Skip to content

Instantly share code, notes, and snippets.

@Li-Hee
Created November 6, 2020 07:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Li-Hee/d7584661e4a27f3f3c501580fdf46ad1 to your computer and use it in GitHub Desktop.
Save Li-Hee/d7584661e4a27f3f3c501580fdf46ad1 to your computer and use it in GitHub Desktop.
dsadas
version: "1"
rules: # Array of rules
- base: master # Required. Target branch
upstream: BlueskyClouds:master # Required. Must be in the same fork network.
mergeMethod: hardreset # Optional, one of [none, merge, squash, rebase, hardreset], Default: none.
mergeUnstable: true # Optional, merge pull request even when the mergeable_state is not clean. Default: false
name: 中国电信签到
on:
workflow_dispatch:
schedule:
- cron: "30 0 * * *"
watch:
types: [started]
jobs:
build:
runs-on: ubuntu-latest
if: github.event.repository.owner.id == github.event.sender.id
steps:
- uses: actions/checkout@v1
- name: Use Node.js 10.x
uses: actions/setup-node@v1
with:
node-version: 10.x
- name: npm install
run: |
npm install
- name: "运行【中国电信签到】"
run: |
node function/10000.js
env:
TELECOM_MOBILE: ${{ secrets.TELECOM_MOBILE }}
SEND_KEY: ${{ secrets.SEND_KEY }}
PUSH_KEY: ${{ secrets.PUSH_KEY }}
BARK_PUSH: ${{ secrets.BARK_PUSH }}
TG_BOT_TOKEN: ${{ secrets.TG_BOT_TOKEN }}
TG_USER_ID: ${{ secrets.TG_USER_ID }}
BARK_SOUND: ${{ secrets.BARK_SOUND }}
name: 93x论坛签到签到
on:
workflow_dispatch:
schedule:
- cron: "15 00 * * *"
watch:
types: [started]
jobs:
build:
runs-on: ubuntu-latest
if: github.event.repository.owner.id == github.event.sender.id
steps:
- uses: actions/checkout@v1
- name: Use Node.js 10.x
uses: actions/setup-node@v1
with:
node-version: 10.x
- name: npm install
run: |
npm install
- name: "运行【93x论坛签到】"
run: |
node function/93x.js
env:
93X_COOKIE: ${{ secrets.93X_COOKIE }}
name: 哔哩哔哩漫画签到
on:
workflow_dispatch:
schedule:
- cron: "5 16 * * *"
watch:
types: [started]
jobs:
build:
runs-on: ubuntu-latest
if: github.event.repository.owner.id == github.event.sender.id
steps:
- name: Checkout
uses: actions/checkout@v2
- name: "Set up Python"
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: "安装依赖包"
run: pip install -r ./requirements.txt
- name: "运行 哔哩哔哩漫画签到"
run: python3 function/bilibili_manga.py
env:
BILI_USER: ${{ secrets.BILI_USER }}
BILI_PASS: ${{ secrets.BILI_PASS }}
push_key: ${{ secrets.PUSH_KEY }}
name: 爱奇艺会员签到
on:
workflow_dispatch:
schedule:
- cron: "5 16 * * *"
watch:
types: [started]
jobs:
build:
runs-on: ubuntu-latest
if: github.event.repository.owner.id == github.event.sender.id
steps:
- uses: actions/checkout@v1
- name: Use Node.js 10.x
uses: actions/setup-node@v1
with:
node-version: 10.x
- name: npm install
run: |
npm install
- name: "运行【爱奇艺会员签到】"
run: |
node function/iqiyi.js
env:
iQIYI_COOKIE: ${{ secrets.iQIYI_COOKIE }}
SEND_KEY: ${{ secrets.SEND_KEY }}
PUSH_KEY: ${{ secrets.PUSH_KEY }}
BARK_PUSH: ${{ secrets.BARK_PUSH }}
TG_BOT_TOKEN: ${{ secrets.TG_BOT_TOKEN }}
TG_USER_ID: ${{ secrets.TG_USER_ID }}
BARK_SOUND: ${{ secrets.BARK_SOUND }}
name: 腾讯视频签到
on:
workflow_dispatch:
schedule:
- cron: "30 15 * * *"
watch:
types: [started]
jobs:
build:
runs-on: ubuntu-latest
if: github.event.repository.owner.id == github.event.sender.id
steps:
- uses: actions/checkout@v1
- name: Use Node.js 10.x
uses: actions/setup-node@v1
with:
node-version: 10.x
- name: npm install
run: |
npm install
- name: "运行【腾讯视频签到】"
run: |
node function/v_video.js
env:
V_REF_URL: ${{ secrets.V_REF_URL }}
V_COOKIE: ${{ secrets.V_COOKIE }}
SEND_KEY: ${{ secrets.SEND_KEY }}
PUSH_KEY: ${{ secrets.PUSH_KEY }}
BARK_PUSH: ${{ secrets.BARK_PUSH }}
TG_BOT_TOKEN: ${{ secrets.TG_BOT_TOKEN }}
TG_USER_ID: ${{ secrets.TG_USER_ID }}
BARK_SOUND: ${{ secrets.BARK_SOUND }}
# OSX
.DS_Store
.git
.idea
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Dependency directories
node_modules/
package-lock.json
result.txt
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/../../../:\My-Actions-master\.idea/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/My-Actions-master.iml" filepath="$PROJECT_DIR$/.idea/My-Actions-master.iml" />
</modules>
</component>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="6cef5e9c-c146-403f-b702-e78d01af0ea4" name="Default Changelist" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="ProjectId" id="1juEjMp7af3EbAEsRKEXte5d2tB" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="aspect.path.notification.shown" value="true" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="settings.editor.selected.configurable" value="org.jetbrains.plugins.github.ui.GithubSettingsConfigurable" />
</component>
<component name="RunManager">
<configuration default="true" type="ArquillianJUnit" factoryName="" nameIsGenerated="true">
<option name="arquillianRunConfiguration">
<value>
<option name="containerStateName" value="" />
</value>
</option>
<option name="TEST_OBJECT" value="class" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="6cef5e9c-c146-403f-b702-e78d01af0ea4" name="Default Changelist" comment="" />
<created>1604645711827</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1604645711827</updated>
<workItem from="1604645713097" duration="522000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="WindowStateProjectService">
<state x="579" y="331" key="Github.CreateGistDialog" timestamp="1604645943598">
<screen x="0" y="0" width="1536" height="824" />
</state>
<state x="579" y="331" key="Github.CreateGistDialog/0.0.1536.824@0.0.1536.824" timestamp="1604645943598" />
<state x="270" y="56" key="SettingsEditor" timestamp="1604646206837">
<screen x="0" y="0" width="1536" height="824" />
</state>
<state x="270" y="56" key="SettingsEditor/0.0.1536.824@0.0.1536.824" timestamp="1604646206837" />
</component>
</project>
function Env(name, opts) {
class Http {
constructor(env) {
this.env = env
}
send(opts, method = 'GET') {
opts = typeof opts === 'string' ? { url: opts } : opts
let sender = this.get
if (method === 'POST') {
sender = this.post
}
return new Promise((resolve, reject) => {
sender.call(this, opts, (err, resp, body) => {
if (err) reject(err)
else resolve(resp)
})
})
}
get(opts) {
return this.send.call(this.env, opts)
}
post(opts) {
return this.send.call(this.env, opts, 'POST')
}
}
return new (class {
constructor(name, opts) {
this.name = name
this.http = new Http(this)
this.data = null
this.dataFile = 'box.dat'
this.logs = []
this.isMute = false
this.isNeedRewrite = false
this.logSeparator = '\n'
this.startTime = new Date().getTime()
Object.assign(this, opts)
this.log('', `🔔${this.name}, 开始!`)
}
isNode() {
return 'undefined' !== typeof module && !!module.exports
}
isQuanX() {
return 'undefined' !== typeof $task
}
isSurge() {
return 'undefined' !== typeof $httpClient && 'undefined' === typeof $loon
}
isLoon() {
return 'undefined' !== typeof $loon
}
toObj(str, defaultValue = null) {
try {
return JSON.parse(str)
} catch {
return defaultValue
}
}
toStr(obj, defaultValue = null) {
try {
return JSON.stringify(obj)
} catch {
return defaultValue
}
}
getjson(key, defaultValue) {
let json = defaultValue
const val = this.getdata(key)
if (val) {
try {
json = JSON.parse(this.getdata(key))
} catch {}
}
return json
}
setjson(val, key) {
try {
return this.setdata(JSON.stringify(val), key)
} catch {
return false
}
}
getScript(url) {
return new Promise((resolve) => {
this.get({ url }, (err, resp, body) => resolve(body))
})
}
runScript(script, runOpts) {
return new Promise((resolve) => {
let httpapi = this.getdata('@chavy_boxjs_userCfgs.httpapi')
httpapi = httpapi ? httpapi.replace(/\n/g, '').trim() : httpapi
let httpapi_timeout = this.getdata('@chavy_boxjs_userCfgs.httpapi_timeout')
httpapi_timeout = httpapi_timeout ? httpapi_timeout * 1 : 20
httpapi_timeout = runOpts && runOpts.timeout ? runOpts.timeout : httpapi_timeout
const [key, addr] = httpapi.split('@')
const opts = {
url: `http://${addr}/v1/scripting/evaluate`,
body: { script_text: script, mock_type: 'cron', timeout: httpapi_timeout },
headers: { 'X-Key': key, 'Accept': '*/*' }
}
this.post(opts, (err, resp, body) => resolve(body))
}).catch((e) => this.logErr(e))
}
loaddata() {
if (this.isNode()) {
this.fs = this.fs ? this.fs : require('fs')
this.path = this.path ? this.path : require('path')
const curDirDataFilePath = this.path.resolve(this.dataFile)
const rootDirDataFilePath = this.path.resolve(process.cwd(), this.dataFile)
const isCurDirDataFile = this.fs.existsSync(curDirDataFilePath)
const isRootDirDataFile = !isCurDirDataFile && this.fs.existsSync(rootDirDataFilePath)
if (isCurDirDataFile || isRootDirDataFile) {
const datPath = isCurDirDataFile ? curDirDataFilePath : rootDirDataFilePath
try {
return JSON.parse(this.fs.readFileSync(datPath))
} catch (e) {
return {}
}
} else return {}
} else return {}
}
writedata() {
if (this.isNode()) {
this.fs = this.fs ? this.fs : require('fs')
this.path = this.path ? this.path : require('path')
const curDirDataFilePath = this.path.resolve(this.dataFile)
const rootDirDataFilePath = this.path.resolve(process.cwd(), this.dataFile)
const isCurDirDataFile = this.fs.existsSync(curDirDataFilePath)
const isRootDirDataFile = !isCurDirDataFile && this.fs.existsSync(rootDirDataFilePath)
const jsondata = JSON.stringify(this.data)
if (isCurDirDataFile) {
this.fs.writeFileSync(curDirDataFilePath, jsondata)
} else if (isRootDirDataFile) {
this.fs.writeFileSync(rootDirDataFilePath, jsondata)
} else {
this.fs.writeFileSync(curDirDataFilePath, jsondata)
}
}
}
lodash_get(source, path, defaultValue = undefined) {
const paths = path.replace(/\[(\d+)\]/g, '.$1').split('.')
let result = source
for (const p of paths) {
result = Object(result)[p]
if (result === undefined) {
return defaultValue
}
}
return result
}
lodash_set(obj, path, value) {
if (Object(obj) !== obj) return obj
if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || []
path
.slice(0, -1)
.reduce((a, c, i) => (Object(a[c]) === a[c] ? a[c] : (a[c] = Math.abs(path[i + 1]) >> 0 === +path[i + 1] ? [] : {})), obj)[
path[path.length - 1]
] = value
return obj
}
getdata(key) {
let val = this.getval(key)
// 如果以 @
if (/^@/.test(key)) {
const [, objkey, paths] = /^@(.*?)\.(.*?)$/.exec(key)
const objval = objkey ? this.getval(objkey) : ''
if (objval) {
try {
const objedval = JSON.parse(objval)
val = objedval ? this.lodash_get(objedval, paths, '') : val
} catch (e) {
val = ''
}
}
}
return val
}
setdata(val, key) {
let issuc = false
if (/^@/.test(key)) {
const [, objkey, paths] = /^@(.*?)\.(.*?)$/.exec(key)
const objdat = this.getval(objkey)
const objval = objkey ? (objdat === 'null' ? null : objdat || '{}') : '{}'
try {
const objedval = JSON.parse(objval)
this.lodash_set(objedval, paths, val)
issuc = this.setval(JSON.stringify(objedval), objkey)
} catch (e) {
const objedval = {}
this.lodash_set(objedval, paths, val)
issuc = this.setval(JSON.stringify(objedval), objkey)
}
} else {
issuc = this.setval(val, key)
}
return issuc
}
getval(key) {
if (this.isSurge() || this.isLoon()) {
return $persistentStore.read(key)
} else if (this.isQuanX()) {
return $prefs.valueForKey(key)
} else if (this.isNode()) {
this.data = this.loaddata()
return this.data[key]
} else {
return (this.data && this.data[key]) || null
}
}
setval(val, key) {
if (this.isSurge() || this.isLoon()) {
return $persistentStore.write(val, key)
} else if (this.isQuanX()) {
return $prefs.setValueForKey(val, key)
} else if (this.isNode()) {
this.data = this.loaddata()
this.data[key] = val
this.writedata()
return true
} else {
return (this.data && this.data[key]) || null
}
}
initGotEnv(opts) {
this.got = this.got ? this.got : require('got')
this.cktough = this.cktough ? this.cktough : require('tough-cookie')
this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar()
if (opts) {
opts.headers = opts.headers ? opts.headers : {}
if (undefined === opts.headers.Cookie && undefined === opts.cookieJar) {
opts.cookieJar = this.ckjar
}
}
}
get(opts, callback = () => {}) {
if (opts.headers) {
delete opts.headers['Content-Type']
delete opts.headers['Content-Length']
}
if (this.isSurge() || this.isLoon()) {
if (this.isSurge() && this.isNeedRewrite) {
opts.headers = opts.headers || {}
Object.assign(opts.headers, { 'X-Surge-Skip-Scripting': false })
}
$httpClient.get(opts, (err, resp, body) => {
if (!err && resp) {
resp.body = body
resp.statusCode = resp.status
}
callback(err, resp, body)
})
} else if (this.isQuanX()) {
if (this.isNeedRewrite) {
opts.opts = opts.opts || {}
Object.assign(opts.opts, { hints: false })
}
$task.fetch(opts).then(
(resp) => {
const { statusCode: status, statusCode, headers, body } = resp
callback(null, { status, statusCode, headers, body }, body)
},
(err) => callback(err)
)
} else if (this.isNode()) {
this.initGotEnv(opts)
this.got(opts)
.on('redirect', (resp, nextOpts) => {
try {
if (resp.headers['set-cookie']) {
const ck = resp.headers['set-cookie'].map(this.cktough.Cookie.parse).toString()
if (ck) {
this.ckjar.setCookieSync(ck, null)
}
nextOpts.cookieJar = this.ckjar
}
} catch (e) {
this.logErr(e)
}
// this.ckjar.setCookieSync(resp.headers['set-cookie'].map(Cookie.parse).toString())
})
.then(
(resp) => {
const { statusCode: status, statusCode, headers, body } = resp
callback(null, { status, statusCode, headers, body }, body)
},
(err) => {
const { message: error, response: resp } = err
callback(error, resp, resp && resp.body)
}
)
}
}
post(opts, callback = () => {}) {
// 如果指定了请求体, 但没指定`Content-Type`, 则自动生成
if (opts.body && opts.headers && !opts.headers['Content-Type']) {
opts.headers['Content-Type'] = 'application/x-www-form-urlencoded'
}
if (opts.headers) delete opts.headers['Content-Length']
if (this.isSurge() || this.isLoon()) {
if (this.isSurge() && this.isNeedRewrite) {
opts.headers = opts.headers || {}
Object.assign(opts.headers, { 'X-Surge-Skip-Scripting': false })
}
$httpClient.post(opts, (err, resp, body) => {
if (!err && resp) {
resp.body = body
resp.statusCode = resp.status
}
callback(err, resp, body)
})
} else if (this.isQuanX()) {
opts.method = 'POST'
if (this.isNeedRewrite) {
opts.opts = opts.opts || {}
Object.assign(opts.opts, { hints: false })
}
$task.fetch(opts).then(
(resp) => {
const { statusCode: status, statusCode, headers, body } = resp
callback(null, { status, statusCode, headers, body }, body)
},
(err) => callback(err)
)
} else if (this.isNode()) {
this.initGotEnv(opts)
const { url, ..._opts } = opts
this.got.post(url, _opts).then(
(resp) => {
const { statusCode: status, statusCode, headers, body } = resp
callback(null, { status, statusCode, headers, body }, body)
},
(err) => {
const { message: error, response: resp } = err
callback(error, resp, resp && resp.body)
}
)
}
}
/**
*
* 示例:$.time('yyyy-MM-dd qq HH:mm:ss.S')
* :$.time('yyyyMMddHHmmssS')
* y:年 M:月 d:日 q:季 H:时 m:分 s:秒 S:毫秒
* 其中y可选0-4位占位符、S可选0-1位占位符,其余可选0-2位占位符
* @param {*} fmt 格式化参数
*
*/
time(fmt) {
let o = {
'M+': new Date().getMonth() + 1,
'd+': new Date().getDate(),
'H+': new Date().getHours(),
'm+': new Date().getMinutes(),
's+': new Date().getSeconds(),
'q+': Math.floor((new Date().getMonth() + 3) / 3),
'S': new Date().getMilliseconds()
}
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (new Date().getFullYear() + '').substr(4 - RegExp.$1.length))
for (let k in o)
if (new RegExp('(' + k + ')').test(fmt))
fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length))
return fmt
}
/**
* 系统通知
*
* > 通知参数: 同时支持 QuanX 和 Loon 两种格式, EnvJs根据运行环境自动转换, Surge 环境不支持多媒体通知
*
* 示例:
* $.msg(title, subt, desc, 'twitter://')
* $.msg(title, subt, desc, { 'open-url': 'twitter://', 'media-url': 'https://github.githubassets.com/images/modules/open_graph/github-mark.png' })
* $.msg(title, subt, desc, { 'open-url': 'https://bing.com', 'media-url': 'https://github.githubassets.com/images/modules/open_graph/github-mark.png' })
*
* @param {*} title 标题
* @param {*} subt 副标题
* @param {*} desc 通知详情
* @param {*} opts 通知参数
*
*/
msg(title = name, subt = '', desc = '', opts) {
const toEnvOpts = (rawopts) => {
if (!rawopts) return rawopts
if (typeof rawopts === 'string') {
if (this.isLoon()) return rawopts
else if (this.isQuanX()) return { 'open-url': rawopts }
else if (this.isSurge()) return { url: rawopts }
else return undefined
} else if (typeof rawopts === 'object') {
if (this.isLoon()) {
let openUrl = rawopts.openUrl || rawopts.url || rawopts['open-url']
let mediaUrl = rawopts.mediaUrl || rawopts['media-url']
return { openUrl, mediaUrl }
} else if (this.isQuanX()) {
let openUrl = rawopts['open-url'] || rawopts.url || rawopts.openUrl
let mediaUrl = rawopts['media-url'] || rawopts.mediaUrl
return { 'open-url': openUrl, 'media-url': mediaUrl }
} else if (this.isSurge()) {
let openUrl = rawopts.url || rawopts.openUrl || rawopts['open-url']
return { url: openUrl }
}
} else {
return undefined
}
}
if (!this.isMute) {
if (this.isSurge() || this.isLoon()) {
$notification.post(title, subt, desc, toEnvOpts(opts))
} else if (this.isQuanX()) {
$notify(title, subt, desc, toEnvOpts(opts))
}
}
if (!this.isMuteLog) {
let logs = ['', '==============📣系统通知📣==============']
logs.push(title)
subt ? logs.push(subt) : ''
desc ? logs.push(desc) : ''
console.log(logs.join('\n'))
this.logs = this.logs.concat(logs)
}
}
log(...logs) {
if (logs.length > 0) {
this.logs = [...this.logs, ...logs]
}
console.log(logs.join(this.logSeparator))
}
logErr(err, msg) {
const isPrintSack = !this.isSurge() && !this.isQuanX() && !this.isLoon()
if (!isPrintSack) {
this.log('', `❗️${this.name}, 错误!`, err)
} else {
this.log('', `❗️${this.name}, 错误!`, err.stack)
}
}
wait(time) {
return new Promise((resolve) => setTimeout(resolve, time))
}
done(val = {}) {
const endTime = new Date().getTime()
const costTime = (endTime - this.startTime) / 1000
this.log('', `🔔${this.name}, 结束! 🕛 ${costTime} 秒`)
this.log()
if (this.isSurge() || this.isQuanX() || this.isLoon()) {
$done(val)
}
}
})(name, opts)
}
function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),a={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(a,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon()?(this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)})):this.isQuanX()?(this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t))):this.isNode()&&(this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)}))}post(t,e=(()=>{})){if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.post(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method="POST",this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){this.initGotEnv(t);const{url:s,...i}=t;this.got.post(s,i).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)})}}time(t){let e={"M+":(new Date).getMonth()+1,"d+":(new Date).getDate(),"H+":(new Date).getHours(),"m+":(new Date).getMinutes(),"s+":(new Date).getSeconds(),"q+":Math.floor(((new Date).getMonth()+3)/3),S:(new Date).getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,((new Date).getFullYear()+"").substr(4-RegExp.$1.length)));for(let s in e)new RegExp("("+s+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?e[s]:("00"+e[s]).substr((""+e[s]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl;return{"open-url":e,"media-url":s}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)}
// version v0.0.1
// create by BlueSkyClouds
// detail url: https://github.com/BlueskyClouds/iQIYI-DailyBonus
const exec = require('child_process').execSync
const fs = require('fs')
const download = require('download')
const $ = new Env('中国电信签到');
const notify = $.isNode() ? require('../sendNotify') : '';
// 公共变量
const KEY = process.env.TELECOM_MOBILE
const SEND_KEY = process.env.SEND_KEY
async function downFile () {
const url = 'https://raw.githubusercontent.com/chavyleung/scripts/master/10000/10000.js'
await download(url, './')
}
async function changeFiele () {
let content = await fs.readFileSync('./10000.js', 'utf8')
//替换各种无用信息.
content = content.replace("\"\\n\"", "\"\"")
content = content.replace("中国电信", ``)
content = content.replace(/==============\\ud83d\\udce3\\u7cfb\\u7edf\\u901a\\u77e5\\ud83d\\udce3==============/, ``)
content = content.replace("\\ud83d\\udd14${this.name}, \\u5f00\\u59cb!", ``)
content = content.replace("\\ud83d\\udd14${this.name}, \\u7ed3\\u675f! \\ud83d\\udd5b ${e} \\u79d2", ``)
content = content.replace("const phonedat = $.getdata($.KEY_mobile)", `const phonedat = '${KEY}'`)
await fs.writeFileSync( './10000.js', content, 'utf8')
}
async function deleteFile(path) {
// 查看文件result.txt是 否存在,如果存在,先删除
const fileExists = await fs.existsSync(path);
// console.log('fileExists', fileExists);
if (fileExists) {
const unlinkRes = await fs.unlinkSync(path);
// console.log('unlinkRes', unlinkRes)
}
}
async function start() {
if (!KEY) {
console.log('请填写电信号码后再继续')
return
}
// 下载最新代码
await downFile();
console.log('下载代码完毕')
// 替换变量
await changeFiele();
console.log('替换变量完毕')
// 执行
await exec("node 10000.js >> result.txt");
console.log('执行完毕')
const path = "./result.txt";
let content = "";
if (fs.existsSync(path)) {
content = fs.readFileSync(path, "utf8");
}
if(SEND_KEY) {
if (content.includes("签到成功") | content.includes("已签")) {
console.log("电信签到-" + content)
}else{
await notify.sendNotify("中国电信签到-" + new Date().toLocaleDateString(), content);
console.log("中国电信签到-" + content)
}
}else{
await notify.sendNotify("中国电信签到-" + new Date().toLocaleDateString(), content);
console.log("中国电信签到-" + content)
}
//运行完成后,删除下载的文件
console.log('运行完成后,删除下载的文件\n')
await deleteFile(path);
}
start()
// prettier-ignore
function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),a={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(a,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon()?(this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)})):this.isQuanX()?(this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t))):this.isNode()&&(this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)}))}post(t,e=(()=>{})){if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.post(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method="POST",this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){this.initGotEnv(t);const{url:s,...i}=t;this.got.post(s,i).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)})}}time(t){let e={"M+":(new Date).getMonth()+1,"d+":(new Date).getDate(),"H+":(new Date).getHours(),"m+":(new Date).getMinutes(),"s+":(new Date).getSeconds(),"q+":Math.floor(((new Date).getMonth()+3)/3),S:(new Date).getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,((new Date).getFullYear()+"").substr(4-RegExp.$1.length)));for(let s in e)new RegExp("("+s+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?e[s]:("00"+e[s]).substr((""+e[s]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl;return{"open-url":e,"media-url":s}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)}
var $ = new Env('93x论坛签到');
const CookieWA = process.env.93X_COOKIE
var user_auth = '';
if(CookieWA){
get_user_auth()
bbs_apply_task_1()
bbs_apply_task_2()
}else{
console.log('未填写cookie')
}
/**
* 获取93x user_auth
* 返回user_auth内容
*/
function get_user_auth() {
$.get({
url: 'https://bbs.93x.net/plugin.php?id=xnet_steam_openid%3ASoftLogin\n',
headers: {
Cookie: CookieWA,
}
}, function(error, response, data) {
if (error) {
$.log(error);
$.msg("93x论坛获取user_auth", "访问失败 ‼️‼️", error)
} else {
if (data.match(/(user_auth)/)) {
cc = data.match(/user_auth":"(.*?)"}/)
//$.msg(cc[1])
user_auth = cc[1];
//console.log(data)
bbs_sign()
} else {
$.msg("93x论坛获取user_auth", "", "获取user_auth请求失败 ‼️‼️")
}
}
//$.done();
})
}
function bbs_sign() {
$.get({
url: 'https://bbs.93x.net/plugin.php?id=are_luo_qiandao%3Agetawardsoftapi&auth=' + user_auth,
headers: {
Cookie: CookieWA,
}
}, function(error, response, data) {
if (error) {
$.log(error);
$.msg("93x论坛签到", "访问失败 ‼️‼️", error)
} else {
if (data.match(/(您已获得)/)) {
$.msg(data)
} else {
$.msg("93x论坛签到失败", "", data + " ‼️‼️")
}
}
$.done();
})
}
function bbs_apply_task_1() {
$.get({
url: 'https://bbs.93x.net/home.php?mod=task&do=apply&id=15\n',
headers: {
Cookie: CookieWA,
}
}, function(error, response, data) {
if (error) {
$.log(error);
$.msg("93x论坛签到", "访问失败 ‼️‼️", error)
} else {
if (data.match(/(申请成功)/)) {
//$.msg(data)
bbs_draw_task_1()
} else {
//$.msg("93x论坛签到", "", data + " ‼️‼️")
}
}
//$.done();
})
}
function bbs_draw_task_1() {
$.get({
url: 'https://bbs.93x.net/home.php?mod=task&do=draw&id=15\n',
headers: {
Cookie: CookieWA,
}
}, function(error, response, data) {
if (error) {
$.log(error);
$.msg("93x论坛签到", "访问失败 ‼️‼️", error)
} else {
if (data.match(/(成功)/)) {
//$.msg(data)
} else {
//$.msg("93x论坛签到", "", data + " ‼️‼️")
}
}
//$.done();
})
}
function bbs_apply_task_2() {
$.get({
url: 'https://bbs.93x.net/home.php?mod=task&do=apply&id=18\n',
headers: {
Cookie: CookieWA,
}
}, function(error, response, data) {
if (error) {
$.log(error);
$.msg("93x论坛签到", "访问失败 ‼️‼️", error)
} else {
if (data.match(/(申请成功)/)) {
//$.msg(data)
bbs_draw_task_2()
} else {
//$.msg("93x论坛签到", "", data + " ‼️‼️")
}
}
//$.done();
})
}
function bbs_draw_task_2() {
$.get({
url: 'https://bbs.93x.net/home.php?mod=task&do=draw&id=18\n',
headers: {
Cookie: CookieWA,
}
}, function(error, response, data) {
if (error) {
$.log(error);
$.msg("93x论坛签到", "访问失败 ‼️‼️", error)
} else {
if (data.match(/(成功)/)) {
//$.msg(data)
} else {
//$.msg("93x论坛签到", "", data + " ‼️‼️")
}
}
//$.done();
})
}
function Env(name, opts) {
class Http {
constructor(env) {
this.env = env
}
send(opts, method = 'GET') {
opts = typeof opts === 'string' ? { url: opts } : opts
let sender = this.get
if (method === 'POST') {
sender = this.post
}
return new Promise((resolve, reject) => {
sender.call(this, opts, (err, resp, body) => {
if (err) reject(err)
else resolve(resp)
})
})
}
get(opts) {
return this.send.call(this.env, opts)
}
post(opts) {
return this.send.call(this.env, opts, 'POST')
}
}
return new (class {
constructor(name, opts) {
this.name = name
this.http = new Http(this)
this.data = null
this.dataFile = 'box.dat'
this.logs = []
this.isMute = false
this.isNeedRewrite = false
this.logSeparator = '\n'
this.startTime = new Date().getTime()
Object.assign(this, opts)
this.log('', `🔔${this.name}, 开始!`)
}
isNode() {
return 'undefined' !== typeof module && !!module.exports
}
isQuanX() {
return 'undefined' !== typeof $task
}
isSurge() {
return 'undefined' !== typeof $httpClient && 'undefined' === typeof $loon
}
isLoon() {
return 'undefined' !== typeof $loon
}
toObj(str, defaultValue = null) {
try {
return JSON.parse(str)
} catch {
return defaultValue
}
}
toStr(obj, defaultValue = null) {
try {
return JSON.stringify(obj)
} catch {
return defaultValue
}
}
getjson(key, defaultValue) {
let json = defaultValue
const val = this.getdata(key)
if (val) {
try {
json = JSON.parse(this.getdata(key))
} catch {}
}
return json
}
setjson(val, key) {
try {
return this.setdata(JSON.stringify(val), key)
} catch {
return false
}
}
getScript(url) {
return new Promise((resolve) => {
this.get({ url }, (err, resp, body) => resolve(body))
})
}
runScript(script, runOpts) {
return new Promise((resolve) => {
let httpapi = this.getdata('@chavy_boxjs_userCfgs.httpapi')
httpapi = httpapi ? httpapi.replace(/\n/g, '').trim() : httpapi
let httpapi_timeout = this.getdata('@chavy_boxjs_userCfgs.httpapi_timeout')
httpapi_timeout = httpapi_timeout ? httpapi_timeout * 1 : 20
httpapi_timeout = runOpts && runOpts.timeout ? runOpts.timeout : httpapi_timeout
const [key, addr] = httpapi.split('@')
const opts = {
url: `http://${addr}/v1/scripting/evaluate`,
body: { script_text: script, mock_type: 'cron', timeout: httpapi_timeout },
headers: { 'X-Key': key, 'Accept': '*/*' }
}
this.post(opts, (err, resp, body) => resolve(body))
}).catch((e) => this.logErr(e))
}
loaddata() {
if (this.isNode()) {
this.fs = this.fs ? this.fs : require('fs')
this.path = this.path ? this.path : require('path')
const curDirDataFilePath = this.path.resolve(this.dataFile)
const rootDirDataFilePath = this.path.resolve(process.cwd(), this.dataFile)
const isCurDirDataFile = this.fs.existsSync(curDirDataFilePath)
const isRootDirDataFile = !isCurDirDataFile && this.fs.existsSync(rootDirDataFilePath)
if (isCurDirDataFile || isRootDirDataFile) {
const datPath = isCurDirDataFile ? curDirDataFilePath : rootDirDataFilePath
try {
return JSON.parse(this.fs.readFileSync(datPath))
} catch (e) {
return {}
}
} else return {}
} else return {}
}
writedata() {
if (this.isNode()) {
this.fs = this.fs ? this.fs : require('fs')
this.path = this.path ? this.path : require('path')
const curDirDataFilePath = this.path.resolve(this.dataFile)
const rootDirDataFilePath = this.path.resolve(process.cwd(), this.dataFile)
const isCurDirDataFile = this.fs.existsSync(curDirDataFilePath)
const isRootDirDataFile = !isCurDirDataFile && this.fs.existsSync(rootDirDataFilePath)
const jsondata = JSON.stringify(this.data)
if (isCurDirDataFile) {
this.fs.writeFileSync(curDirDataFilePath, jsondata)
} else if (isRootDirDataFile) {
this.fs.writeFileSync(rootDirDataFilePath, jsondata)
} else {
this.fs.writeFileSync(curDirDataFilePath, jsondata)
}
}
}
lodash_get(source, path, defaultValue = undefined) {
const paths = path.replace(/\[(\d+)\]/g, '.$1').split('.')
let result = source
for (const p of paths) {
result = Object(result)[p]
if (result === undefined) {
return defaultValue
}
}
return result
}
lodash_set(obj, path, value) {
if (Object(obj) !== obj) return obj
if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || []
path
.slice(0, -1)
.reduce((a, c, i) => (Object(a[c]) === a[c] ? a[c] : (a[c] = Math.abs(path[i + 1]) >> 0 === +path[i + 1] ? [] : {})), obj)[
path[path.length - 1]
] = value
return obj
}
getdata(key) {
let val = this.getval(key)
// 如果以 @
if (/^@/.test(key)) {
const [, objkey, paths] = /^@(.*?)\.(.*?)$/.exec(key)
const objval = objkey ? this.getval(objkey) : ''
if (objval) {
try {
const objedval = JSON.parse(objval)
val = objedval ? this.lodash_get(objedval, paths, '') : val
} catch (e) {
val = ''
}
}
}
return val
}
setdata(val, key) {
let issuc = false
if (/^@/.test(key)) {
const [, objkey, paths] = /^@(.*?)\.(.*?)$/.exec(key)
const objdat = this.getval(objkey)
const objval = objkey ? (objdat === 'null' ? null : objdat || '{}') : '{}'
try {
const objedval = JSON.parse(objval)
this.lodash_set(objedval, paths, val)
issuc = this.setval(JSON.stringify(objedval), objkey)
} catch (e) {
const objedval = {}
this.lodash_set(objedval, paths, val)
issuc = this.setval(JSON.stringify(objedval), objkey)
}
} else {
issuc = this.setval(val, key)
}
return issuc
}
getval(key) {
if (this.isSurge() || this.isLoon()) {
return $persistentStore.read(key)
} else if (this.isQuanX()) {
return $prefs.valueForKey(key)
} else if (this.isNode()) {
this.data = this.loaddata()
return this.data[key]
} else {
return (this.data && this.data[key]) || null
}
}
setval(val, key) {
if (this.isSurge() || this.isLoon()) {
return $persistentStore.write(val, key)
} else if (this.isQuanX()) {
return $prefs.setValueForKey(val, key)
} else if (this.isNode()) {
this.data = this.loaddata()
this.data[key] = val
this.writedata()
return true
} else {
return (this.data && this.data[key]) || null
}
}
initGotEnv(opts) {
this.got = this.got ? this.got : require('got')
this.cktough = this.cktough ? this.cktough : require('tough-cookie')
this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar()
if (opts) {
opts.headers = opts.headers ? opts.headers : {}
if (undefined === opts.headers.Cookie && undefined === opts.cookieJar) {
opts.cookieJar = this.ckjar
}
}
}
get(opts, callback = () => {}) {
if (opts.headers) {
delete opts.headers['Content-Type']
delete opts.headers['Content-Length']
}
if (this.isSurge() || this.isLoon()) {
if (this.isSurge() && this.isNeedRewrite) {
opts.headers = opts.headers || {}
Object.assign(opts.headers, { 'X-Surge-Skip-Scripting': false })
}
$httpClient.get(opts, (err, resp, body) => {
if (!err && resp) {
resp.body = body
resp.statusCode = resp.status
}
callback(err, resp, body)
})
} else if (this.isQuanX()) {
if (this.isNeedRewrite) {
opts.opts = opts.opts || {}
Object.assign(opts.opts, { hints: false })
}
$task.fetch(opts).then(
(resp) => {
const { statusCode: status, statusCode, headers, body } = resp
callback(null, { status, statusCode, headers, body }, body)
},
(err) => callback(err)
)
} else if (this.isNode()) {
this.initGotEnv(opts)
this.got(opts)
.on('redirect', (resp, nextOpts) => {
try {
if (resp.headers['set-cookie']) {
const ck = resp.headers['set-cookie'].map(this.cktough.Cookie.parse).toString()
this.ckjar.setCookieSync(ck, null)
nextOpts.cookieJar = this.ckjar
}
} catch (e) {
this.logErr(e)
}
// this.ckjar.setCookieSync(resp.headers['set-cookie'].map(Cookie.parse).toString())
})
.then(
(resp) => {
const { statusCode: status, statusCode, headers, body } = resp
callback(null, { status, statusCode, headers, body }, body)
},
(err) => {
const { message: error, response: resp } = err
callback(error, resp, resp && resp.body)
}
)
}
}
post(opts, callback = () => {}) {
// 如果指定了请求体, 但没指定`Content-Type`, 则自动生成
if (opts.body && opts.headers && !opts.headers['Content-Type']) {
opts.headers['Content-Type'] = 'application/x-www-form-urlencoded'
}
if (opts.headers) delete opts.headers['Content-Length']
if (this.isSurge() || this.isLoon()) {
if (this.isSurge() && this.isNeedRewrite) {
opts.headers = opts.headers || {}
Object.assign(opts.headers, { 'X-Surge-Skip-Scripting': false })
}
$httpClient.post(opts, (err, resp, body) => {
if (!err && resp) {
resp.body = body
resp.statusCode = resp.status
}
callback(err, resp, body)
})
} else if (this.isQuanX()) {
opts.method = 'POST'
if (this.isNeedRewrite) {
opts.opts = opts.opts || {}
Object.assign(opts.opts, { hints: false })
}
$task.fetch(opts).then(
(resp) => {
const { statusCode: status, statusCode, headers, body } = resp
callback(null, { status, statusCode, headers, body }, body)
},
(err) => callback(err)
)
} else if (this.isNode()) {
this.initGotEnv(opts)
const { url, ..._opts } = opts
this.got.post(url, _opts).then(
(resp) => {
const { statusCode: status, statusCode, headers, body } = resp
callback(null, { status, statusCode, headers, body }, body)
},
(err) => {
const { message: error, response: resp } = err
callback(error, resp, resp && resp.body)
}
)
}
}
/**
*
* 示例:$.time('yyyy-MM-dd qq HH:mm:ss.S')
* :$.time('yyyyMMddHHmmssS')
* y:年 M:月 d:日 q:季 H:时 m:分 s:秒 S:毫秒
* 其中y可选0-4位占位符、S可选0-1位占位符,其余可选0-2位占位符
* @param {*} fmt 格式化参数
*
*/
time(fmt) {
let o = {
'M+': new Date().getMonth() + 1,
'd+': new Date().getDate(),
'H+': new Date().getHours(),
'm+': new Date().getMinutes(),
's+': new Date().getSeconds(),
'q+': Math.floor((new Date().getMonth() + 3) / 3),
'S': new Date().getMilliseconds()
}
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (new Date().getFullYear() + '').substr(4 - RegExp.$1.length))
for (let k in o)
if (new RegExp('(' + k + ')').test(fmt))
fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length))
return fmt
}
/**
* 系统通知
*
* > 通知参数: 同时支持 QuanX 和 Loon 两种格式, EnvJs根据运行环境自动转换, Surge 环境不支持多媒体通知
*
* 示例:
* $.msg(title, subt, desc, 'twitter://')
* $.msg(title, subt, desc, { 'open-url': 'twitter://', 'media-url': 'https://github.githubassets.com/images/modules/open_graph/github-mark.png' })
* $.msg(title, subt, desc, { 'open-url': 'https://bing.com', 'media-url': 'https://github.githubassets.com/images/modules/open_graph/github-mark.png' })
*
* @param {*} title 标题
* @param {*} subt 副标题
* @param {*} desc 通知详情
* @param {*} opts 通知参数
*
*/
msg(title = name, subt = '', desc = '', opts) {
const toEnvOpts = (rawopts) => {
if (!rawopts) return rawopts
if (typeof rawopts === 'string') {
if (this.isLoon()) return rawopts
else if (this.isQuanX()) return { 'open-url': rawopts }
else if (this.isSurge()) return { url: rawopts }
else return undefined
} else if (typeof rawopts === 'object') {
if (this.isLoon()) {
let openUrl = rawopts.openUrl || rawopts.url || rawopts['open-url']
let mediaUrl = rawopts.mediaUrl || rawopts['media-url']
return { openUrl, mediaUrl }
} else if (this.isQuanX()) {
let openUrl = rawopts['open-url'] || rawopts.url || rawopts.openUrl
let mediaUrl = rawopts['media-url'] || rawopts.mediaUrl
return { 'open-url': openUrl, 'media-url': mediaUrl }
} else if (this.isSurge()) {
let openUrl = rawopts.url || rawopts.openUrl || rawopts['open-url']
return { url: openUrl }
}
} else {
return undefined
}
}
if (!this.isMute) {
if (this.isSurge() || this.isLoon()) {
$notification.post(title, subt, desc, toEnvOpts(opts))
} else if (this.isQuanX()) {
$notify(title, subt, desc, toEnvOpts(opts))
}
}
let logs = ['', '==============📣系统通知📣==============']
logs.push(title)
subt ? logs.push(subt) : ''
desc ? logs.push(desc) : ''
console.log(logs.join('\n'))
this.logs = this.logs.concat(logs)
}
log(...logs) {
if (logs.length > 0) {
this.logs = [...this.logs, ...logs]
}
console.log(logs.join(this.logSeparator))
}
logErr(err, msg) {
const isPrintSack = !this.isSurge() && !this.isQuanX() && !this.isLoon()
if (!isPrintSack) {
this.log('', `❗️${this.name}, 错误!`, err)
} else {
this.log('', `❗️${this.name}, 错误!`, err.stack)
}
}
wait(time) {
return new Promise((resolve) => setTimeout(resolve, time))
}
done(val = {}) {
const endTime = new Date().getTime()
const costTime = (endTime - this.startTime) / 1000
this.log('', `🔔${this.name}, 结束! 🕛 ${costTime} 秒`)
this.log()
if (this.isSurge() || this.isQuanX() || this.isLoon()) {
$done(val)
}
}
})(name, opts)
}
#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-
"""Bilibili Toolkit 哔哩哔哩工具箱
https://github.com/Hsury/Bilibili-Toolkit"""
banner = r"""
\\ //
\\ //
##################### ________ ___ ___ ___ ________ ___ ___ ___
## ## |\ __ \ |\ \ |\ \ |\ \ |\ __ \ |\ \ |\ \ |\ \
## // \\ ## \ \ \|\ /_\ \ \\ \ \ \ \ \\ \ \|\ /_\ \ \\ \ \ \ \ \
## // \\ ## \ \ __ \\ \ \\ \ \ \ \ \\ \ __ \\ \ \\ \ \ \ \ \
## ## \ \ \|\ \\ \ \\ \ \____ \ \ \\ \ \|\ \\ \ \\ \ \____ \ \ \
## www ## \ \_______\\ \__\\ \_______\\ \__\\ \_______\\ \__\\ \_______\\ \__\
## ## \|_______| \|__| \|_______| \|__| \|_______| \|__| \|_______| \|__|
#####################
\/ \/ 哔哩哔哩 (゜-゜)つロ 干杯~
"""
import base64
import chardet
import functools
import hashlib
import json
import os
import platform
import random
import requests
import rsa
import shutil
import subprocess
import sys
import threading
import time
from multiprocessing import freeze_support, Manager, Pool, Process
from urllib import parse
__author__ = "Hsury"
__email__ = "i@hsury.com"
__license__ = "SATA"
__version__ = "2020.7.20"
class Bilibili:
app_key = "bca7e84c2d947ac6"
patterns = {
'video': {
'id': 1,
'prefix': "https://www.bilibili.com/video/av",
},
'activity': {
'id': 4,
'prefix': "https://www.bilibili.com/blackboard/",
},
'gallery': {
'id': 11,
'prefix': "https://h.bilibili.com/",
},
'article': {
'id': 12,
'prefix': "https://www.bilibili.com/read/cv",
},
}
def __init__(self, https=True, queue=None):
self._session = requests.Session()
self._session.headers.update({'User-Agent': "Mozilla/5.0 BiliDroid/6.4.0 (bbcallen@gmail.com) os/android model/M1903F11I mobi_app/android build/6040500 channel/bili innerVer/6040500 osVer/9.0.0 network/2"})
self.__queue = queue
self.get_cookies = lambda: self._session.cookies.get_dict(domain=".bilibili.com")
self.get_csrf = lambda: self.get_cookies().get("bili_jct", "")
self.get_sid = lambda: self.get_cookies().get("sid", "")
self.get_uid = lambda: self.get_cookies().get("DedeUserID", "")
self.access_token = ""
self.refresh_token = ""
self.username = ""
self.password = ""
self.info = {
'ban': False,
'coins': 0,
'experience': {
'current': 0,
'next': 0,
},
'face': "",
'level': 0,
'nickname': "",
}
self.protocol = "https" if https else "http"
self.proxy = None
self.proxy_pool = set()
def _log(self, message):
log = f"[{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))}][{self.username if self.username else '#' + self.get_uid() if self.get_uid() else ''}] {message}"
print(log)
self.__push_to_queue("log", log)
def _requests(self, method, url, decode_level=2, enable_proxy=True, retry=10, timeout=15, **kwargs):
if method in ["get", "post"]:
for _ in range(retry + 1):
try:
response = getattr(self._session, method)(url, timeout=timeout, proxies=self.proxy if enable_proxy else None, **kwargs)
return response.json() if decode_level == 2 else response.content if decode_level == 1 else response
except:
if enable_proxy:
self.set_proxy()
return None
def _solve_captcha(self, image):
url = "https://bili.dev:2233/captcha"
payload = {'image': base64.b64encode(image).decode("utf-8")}
response = self._requests("post", url, json=payload)
return response['message'] if response and response.get("code") == 0 else None
def __bvid_handle(args_index=None, kwargs_key="aid"):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
self = args[0]
if args_index is not None and args_index < len(args):
result = Bilibili.bvid_to_aid(args[args_index])
if result:
args = list(args)
self._log(f"{args[args_index]}被自动转换为av{result}")
args[args_index] = result
if kwargs_key is not None and kwargs_key in kwargs:
result = Bilibili.bvid_to_aid(kwargs[kwargs_key])
if result:
self._log(f"{kwargs[kwargs_key]}被自动转换为av{result}")
kwargs[kwargs_key] = result
return func(*args, **kwargs)
return wrapper
return decorator
def __push_to_queue(self, manufacturer, data):
if self.__queue:
self.__queue.put({
'uid': self.get_uid(),
'time': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())),
'manufacturer': manufacturer,
'data': data,
})
@staticmethod
def bvid_to_aid(bvid="BV17x411w7KC"):
# Snippet source: https://www.zhihu.com/question/381784377/answer/1099438784
table = "fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF"
tr = {}
for i in range(58):
tr[table[i]] = i
s = [11, 10, 3, 8, 4, 6]
xor = 177451812
add = 8728348608
r = 0
try:
for i in range(6):
r += tr[bvid[s[i]]] * 58 ** i
return (r - add) ^ xor
except:
return None
@staticmethod
def calc_sign(param):
salt = "60698ba2f68e01ce44738920a0ffe768"
sign_hash = hashlib.md5()
sign_hash.update(f"{param}{salt}".encode())
return sign_hash.hexdigest()
def set_proxy(self, add=None):
if isinstance(add, str):
self.proxy_pool.add(add)
elif isinstance(add, list):
self.proxy_pool.update(add)
if self.proxy_pool:
proxy = random.sample(self.proxy_pool, 1)[0]
self.proxy = {self.protocol: f"{self.protocol}://{proxy}"}
# self._log(f"使用{self.protocol.upper()}代理: {proxy}")
else:
self.proxy = None
return self.proxy
# 登录
def login(self, **kwargs):
def by_cookie():
url = f"{self.protocol}://api.bilibili.com/x/space/myinfo"
headers = {'Host': "api.bilibili.com"}
response = self._requests("get", url, headers=headers)
if response and response.get("code") != -101:
self._log("Cookie仍有效")
return True
else:
self._log("Cookie已失效")
return False
def by_token(force_refresh=False):
if not force_refresh:
param = f"access_key={self.access_token}&appkey={Bilibili.app_key}&ts={int(time.time())}"
url = f"{self.protocol}://passport.bilibili.com/api/v2/oauth2/info?{param}&sign={self.calc_sign(param)}"
response = self._requests("get", url)
if response and response.get("code") == 0:
self._session.cookies.set('DedeUserID', str(response['data']['mid']), domain=".bilibili.com")
self._log(f"Token仍有效, 有效期至{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time() + int(response['data']['expires_in'])))}")
param = f"access_key={self.access_token}&appkey={Bilibili.app_key}&gourl={self.protocol}%3A%2F%2Faccount.bilibili.com%2Faccount%2Fhome&ts={int(time.time())}"
url = f"{self.protocol}://passport.bilibili.com/api/login/sso?{param}&sign={self.calc_sign(param)}"
self._requests("get", url, decode_level=0)
if all(key in self.get_cookies() for key in ["bili_jct", "DedeUserID", "DedeUserID__ckMd5", "sid", "SESSDATA"]):
self._log("Cookie获取成功")
return True
else:
self._log("Cookie获取失败")
url = f"{self.protocol}://passport.bilibili.com/api/v2/oauth2/refresh_token"
param = f"access_key={self.access_token}&appkey={Bilibili.app_key}&refresh_token={self.refresh_token}&ts={int(time.time())}"
payload = f"{param}&sign={self.calc_sign(param)}"
headers = {'Content-type': "application/x-www-form-urlencoded"}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
for cookie in response['data']['cookie_info']['cookies']:
self._session.cookies.set(cookie['name'], cookie['value'], domain=".bilibili.com")
self.access_token = response['data']['token_info']['access_token']
self.refresh_token = response['data']['token_info']['refresh_token']
self._log(f"Token刷新成功, 有效期至{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time() + int(response['data']['token_info']['expires_in'])))}")
return True
else:
self.access_token = ""
self.refresh_token = ""
self._log("Token刷新失败")
return False
def by_password():
def get_key():
url = f"{self.protocol}://passport.bilibili.com/api/oauth2/getKey"
payload = {
'appkey': Bilibili.app_key,
'sign': self.calc_sign(f"appkey={Bilibili.app_key}"),
}
while True:
response = self._requests("post", url, data=payload)
if response and response.get("code") == 0:
return {
'key_hash': response['data']['hash'],
'pub_key': rsa.PublicKey.load_pkcs1_openssl_pem(response['data']['key'].encode()),
}
else:
time.sleep(1)
while True:
key = get_key()
key_hash, pub_key = key['key_hash'], key['pub_key']
url = f"{self.protocol}://passport.bilibili.com/api/v2/oauth2/login"
param = f"appkey={Bilibili.app_key}&password={parse.quote_plus(base64.b64encode(rsa.encrypt(f'{key_hash}{self.password}'.encode(), pub_key)))}&username={parse.quote_plus(self.username)}"
payload = f"{param}&sign={self.calc_sign(param)}"
headers = {'Content-type': "application/x-www-form-urlencoded"}
response = self._requests("post", url, data=payload, headers=headers)
while True:
if response and response.get("code") is not None:
if response['code'] == -105:
url = f"{self.protocol}://passport.bilibili.com/captcha"
headers = {'Host': "passport.bilibili.com"}
response = self._requests("get", url, headers=headers, decode_level=1)
captcha = self._solve_captcha(response)
if captcha:
self._log(f"登录验证码识别结果: {captcha}")
key = get_key()
key_hash, pub_key = key['key_hash'], key['pub_key']
url = f"{self.protocol}://passport.bilibili.com/api/v2/oauth2/login"
param = f"appkey={Bilibili.app_key}&captcha={captcha}&password={parse.quote_plus(base64.b64encode(rsa.encrypt(f'{key_hash}{self.password}'.encode(), pub_key)))}&username={parse.quote_plus(self.username)}"
payload = f"{param}&sign={self.calc_sign(param)}"
headers = {'Content-type': "application/x-www-form-urlencoded"}
response = self._requests("post", url, data=payload, headers=headers)
else:
self._log(f"登录验证码识别服务暂时不可用, {'尝试更换代理' if self.proxy else '10秒后重试'}")
if not self.set_proxy():
time.sleep(10)
break
elif response['code'] == -449:
self._log("服务繁忙, 尝试使用V3接口登录")
url = f"{self.protocol}://passport.bilibili.com/api/v3/oauth2/login"
param = f"access_key=&actionKey=appkey&appkey={Bilibili.app_key}&build=6040500&captcha=&challenge=&channel=bili&cookies=&device=phone&mobi_app=android&password={parse.quote_plus(base64.b64encode(rsa.encrypt(f'{key_hash}{self.password}'.encode(), pub_key)))}&permission=ALL&platform=android&seccode=&subid=1&ts={int(time.time())}&username={parse.quote_plus(self.username)}&validate="
payload = f"{param}&sign={self.calc_sign(param)}"
headers = {'Content-type': "application/x-www-form-urlencoded"}
response = self._requests("post", url, data=payload, headers=headers)
elif response['code'] == 0 and response['data']['status'] == 0:
for cookie in response['data']['cookie_info']['cookies']:
self._session.cookies.set(cookie['name'], cookie['value'], domain=".bilibili.com")
self.access_token = response['data']['token_info']['access_token']
self.refresh_token = response['data']['token_info']['refresh_token']
self._log("登录成功")
return True
else:
self._log(f"登录失败 {response}")
return False
else:
self._log(f"当前IP登录过于频繁, {'尝试更换代理' if self.proxy else '1分钟后重试'}")
if not self.set_proxy():
time.sleep(60)
break
self._session.cookies.clear()
for name in ["bili_jct", "DedeUserID", "DedeUserID__ckMd5", "sid", "SESSDATA"]:
value = kwargs.get(name)
if value:
self._session.cookies.set(name, value, domain=".bilibili.com")
self.access_token = kwargs.get("access_token", "")
self.refresh_token = kwargs.get("refresh_token", "")
self.username = kwargs.get("username", "")
self.password = kwargs.get("password", "")
force_refresh_token = kwargs.get("force_refresh_token", False)
if (not force_refresh_token or not self.access_token or not self.refresh_token) and all(key in self.get_cookies() for key in ["bili_jct", "DedeUserID", "DedeUserID__ckMd5", "sid", "SESSDATA"]) and by_cookie():
return True
elif self.access_token and self.refresh_token and by_token(force_refresh_token):
return True
elif self.username and self.password and by_password():
return True
else:
self._session.cookies.clear()
return False
# 获取用户信息
def get_user_info(self):
url = f"{self.protocol}://api.bilibili.com/x/space/myinfo?jsonp=jsonp"
headers = {
'Host': "api.bilibili.com",
'Referer': f"https://space.bilibili.com/{self.get_uid()}/",
}
response = self._requests("get", url, headers=headers)
if response and response.get("code") == 0:
self.info['ban'] = bool(response['data']['silence'])
self.info['coins'] = response['data']['coins']
self.info['experience']['current'] = response['data']['level_exp']['current_exp']
self.info['experience']['next'] = response['data']['level_exp']['next_exp']
self.info['face'] = response['data']['face']
self.info['level'] = response['data']['level']
self.info['nickname'] = response['data']['name']
self._log(f"{self.info['nickname']}(UID={self.get_uid()}), Lv.{self.info['level']}({self.info['experience']['current']}/{self.info['experience']['next']}), 拥有{self.info['coins']}枚硬币, 账号{'状态正常' if not self.info['ban'] else '被封禁'}")
return True
else:
self._log("用户信息获取失败")
return False
# 修改隐私设置
def set_privacy(self, show_favourite=None, show_bangumi=None, show_tag=None, show_reward=None, show_info=None, show_game=None):
# show_favourite = 展示[我的收藏夹]
# show_bangumi = 展示[订阅番剧]
# show_tag = 展示[订阅标签]
# show_reward = 展示[最近投币的视频]
# show_info = 展示[个人资料]
# show_game = 展示[最近玩过的游戏]
privacy = {
'fav_video': show_favourite,
'bangumi': show_bangumi,
'tags': show_tag,
'coins_video': show_reward,
'user_info': show_info,
'played_game': show_game,
}
url = f"{self.protocol}://space.bilibili.com/ajax/settings/getSettings?mid={self.get_uid()}"
headers = {
'Host': "space.bilibili.com",
'Referer': f"https://space.bilibili.com/{self.get_uid()}/",
}
response = self._requests("get", url, headers=headers)
if response and response.get("status") == True:
for key, value in privacy.items():
if response['data']['privacy'][key] == value:
privacy[key] = None
else:
self._log(f"隐私设置获取失败 {response}")
return False
url = f"{self.protocol}://space.bilibili.com/ajax/settings/setPrivacy"
headers = {
'Host': "space.bilibili.com",
'Origin': "https://space.bilibili.com",
'Referer': f"https://space.bilibili.com/{self.get_uid()}/",
}
fail = []
for key, value in privacy.items():
if value is not None:
payload = {
key: 1 if value else 0,
'csrf': self.get_csrf(),
}
response = self._requests("post", url, data=payload, headers=headers)
if not response or response.get("status") != True:
fail.append(key)
if not fail:
self._log("隐私设置修改成功")
return True
else:
self._log(f"隐私设置修改失败 {fail}")
return False
# 银瓜子兑换硬币
def silver_to_coin(self, app=True, pc=False):
# app = APP通道
# pc = PC通道
if app:
param = f"access_key={self.access_token}&appkey={Bilibili.app_key}&ts={int(time.time())}"
url = f"{self.protocol}://api.live.bilibili.com/AppExchange/silver2coin?{param}&sign={self.calc_sign(param)}"
response = self._requests("get", url)
if response and response.get("code") == 0:
self._log("银瓜子兑换硬币(APP通道)成功")
else:
self._log(f"银瓜子兑换硬币(APP通道)失败 {response}")
if pc:
url = f"{self.protocol}://api.live.bilibili.com/pay/v1/Exchange/silver2coin"
payload = {
'platform': "pc",
'csrf_token': self.get_csrf(),
}
headers = {
'Host': "api.live.bilibili.com",
'Origin': "https://live.bilibili.com",
'Referer': "https://live.bilibili.com/exchange",
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
self._log("银瓜子兑换硬币(PC通道)成功")
else:
self._log(f"银瓜子兑换硬币(PC通道)失败 {response}")
# 观看
@__bvid_handle(1, "aid")
def watch(self, aid):
# aid = 稿件av号
url = f"{self.protocol}://api.bilibili.com/x/web-interface/view?aid={aid}"
response = self._requests("get", url)
if response and response.get("data") is not None:
cid = response['data']['cid']
duration = response['data']['duration']
else:
self._log(f"av{aid}信息解析失败")
return False
url = f"{self.protocol}://api.bilibili.com/x/report/click/h5"
payload = {
'aid': aid,
'cid': cid,
'part': 1,
'did': self.get_sid(),
'ftime': int(time.time()),
'jsonp': "jsonp",
'lv': None,
'mid': self.get_uid(),
'csrf': self.get_csrf(),
'stime': int(time.time()),
}
headers = {
'Host': "api.bilibili.com",
'Origin': "https://www.bilibili.com",
'Referer': f"https://www.bilibili.com/video/av{aid}",
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
url = f"{self.protocol}://api.bilibili.com/x/report/web/heartbeat"
payload = {
'aid': aid,
'cid': cid,
'jsonp': "jsonp",
'mid': self.get_uid(),
'csrf': self.get_csrf(),
'played_time': 0,
'pause': False,
'realtime': duration,
'dt': 7,
'play_type': 1,
'start_ts': int(time.time()),
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
time.sleep(5)
payload['played_time'] = duration - 1
payload['play_type'] = 0
payload['start_ts'] = int(time.time())
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
self._log(f"av{aid}观看成功")
return True
self._log(f"av{aid}观看失败 {response}")
return False
# 点赞
@__bvid_handle(1, "aid")
def like(self, aid):
# aid = 稿件av号
url = f"{self.protocol}://api.bilibili.com/x/web-interface/archive/like"
payload = {
'aid': aid,
'like': 1,
'csrf': self.get_csrf(),
}
headers = {
'Host': "api.bilibili.com",
'Origin': "https://www.bilibili.com",
'Referer': f"https://www.bilibili.com/video/av{aid}",
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
self._log(f"av{aid}点赞成功")
return True
else:
self._log(f"av{aid}点赞失败 {response}")
return False
# 投币
@__bvid_handle(1, "aid")
def reward(self, aid, double=True):
# aid = 稿件av号
# double = 双倍投币
url = f"{self.protocol}://api.bilibili.com/x/web-interface/coin/add"
payload = {
'aid': aid,
'multiply': 2 if double else 1,
'cross_domain': "true",
'csrf': self.get_csrf(),
}
headers = {
'Host': "api.bilibili.com",
'Origin': "https://www.bilibili.com",
'Referer': f"https://www.bilibili.com/video/av{aid}",
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
self._log(f"av{aid}投{2 if double else 1}枚硬币成功")
return True
else:
self._log(f"av{aid}投{2 if double else 1}枚硬币失败 {response}")
return self.reward(aid, False) if double else False
# 收藏
@__bvid_handle(1, "aid")
def favour(self, aid):
# aid = 稿件av号
url = f"{self.protocol}://api.bilibili.com/x/v2/fav/folder"
headers = {'Host': "api.bilibili.com"}
response = self._requests("get", url, headers=headers)
if response and response.get("data"):
fid = response['data'][0]['fid']
else:
self._log("fid获取失败")
return False
url = f"{self.protocol}://api.bilibili.com/x/v2/fav/video/add"
payload = {
'aid': aid,
'fid': fid,
'jsonp': "jsonp",
'csrf': self.get_csrf(),
}
headers = {
'Host': "api.bilibili.com",
'Origin': "https://www.bilibili.com",
'Referer': f"https://www.bilibili.com/video/av{aid}",
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
self._log(f"av{aid}收藏成功")
return True
else:
self._log(f"av{aid}收藏失败 {response}")
return False
# 三连推荐
@__bvid_handle(1, "aid")
def combo(self, aid):
# aid = 稿件av号
url = f"{self.protocol}://api.bilibili.com/x/web-interface/archive/like/triple"
payload = {
'aid': aid,
'csrf': self.get_csrf(),
}
headers = {
'Host': "api.bilibili.com",
'Origin': "https://www.bilibili.com",
'Referer': f"https://www.bilibili.com/video/av{aid}",
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
self._log(f"av{aid}三连推荐成功")
return True
else:
self._log(f"av{aid}三连推荐失败 {response}")
return False
# 分享
@__bvid_handle(1, "aid")
def share(self, aid):
# aid = 稿件av号
url = f"{self.protocol}://api.bilibili.com/x/web-interface/share/add"
payload = {
'aid': aid,
'jsonp': "jsonp",
'csrf': self.get_csrf(),
}
headers = {
'Host': "api.bilibili.com",
'Origin': "https://www.bilibili.com",
'Referer': f"https://www.bilibili.com/video/av{aid}",
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
self._log(f"av{aid}分享成功")
return True
else:
self._log(f"av{aid}分享失败 {response}")
return False
# 关注
def follow(self, mid, secret=False):
# mid = 被关注用户UID
# secret = 悄悄关注
url = f"{self.protocol}://api.bilibili.com/x/relation/modify"
payload = {
'fid': mid,
'act': 3 if secret else 1,
're_src': 11,
'jsonp': "jsonp",
'csrf': self.get_csrf(),
}
headers = {
'Host': "api.bilibili.com",
'Origin': "https://space.bilibili.com",
'Referer': f"https://space.bilibili.com/{mid}/",
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
self._log(f"用户{mid}{'悄悄' if secret else ''}关注成功")
return True
else:
self._log(f"用户{mid}{'悄悄' if secret else ''}关注失败 {response}")
return False
# 批量关注
def follow_batch(self, mids):
# mids = 被关注用户UID
url = f"{self.protocol}://api.bilibili.com/x/relation/batch/modify"
payload = {
'fids': ",".join(map(str, mids)),
'act': 1,
'csrf': self.get_csrf(),
're_src': 222,
}
headers = {
'Host': "api.bilibili.com",
'Referer': "https://www.bilibili.com/blackboard/live/activity-NfUS01P8.html",
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
self._log(f"用户{', '.join(map(str, mids))}批量关注成功")
return True
else:
self._log(f"用户{', '.join(map(str, mids))}批量关注失败 {response}")
return False
# 弹幕发送
@__bvid_handle(1, "aid")
def danmaku_post(self, aid, message, page=1, moment=-1):
# aid = 稿件av号
# message = 弹幕内容
# page = 分P
# moment = 弹幕发送时间
url = f"{self.protocol}://api.bilibili.com/x/web-interface/view?aid={aid}"
response = self._requests("get", url)
if response and response.get("data") is not None:
page_info = {page['page']: {
'cid': page['cid'],
'duration': page['duration'],
} for page in response['data']['pages']}
if page in page_info:
oid = page_info[page]['cid']
duration = page_info[page]['duration']
else:
self._log(f"av{aid}不存在P{page}")
return False
else:
self._log(f"av{aid}信息解析失败")
return False
url = f"{self.protocol}://api.bilibili.com/x/v2/dm/post"
headers = {
'Host': "api.bilibili.com",
'Origin': "https://www.bilibili.com",
'Referer': f"https://www.bilibili.com/video/av{aid}",
}
while True:
payload = {
'type': 1,
'oid': oid,
'msg': message,
'aid': aid,
'progress': int(moment * 1E3) if moment != -1 else random.randint(0, duration * 1E3),
'color': 16777215,
'fontsize': 25,
'pool': 0,
'mode': 1,
'rnd': int(time.time() * 1E6),
'plat': 1,
'csrf': self.get_csrf(),
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") is not None:
if response['code'] == 0:
self._log(f"av{aid}(P{page})弹幕\"{message}\"发送成功")
return True
elif response['code'] == 36703:
self._log(f"av{aid}(P{page})弹幕发送频率过快, 10秒后重试")
time.sleep(10)
else:
self._log(f"av{aid}(P{page})弹幕\"{message}\"发送失败 {response}")
return False
# 评论点赞
def comment_like(self, otype, oid, rpid):
# otype = 作品类型
# oid = 作品ID
# rpid = 评论ID
if Bilibili.patterns.get(otype) is None:
return False
url = f"{self.protocol}://api.bilibili.com/x/v2/reply/action"
payload = {
'oid': oid,
'type': Bilibili.patterns[otype]['id'],
'rpid': rpid,
'action': 1,
'jsonp': "jsonp",
'csrf': self.get_csrf(),
}
headers = {
'Content-Type': "application/x-www-form-urlencoded; charset=UTF-8",
'Host': "api.bilibili.com",
'Origin': "https://www.bilibili.com",
'Referer': f"{Bilibili.patterns[otype]['prefix']}{oid}",
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
self._log(f"评论{rpid}点赞成功")
return True
else:
self._log(f"评论{rpid}点赞失败 {response}")
return False
# 评论发表
def comment_post(self, otype, oid, message):
# otype = 作品类型
# oid = 作品ID
# message = 评论内容
if Bilibili.patterns.get(otype) is None:
return False
url = f"{self.protocol}://api.bilibili.com/x/v2/reply/add"
while True:
payload = {
'oid': oid,
'type': Bilibili.patterns[otype]['id'],
'message': message,
'plat': 1,
'jsonp': "jsonp",
'csrf': self.get_csrf(),
}
headers = {
'Content-Type': "application/x-www-form-urlencoded; charset=UTF-8",
'Host': "api.bilibili.com",
'Origin': "https://www.bilibili.com",
'Referer': f"{Bilibili.patterns[otype]['prefix']}{oid}",
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") is not None:
if response['code'] == 0:
self._log(f"作品{oid}提交评论\"{message}\"成功")
return True
elif response['code'] == 12015:
response = self._requests("get", response['data']['url'], headers=headers, decode_level=1)
captcha = self._solve_captcha(response)
if captcha:
self._log(f"评论验证码识别结果: {captcha}")
payload['code'] = captcha
else:
self._log(f"评论验证码识别服务暂时不可用, 1分钟后重试")
time.sleep(60)
elif response['code'] == 12035:
self._log(f"作品{oid}提交评论\"{message}\"失败, 该账号被UP主列入评论黑名单")
return False
elif response['code'] == -105:
if "code" in payload:
payload.pop("code")
else:
self._log(f"作品{oid}提交评论\"{message}\"失败 {response}")
return False
# 动态点赞
def dynamic_like(self, did):
# did = 动态ID
url = f"{self.protocol}://api.vc.bilibili.com/dynamic_like/v1/dynamic_like/thumb"
payload = {
'uid': self.get_uid(),
'dynamic_id': did,
'up': 1,
'csrf_token': self.get_csrf(),
}
headers = {
'Content-Type': "application/x-www-form-urlencoded",
'Host': "api.vc.bilibili.com",
'Origin': "https://space.bilibili.com",
'Referer': "https://space.bilibili.com/208259/",
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
self._log(f"动态{did}点赞成功")
return True
else:
self._log(f"动态{did}点赞失败 {response}")
return False
# 动态转发
def dynamic_repost(self, did, message="转发动态", ats=[]):
# did = 动态ID
# message = 转发内容
# ats = 被@用户UID列表
def uid_to_nickname(mid):
url = f"{self.protocol}://api.bilibili.com/x/web-interface/card?mid={mid}"
response = self._requests("get", url)
if response and response.get("code") == 0:
return response['data']['card']['name']
else:
return ""
url = f"{self.protocol}://api.vc.bilibili.com/dynamic_repost/v1/dynamic_repost/repost"
ctrl = []
for at in zip(ats, [uid_to_nickname(mid) for mid in ats]):
ctrl.append({
'data': str(at[0]),
'location': len(message) + 1,
'length': len(at[1]) + 1,
'type': 1,
})
message = f"{message} @{at[1]}"
payload = {
'uid': self.get_uid(),
'dynamic_id': did,
'content': message,
'at_uids': ",".join([str(at) for at in ats]),
'ctrl': json.dumps(ctrl),
'csrf_token': self.get_csrf(),
}
headers = {
'Content-Type': "application/x-www-form-urlencoded",
'Host': "api.vc.bilibili.com",
'Origin': "https://space.bilibili.com",
'Referer': "https://space.bilibili.com/208259/",
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
self._log(f"动态{did}转发成功")
return True
else:
self._log(f"动态{did}转发失败 {response}")
return False
# 动态清理
def dynamic_purge(self):
def get_lottery_dynamics():
headers = {
'Host': "api.vc.bilibili.com",
'Origin': "https://space.bilibili.com",
'Referer': f"https://space.bilibili.com/{self.get_uid()}/dynamic",
}
dynamics = []
offset = 0
while True:
url = f"{self.protocol}://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history?visitor_uid={self.get_uid()}&host_uid={self.get_uid()}&offset_dynamic_id={offset}"
response = self._requests("get", url, headers=headers)
if response and response.get("code") == 0:
if response['data']['has_more']:
dynamics.extend([{
'did': card['desc']['dynamic_id'],
'lottery_did': card['desc']['orig_dy_id'],
} for card in response['data']['cards'] if card['desc']['orig_type'] == 2 or card['desc']['orig_type'] == 1024])
offset = response['data']['cards'][-1]['desc']['dynamic_id']
else:
return dynamics
dynamics = get_lottery_dynamics()
self._log(f"发现{len(dynamics)}条互动抽奖动态")
delete = 0
for dynamic in dynamics:
url = f"{self.protocol}://api.vc.bilibili.com/lottery_svr/v2/lottery_svr/lottery_notice?dynamic_id={dynamic['lottery_did']}"
headers = {
'Host': "api.vc.bilibili.com",
'Origin': "https://t.bilibili.com",
'Referer': "https://t.bilibili.com/lottery/h5/index/",
}
response = self._requests("get", url, headers=headers)
if response and response.get("code") == 0:
expired = response['data']['status'] == 2 or response['data']['status'] == -1
winning = any(self.get_uid() in winners for winners in [response['data'].get("lottery_result", {}).get(f"{level}_prize_result", []) for level in ["first", "second", "third"]])
if not expired:
self._log(f"动态{dynamic['lottery_did']}尚未开奖({time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(response['data']['lottery_time']))}), 跳过")
else:
if winning:
self._log(f"动态{dynamic['lottery_did']}中奖, 跳过")
else:
url = f"{self.protocol}://api.vc.bilibili.com/dynamic_repost/v1/dynamic_repost/rm_rp_dyn"
payload = {
'uid': self.get_uid(),
'dynamic_id': dynamic['did'],
'csrf_token': self.get_csrf(),
}
headers = {
'Content-Type': "application/x-www-form-urlencoded",
'Host': "api.vc.bilibili.com",
'Origin': "https://space.bilibili.com",
'Referer': f"https://space.bilibili.com/{self.get_uid()}/dynamic",
}
response = self._requests("post", url, data=payload, headers=headers)
if response and response.get("code") == 0:
delete += 1
self._log(f"动态{dynamic['lottery_did']}未中奖, 清理成功")
else:
self._log(f"动态{dynamic['lottery_did']}未中奖, 清理失败")
time.sleep(1)
self._log(f"清理了{delete}条动态")
# 系统通知查询
def system_notice(self, time_span=["", ""], keyword=[]):
# time_span = 时间范围
# keyword = 包含关键字
cursor_span = [int(time.mktime(time.strptime(element, "%Y-%m-%d %H:%M:%S")) * 1E9) if element else "" for element in time_span]
headers = {
'Host': "message.bilibili.com",
'Referer': "https://message.bilibili.com/",
}
notice_list = []
cursor = cursor_span[1]
while True:
url = f"{self.protocol}://message.bilibili.com/api/notify/query.sysnotify.list.do?data_type=1{'&cursor=' + str(cursor) if cursor else ''}"
response = self._requests("get", url, headers=headers)
if response and response.get("code") == 0:
for notice in response['data']:
if not cursor_span[0] or notice['cursor'] > cursor_span[0]:
if not keyword or any(keyword in notice['title'] or keyword in notice['content'] for keyword in keyword):
notice_list.append({
'time': notice['time_at'],
'title': notice['title'],
'content': notice['content'],
})
else:
break
else:
if len(response['data']) == 20:
cursor = notice['cursor']
continue
self._log(f"系统通知获取成功, 总计{len(notice_list)}条通知")
for notice in notice_list:
self._log(f"{notice['title']}({notice['time']}): {notice['content']}")
self.__push_to_queue("system_notice", notice_list)
return notice_list
# 会员购抢购
def mall_rush(self, item_id, thread=1, headless=True, timeout=10):
# item_id = 商品ID
# thread = 线程数
# headless = 隐藏窗口
# timeout = 超时刷新
def executor(thread_id):
def find_and_click(class_name):
try:
element = driver.find_element_by_class_name(class_name)
element.click()
except:
element = None
return element
options = webdriver.ChromeOptions()
options.add_argument("log-level=3")
if headless:
options.add_argument("headless")
else:
options.add_argument("disable-infobars")
options.add_argument("window-size=374,729")
if platform.system() == "Linux":
options.add_argument("no-sandbox")
options.add_experimental_option("mobileEmulation", {'deviceName': "Nexus 5"})
if platform.system() == "Windows":
options.binary_location = "chrome-win\\chrome.exe"
driver = webdriver.Chrome(executable_path="chromedriver.exe" if platform.system() == "Windows" else "chromedriver", options=options)
driver.get(f"{self.protocol}://mall.bilibili.com/detail.html?itemsId={item_id}")
for key, value in self.get_cookies().items():
driver.add_cookie({
'name': key,
'value': value,
'domain': ".bilibili.com",
})
self._log(f"(线程{thread_id})商品{item_id}开始监视库存")
url = f"{self.protocol}://mall.bilibili.com/mall-c/items/info?itemsId={item_id}"
while True:
response = self._requests("get", url)
if response and response.get("code") == 0 and response['data']['activityInfoVO']['serverTime'] >= response['data']['activityInfoVO']['startTime'] if response['data']['activityInfoVO'] else True:
break
timestamp = time.time()
in_stock = False
while True:
try:
result = {class_name: find_and_click(class_name) for class_name in ["bottom-buy-button", "button", "dot", "pay-btn", "expire-time-format", "alert-ok", "error-button"]}
if result['bottom-buy-button']:
if "bottom-buy-disable" not in result['bottom-buy-button'].get_attribute("class"):
if not in_stock:
self._log(f"(线程{thread_id})商品{item_id}已开放购买")
in_stock = True
else:
if in_stock:
self._log(f"(线程{thread_id})商品{item_id}暂无法购买, 原因为{result['bottom-buy-button'].text}")
in_stock = False
driver.refresh()
timestamp = time.time()
if result['pay-btn']:
timestamp = time.time()
if result['alert-ok']:
driver.refresh()
if result['expire-time-format']:
self._log(f"(线程{thread_id})商品{item_id}订单提交成功, 请在{result['expire-time-format'].text}内完成支付")
driver.quit()
return True
if time.time() - timestamp > timeout:
self._log(f"(线程{thread_id})商品{item_id}操作超时, 当前页面为{driver.current_url}")
driver.get(f"{self.protocol}://mall.bilibili.com/detail.html?itemsId={item_id}")
timestamp = time.time()
except:
pass
threads = []
for i in range(thread):
threads.append(threading.Thread(target=executor, args=(i + 1,)))
for thread in threads:
thread.start()
for thread in threads:
thread.join()
# 会员购优惠卷领取
def mall_coupon(self, coupon_id, thread=1):
# coupon_id = 优惠券ID
# thread = 线程数
def get_coupon_info(coupon_id):
url = f"{self.protocol}://mall.bilibili.com/mall-c/coupon/user_coupon_code_receive_status_list"
payload = {
'couponIds': [str(coupon_id)],
'mid': "",
'csrf': self.get_csrf(),
}
headers = {
'Host': "mall.bilibili.com",
'Origin': "https://www.bilibili.com",
}
response = self._requests("post", url, json=payload, headers=headers)
if response and response.get("code") == 0:
return {
'end': response['data'][0]['receiveEndTime'],
'message': response['data'][0]['couponStatusMsg'],
'name': response['data'][0]['couponName'],
'total': response['data'][0]['provideNum'],
'remain': response['data'][0]['remainNum'],
'start': response['data'][0]['receiveStartTime'],
'status': response['data'][0]['receiveStatus'],
}
def get_server_time(target_time=0):
url = f"{self.protocol}://mall.bilibili.com/mall-c/common/time/remain?v={int(time.time())}&targetTime={target_time}"
headers = {
'Host': "mall.bilibili.com",
'Origin': "https://www.bilibili.com",
}
response = self._requests("get", url, headers=headers)
if response and response.get("code") == 0:
return {
'current': response['data']['serverTime'],
'remain': response['data']['remainSeconds'],
}
def executor(thread_id):
url = f"{self.protocol}://mall.bilibili.com/mall-c/coupon/create_coupon_code?couponId={coupon_id}&deviceId="
payload = {'csrf': self.get_csrf()}
headers = {
'Host': "mall.bilibili.com",
'Origin': "https://www.bilibili.com",
}
nonlocal flag
while not flag:
response = self._requests("post", url, json=payload, headers=headers)
if response and response.get("code") is not None:
if response['code'] == 83094004:
self._log(f"(线程{thread_id})会员购优惠卷\"{coupon_info['name']}\"(ID={coupon_id})领取成功")
elif response['code'] == 83110005:
self._log(f"(线程{thread_id})会员购优惠卷\"{coupon_info['name']}\"(ID={coupon_id})领取失败, 优惠券领取数量已达到上限")
elif response['code'] == 83110015:
self._log(f"(线程{thread_id})会员购优惠卷\"{coupon_info['name']}\"(ID={coupon_id})领取失败, 优惠券库存不足")
else:
continue
else:
self._log(f"(线程{thread_id})会员购优惠卷\"{coupon_info['name']}\"(ID={coupon_id})领取失败, 当前IP请求过于频繁")
flag = True
coupon_info = get_coupon_info(coupon_id)
if coupon_info:
if coupon_info['message'] == "可领取":
server_time = get_server_time(coupon_info['start'])
if server_time:
delay = max(server_time['remain'] - 3, 0)
self._log(f"会员购优惠卷\"{coupon_info['name']}\"(ID={coupon_id})可领取时间为{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(coupon_info['start']))}至{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(coupon_info['end']))}, 库存{coupon_info['remain']}张, 将于{delay}秒后开始领取")
time.sleep(delay)
else:
self._log(f"会员购服务器时间获取失败")
return
else:
self._log(f"会员购优惠卷\"{coupon_info['name']}\"(ID={coupon_id}){coupon_info['message']}")
return
else:
self._log(f"会员购优惠卷{coupon_id}信息获取失败")
return
flag = False
threads = []
for i in range(thread):
threads.append(threading.Thread(target=executor, args=(i + 1,)))
for thread in threads:
thread.start()
for thread in threads:
thread.join()
# 会员购订单列表查询
def mall_order_list(self, status=0, type=[2]):
# status = 订单状态
# type = 订单类型
def get_order_list(status, type):
headers = {
'Origin': "https://mall.bilibili.com",
'Referer': "https://mall.bilibili.com/orderlist.html",
}
order_list = []
page = 0
while True:
url = f"{self.protocol}://show.bilibili.com/api/ticket/ordercenter/list?pageNum={page}&pageSize=20&status={status}&customer=0&platform=h5&v={int(time.time())}"
response = self._requests("get", url, headers=headers)
if response and response.get("errno") == 0:
data = response['data']['list']
if data:
for order in data:
if not type or order['order_type'] in type:
order_list.append(order)
page += 1
else:
self._log(f"会员购订单列表获取成功, 总计{len(order_list)}个订单")
break
else:
self._log(f"会员购订单列表获取失败 {response}")
return order_list
def get_order_detail(order_id):
url = f"{self.protocol}://mall.bilibili.com/mall-c/order/detail?orderId={order_id}&platform=h5&time={int(time.time())}"
headers = {
'Origin': "https://mall.bilibili.com",
'Referer': f"https://mall.bilibili.com/orderdetail.html?orderId={order_id}",
}
response = self._requests("get", url, headers=headers)
if response and response.get("code") == 0 and response['data']['vo']:
data = response['data']['vo']
self._log(f"会员购订单{order_id}详情获取成功, 包含\"{data['skuList'][0]['itemsName']}\"等{len(data['skuList'])}件商品")
return data
else:
self._log(f"会员购订单{order_id}详情获取失败 {response}")
return {}
def get_order_express(order_id):
url = f"{self.protocol}://mall.bilibili.com/mall-c/order/express/detail?orderId={order_id}"
headers = {
'Origin': "https://mall.bilibili.com",
'Referer': f"https://mall.bilibili.com/orderdetail.html?orderId={order_id}",
}
for _ in range(5):
response = self._requests("get", url, headers=headers)
if response and response.get("code") == 0 and response['data']['vo']:
data = response['data']['vo']
self._log(f"会员购订单{order_id}物流获取成功, 状态为{data['state_v']}")
return data
time.sleep(3)
self._log(f"会员购订单{order_id}物流获取失败 {response}")
return {}
order_list = []
for order in get_order_list(status, type):
order_detail = get_order_detail(order['order_id'])
order_express = get_order_express(order['order_id']) if order_detail and order_detail['orderExpress'] else {}
order_list.append({
'id': order.get("order_id"),
'item': [{
'id': item.get("itemsId"),
'name': item.get("itemsName"),
'spec': item.get("skuSpec"),
'number': item.get("skuNum"),
'price': item.get("price"),
} for item in order_detail.get("skuList", [])],
'create': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(order.get("order_ctime"))) if order.get("current_timestamp") else None,
'status': {
'code': order.get("status"),
'name': order.get("status_name"),
},
'pay': {
'id': order_detail['orderBasic'].get("payId") if order_detail.get("orderBasic") else None,
'time': order.get("pay_ctime") if order.get("pay_ctime") != "0000-00-00 00:00:00" else None,
'channel': order_detail['orderBasic'].get("paymentChannel") if order_detail.get("orderBasic") else None,
'total': order.get("show_money") / 100 if order.get("show_money") else None,
'origin': order_detail['orderBasic'].get("payTotalMoney") if order_detail.get("orderBasic") else None,
'discount': order_detail['orderBasic'].get("discountMoneys") if order_detail.get("orderBasic") else None,
'express': order.get("express_fee") / 100 if order.get("express_fee") else None,
},
'preorder': {
'phone': order_detail['extData'].get("notifyPhoneOrigin") if order_detail.get("extData") else None,
'front': {
'total': order_detail['extData'].get("frontPayMoney") if order_detail.get("extData") else None,
'origin': order_detail['extData'].get("frontMoney") if order_detail.get("extData") else None,
'discount': order_detail['extData'].get("frontDisMoney") if order_detail.get("extData") else None,
},
'final': {
'total': order_detail['extData'].get("finalPayMoney") if order_detail.get("extData") else None,
'origin': order_detail['extData'].get("finalMoney") if order_detail.get("extData") else None,
'discount': order_detail['extData'].get("finalDisMoney") if order_detail.get("extData") else None,
'start': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(order_detail['extData'].get("finalMoneyStart") / 1E3)) if order_detail.get("extData") and order_detail['extData'].get("finalMoneyStart") else None,
'end': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(order_detail['extData'].get("finalMoneyEnd") / 1E3)) if order_detail.get("extData") and order_detail['extData'].get("finalMoneyStart") else None,
},
},
'shipping': {
'name': order_detail['orderDeliver'].get("deliverName") if order_detail.get("orderDeliver") else None,
'phone': order_detail['orderDeliver'].get("deliverPhone") if order_detail.get("orderDeliver") else None,
'address': order_detail['orderDeliver'].get("deliverAddr") if order_detail.get("orderDeliver") else None,
'company': order_detail['orderExpress'].get("com_v") if order_detail.get("orderExpress") else None,
'number': order_detail['orderExpress'].get("sno") if order_detail.get("orderExpress") else None,
'status': order_express.get("state_v"),
'detail': order_express.get("detail"),
},
})
self.__push_to_queue("mall_order_list", order_list)
return order_list
# 会员购优惠券列表查询
def mall_coupon_list(self, status=1):
# status = 优惠券状态
status_map = {
1: "validList",
2: "usedList",
3: "invalidList",
}
if status not in status_map:
return []
headers = {
'Referer': "https://mall.bilibili.com/couponlist.html?noTitleBar=1",
}
coupon_list = []
page = 1
while True:
url = f"{self.protocol}://mall.bilibili.com/mall-c/coupon/list?status={status}&pageIndex={page}&pageSize=20"
response = self._requests("get", url, headers=headers)
if response and response.get("code") == 0:
if response['data'][status_map[status]]:
for coupon in response['data'][status_map[status]]['list']:
coupon_list.append({
'name': coupon['couponCodeName'],
'description': coupon['couponDesc'],
'detail': coupon['couponDetail'],
'discount': coupon['couponDiscount'],
'status': coupon['status'],
'type': coupon['couponCodeType'],
'start': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(coupon['useStartTime'] / 1E3)) if coupon['useStartTime'] else None,
'end': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(coupon['useEndTime'] / 1E3)) if coupon['useEndTime'] else None,
'use': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(coupon['useTime'] / 1E3)) if coupon['useTime'] else None,
'expire': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(coupon['expireDate'] / 1E3)) if coupon['expireDate'] else None,
})
if response['data'][status_map[status]]['hasNextPage']:
page += 1
continue
self._log(f"会员购优惠券列表获取成功, 总计{len(coupon_list)}张优惠券")
for coupon in coupon_list:
self._log(f"会员购优惠券: {coupon['name']}" + (f", 失效时间为{coupon['expire']}" if coupon['expire'] else f", 使用时间为{coupon['use']}" if coupon['use'] else f", 使用有效期为{coupon['start']}至{coupon['end']}" if coupon['start'] and coupon['end'] else ""))
break
else:
self._log(f"会员购优惠券列表获取失败 {response}")
break
self.__push_to_queue("mall_coupon_list", coupon_list)
return coupon_list
# 会员购奖品列表查询
def mall_prize_list(self, status=0, type=[1, 2]):
# status = 奖品状态
# type = 奖品类型
headers = {
'Referer': "https://mall.bilibili.com/prizecenter.html",
}
prize_list = []
page = 1
while True:
url = f"{self.protocol}://mall.bilibili.com/mall-c/prize/list?pageNum={page}&pageSize=20&type={status}&v={int(time.time())}"
response = self._requests("get", url, headers=headers)
if response and response.get("code") == 0:
for prize in response['data']['pageInfo']['list']:
if not type or prize['prizeType'] in type:
prize_list.append({
'name': prize['prizeName'],
'source': prize['sourceName'],
'status': prize['status'],
'type': prize['prizeType'],
'expire': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(prize['expireTime'])),
})
if response['data']['pageInfo']['hasNextPage']:
page += 1
else:
self._log(f"会员购奖品列表获取成功, 总计{len(prize_list)}个奖品, {response['data']['waitDeliveryNum']}个奖品待发货")
for prize in prize_list:
self._log(f"会员购奖品: {prize['name']}, 来自{prize['source']}, 领取有效期至{prize['expire']}")
break
else:
self._log(f"会员购奖品列表获取失败 {response}")
break
self.__push_to_queue("mall_prize_list", prize_list)
return prize_list
# 直播奖品列表查询
def live_prize_list(self):
headers = {
'Origin': "https://link.bilibili.com",
'Referer': "https://link.bilibili.com/p/center/index",
}
prize_list = []
page = 1
while True:
url = f"{self.protocol}://api.live.bilibili.com/lottery/v1/award/award_list?page={page}&month="
response = self._requests("get", url, headers=headers)
if response and response.get("code") == 0:
for prize in response['data']['list']:
prize_list.append({
'name': prize['gift_name'],
'number': prize['gift_num'],
'source': prize['source'],
'status': prize['status'],
'type': prize['gift_type'],
'create': prize['create_time'],
'expire': prize['expire_time'],
})
if page < response['data']['total_page']:
page += 1
else:
self._log(f"直播奖品列表获取成功, 总计{len(prize_list)}个奖品")
for prize in prize_list:
self._log(f"直播奖品: {prize['name']} x{prize['number']}, 来自{prize['source']}, 中奖时间为{prize['create']}, 领取有效期至{prize['expire']}")
break
else:
self._log(f"直播奖品列表获取失败 {response}")
break
self.__push_to_queue("live_prize_list", prize_list)
return prize_list
def detect_charset(file, fallback="utf-8"):
with open(file, "rb") as f:
detector = chardet.UniversalDetector()
for line in f.readlines():
detector.feed(line)
if detector.done:
return detector.result['encoding']
return fallback
def download(url, save_as=None):
print(f"正在下载{url}")
if save_as is None:
save_as = url.split("/")[-1]
with open(save_as, "wb") as f:
response = requests.get(url, stream=True)
length = response.headers.get("content-length")
if length:
length = int(length)
receive = 0
for data in response.iter_content(chunk_size=100 * 1024):
f.write(data)
receive += len(data)
percent = receive / length
print(f"\r[{'=' * int(50 * percent)}{' ' * (50 - int(50 * percent))}] {percent:.0%}", end="", flush=True)
print()
else:
f.write(response.content)
return save_as
def decompress(file, remove=True):
shutil.unpack_archive(file)
if remove:
os.remove(file)
print(f"{file}解压完毕")
def export(queue, config):
bucket = {}
log_file = open(config['global']['log'], "a", encoding="utf-8") if config['global']['log'] else None
try:
while True:
packet = queue.get()
if isinstance(packet, dict) and all(key in packet for key in ['uid', 'manufacturer', 'data']):
if packet['manufacturer'] == "log":
if log_file:
log_file.write(packet['data'] + "\n")
else:
if packet['manufacturer'] not in bucket:
bucket[packet['manufacturer']] = {}
if packet['uid'] not in bucket[packet['manufacturer']]:
bucket[packet['manufacturer']][packet['uid']] = []
if isinstance(packet['data'], list):
bucket[packet['manufacturer']][packet['uid']].extend(packet['data'])
else:
bucket[packet['manufacturer']][packet['uid']].append(packet['data'])
elif packet is None:
for manufacturer, data in bucket.items():
if config.get(manufacturer, {}).get("export"):
with open(config[manufacturer]['export'], "w", encoding="utf-8") as f:
f.write(json.dumps(data, indent=4, ensure_ascii=False))
return
finally:
if log_file:
log_file.close()
def wrapper(arg):
def delay_wrapper(func, interval, arg_list=[()], shuffle=False):
if shuffle:
random.shuffle(arg_list)
for i in range(len(arg_list)):
func(*arg_list[i])
if i < len(arg_list) - 1:
time.sleep(interval)
config, account, queue = arg['config'], arg['account'], arg['queue']
instance = Bilibili(config['global']['https'], queue)
if config['proxy']['enable']:
if isinstance(config['proxy']['pool'], str):
try:
with open(config['proxy']['pool'], "r", encoding=detect_charset(config['proxy']['pool'])) as f:
instance.set_proxy(add=[proxy for proxy in f.read().strip().splitlines() if proxy and proxy[0] != "#"])
except:
pass
elif isinstance(config['proxy']['pool'], list):
instance.set_proxy(add=config['proxy']['pool'])
if instance.login(force_refresh_token=config['user']['force_refresh_token'], **account):
threads = []
if config['get_user_info']['enable']:
threads.append(threading.Thread(target=instance.get_user_info))
if config['set_privacy']['enable']:
threads.append(threading.Thread(target=instance.set_privacy, args=(config['set_privacy']['show_favourite'], config['set_privacy']['show_bangumi'], config['set_privacy']['show_tag'], config['set_privacy']['show_reward'], config['set_privacy']['show_info'], config['set_privacy']['show_game'])))
if config['silver_to_coin']['enable']:
threads.append(threading.Thread(target=instance.silver_to_coin))
if config['watch']['enable']:
threads.append(threading.Thread(target=delay_wrapper, args=(instance.watch, 5, list(zip(config['watch']['aid'])))))
if config['like']['enable']:
threads.append(threading.Thread(target=delay_wrapper, args=(instance.like, 5, list(zip(config['like']['aid'])))))
if config['reward']['enable']:
threads.append(threading.Thread(target=delay_wrapper, args=(instance.reward, 5, list(zip(config['reward']['aid'], config['reward']['double'])))))
if config['favour']['enable']:
threads.append(threading.Thread(target=delay_wrapper, args=(instance.favour, 5, list(zip(config['favour']['aid'])))))
if config['combo']['enable']:
threads.append(threading.Thread(target=delay_wrapper, args=(instance.combo, 5, list(zip(config['combo']['aid'])))))
if config['share']['enable']:
threads.append(threading.Thread(target=delay_wrapper, args=(instance.share, 5, list(zip(config['share']['aid'])))))
if config['follow']['enable']:
threads.append(threading.Thread(target=delay_wrapper, args=(instance.follow, 5, list(zip(config['follow']['mid'], config['follow']['secret'])))))
if config['follow_batch']['enable']:
threads.append(threading.Thread(target=delay_wrapper, args=(instance.follow_batch, 5, list((config['follow_batch']['mid'][i:i + 50],) for i in range(0, len(config['follow_batch']['mid']), 50)))))
if config['danmaku_post']['enable']:
threads.append(threading.Thread(target=delay_wrapper, args=(instance.danmaku_post, 5, list(zip(config['danmaku_post']['aid'], config['danmaku_post']['message'], config['danmaku_post']['page'], config['danmaku_post']['moment'])))))
if config['comment_like']['enable']:
threads.append(threading.Thread(target=delay_wrapper, args=(instance.comment_like, 5, list(zip(config['comment_like']['otype'], config['comment_like']['oid'], config['comment_like']['rpid'])))))
if config['comment_post']['enable']:
threads.append(threading.Thread(target=delay_wrapper, args=(instance.comment_post, 5, list(zip(config['comment_post']['otype'], config['comment_post']['oid'], config['comment_post']['message'])))))
# for comment in zip(config['comment_post']['otype'], config['comment_post']['oid'], config['comment_post']['message']):
# threads.append(threading.Thread(target=instance.comment_post, args=(comment[0], comment[1], comment[2])))
if config['dynamic_like']['enable']:
threads.append(threading.Thread(target=delay_wrapper, args=(instance.dynamic_like, 5, list(zip(config['dynamic_like']['did'])))))
if config['dynamic_repost']['enable']:
threads.append(threading.Thread(target=delay_wrapper, args=(instance.dynamic_repost, 5, list(zip(config['dynamic_repost']['did'], config['dynamic_repost']['message'], config['dynamic_repost']['ats'])))))
if config['dynamic_purge']['enable']:
threads.append(threading.Thread(target=instance.dynamic_purge))
if config['system_notice']['enable']:
threads.append(threading.Thread(target=instance.system_notice, args=(config['system_notice']['time_span'], config['system_notice']['keyword'])))
if config['mall_rush']['enable']:
for item in zip(config['mall_rush']['item_id'], config['mall_rush']['thread']):
threads.append(threading.Thread(target=instance.mall_rush, args=(item[0], item[1], config['mall_rush']['headless'], config['mall_rush']['timeout'])))
if config['mall_coupon']['enable']:
for coupon in zip(config['mall_coupon']['coupon_id'], config['mall_coupon']['thread']):
threads.append(threading.Thread(target=instance.mall_coupon, args=(coupon[0], coupon[1])))
if config['mall_order_list']['enable']:
threads.append(threading.Thread(target=instance.mall_order_list, args=(config['mall_order_list']['status'], config['mall_order_list']['type'])))
if config['mall_coupon_list']['enable']:
threads.append(threading.Thread(target=instance.mall_coupon_list, args=(config['mall_coupon_list']['status'],)))
if config['mall_prize_list']['enable']:
threads.append(threading.Thread(target=instance.mall_prize_list, args=(config['mall_prize_list']['status'], config['mall_prize_list']['type'])))
if config['live_prize_list']['enable']:
threads.append(threading.Thread(target=instance.live_prize_list))
# instance._log("任务开始执行")
for thread in threads:
thread.start()
for thread in threads:
thread.join()
# instance._log("任务执行完毕")
return {
'username': instance.username,
'password': instance.password,
'access_token': instance.access_token,
'refresh_token': instance.refresh_token,
'cookie': instance.get_cookies(),
}
def main():
print(f"{banner}\n{__doc__}\n版本: {__version__}\n")
config_file = sys.argv[1] if len(sys.argv) > 1 else "config.toml"
try:
with open(config_file, "r", encoding=detect_charset(config_file)) as f:
config = toml.load(f)
except:
print(f"无法加载{config_file}")
return
accounts = []
for line in config['user']['account'].splitlines():
try:
if line[0] == "#":
continue
pairs = {}
for pair in line.strip(";").split(";"):
if len(pair.split("=")) == 2:
key, value = pair.split("=")
pairs[key] = value
password = all(key in pairs for key in ["username", "password"])
token = all(key in pairs for key in ["access_token", "refresh_token"])
cookie = all(key in pairs for key in ["bili_jct", "DedeUserID", "DedeUserID__ckMd5", "sid", "SESSDATA"])
if password or token or cookie:
accounts.append(pairs)
except:
pass
config['user'].pop("account")
print(f"导入了{len(accounts)}个用户")
if not accounts:
return
if config['mall_rush']['enable']:
if platform.system() == "Linux" and os.path.exists("/etc/debian_version"):
prefix = "sudo " if shutil.which("sudo") else ""
if shutil.which("chromium-browser") is None:
os.system(f"{prefix}apt -y install chromium-browser")
if shutil.which("chromedriver") is None:
os.system(f"{prefix}apt -y install chromium-chromedriver")
os.system(f"{prefix}ln -s /usr/lib/chromium-browser/chromedriver /usr/bin")
elif platform.system() == "Linux" and os.path.exists("/etc/redhat-release"):
prefix = "sudo " if shutil.which("sudo") else ""
if shutil.which("chromium-browser") is None:
os.system(f"{prefix}yum -y install chromium")
if shutil.which("chromedriver") is None:
os.system(f"{prefix}yum -y install chromedriver")
elif platform.system() == "Windows":
if not os.path.exists("chrome-win\\chrome.exe"):
decompress(download("https://npm.taobao.org/mirrors/chromium-browser-snapshots/Win/706915/chrome-win.zip"))
if not os.path.exists("chromedriver.exe"):
decompress(download("https://npm.taobao.org/mirrors/chromedriver/79.0.3945.36/chromedriver_win32.zip"))
else:
print("会员购抢购组件不支持在当前平台上运行")
config['mall_rush']['enable'] = False
queue = Manager().Queue()
export_process = Process(target=export, args=(queue, config))
export_process.start()
with Pool(min(config['global']['process'], len(accounts))) as p:
result = p.map(wrapper, [{
'config': config,
'account': account,
'queue': queue,
} for account in accounts])
p.close()
p.join()
if config['user']['update']:
with open(config_file, "r+", encoding=detect_charset(config_file)) as f:
content = f.read()
before = content.split("account")[0]
after = content.split("account")[-1].split("\"\"\"")[-1]
f.seek(0)
f.truncate()
f.write(before)
f.write("account = \"\"\"\n")
for credential in result:
new_line = False
for key, value in credential.items():
if value:
if key == "cookie":
f.write(f"{';'.join(f'{key}={value}' for key, value in value.items())};")
else:
f.write(f"{key}={value};")
new_line = True
if new_line:
f.write("\n")
f.write("\"\"\"")
f.write(after)
print("凭据已更新")
queue.put(None)
export_process.join()
if __name__ == "__main__":
freeze_support()
main()
if platform.system() == "Windows":
os.system("pause >nul | set /p =请按任意键退出")
import requests
import sys;
sys.path.append("My-Actions/function/")
from bilibili import *
import time
import os
msg = ""
day = ""
serverJ = os.environ['push_key']
# 尝试登陆
b = Bilibili()
b.login(username=os.environ['BILI_USER'], password=os.environ['BILI_PASS'])
# 获取 Cookie
cookie_str = ""
cookies = b.get_cookies()
for cookie in cookies:
cookie_str += cookie + "=" + cookies[cookie] + "; "
headers_with_cookie={
'User-Agent': "Mozilla/5.0 BiliDroid/6.4.0 (bbcallen@gmail.com) os/android model/M1903F11I mobi_app/android build/6040500 channel/bili innerVer/6040500 osVer/9.0.0 network/2",
'Cookie': cookie_str
}
print("哔哩哔哩漫画开始签到 start>>>")
msg = msg + "哔哩哔哩漫画开始签到: \n"
r = requests.post("https://manga.bilibili.com/twirp/activity.v1.Activity/ClockIn", verify=False, headers=headers_with_cookie, data={
"platform": "android"
})
# print("响应: " + r.text)
if r.json()['code'] == 0:
print("签到成功.")
msg = msg + "签到成功🐶\n"
if r.json()['msg'] == "clockin clockin is duplicate":
print("今日已签到.")
msg = msg + "今日已签到⚠\n"
time.sleep(2)
print("哔哩哔哩漫画获取签到信息 start>>>")
msg = msg + "哔哩哔哩漫画获取签到信息: \n"
r = requests.post("https://manga.bilibili.com/twirp/activity.v1.Activity/GetClockInInfo", verify=False, headers=headers_with_cookie)
day = str(r.json()['data']['day_count'])
if day == "0":
print("登录失败,未登录🐶")
msg = "登录失败,未登录🐶"
print("累计签到" + day + "天🐶")
msg = msg + "累计签到" + day + "天🐶\n"
time.sleep(3)
# 如果不使用银瓜子兑换硬币 请注释掉下面两行即可。
print("哔哩哔哩银瓜子兑换硬币 start>>>")
print(b.silver_to_coin())
# print(msg)
# Server酱
if serverJ != "":
api = "https://sc.ftqq.com/"+ serverJ + ".send"
title = u"哔哩哔哩漫画签到"
content = msg
data = {
"text":title,
"desp":content
}
req = requests.post(api,data = data)
// version v0.0.1
// create by BlueSkyClouds
// detail url: https://github.com/BlueskyClouds/iQIYI-DailyBonus
const exec = require('child_process').execSync
const fs = require('fs')
const download = require('download')
const $ = new Env('爱奇艺会员签到');
const notify = $.isNode() ? require('../sendNotify') : '';
// 公共变量
const KEY = process.env.iQIYI_COOKIE
const SEND_KEY = process.env.SEND_KEY
async function downFile () {
const url = 'https://raw.githubusercontent.com/NobyDa/Script/master/iQIYI-DailyBonus/iQIYI.js'
await download(url, './')
}
async function changeFiele () {
let content = await fs.readFileSync('./iQIYI.js', 'utf8')
content = content.replace(/var cookie = ''/, `var cookie = '${KEY}'`)
await fs.writeFileSync( './iQIYI.js', content, 'utf8')
}
async function deleteFile(path) {
// 查看文件result.txt是 否存在,如果存在,先删除
const fileExists = await fs.existsSync(path);
// console.log('fileExists', fileExists);
if (fileExists) {
const unlinkRes = await fs.unlinkSync(path);
// console.log('unlinkRes', unlinkRes)
}
}
async function start() {
if (!KEY) {
console.log('请填写 key 后在继续')
return
}
// 下载最新代码
await downFile();
console.log('下载代码完毕')
// 替换变量
await changeFiele();
console.log('替换变量完毕')
// 执行
await exec("node iQIYI.js >> result.txt");
console.log('执行完毕')
const path = "./result.txt";
let content = "";
if (fs.existsSync(path)) {
content = fs.readFileSync(path, "utf8");
}
if(SEND_KEY) {
if (content.includes("Cookie")) {
await notify.sendNotify("爱奇艺签到-" + new Date().toLocaleDateString(), content);
console.log("爱奇艺签到-" + content)
}else{
console.log("爱奇艺签到-" + content)
}
}else{
await notify.sendNotify("爱奇艺签到-" + new Date().toLocaleDateString(), content);
console.log("爱奇艺签到-" + content)
}
//运行完成后,删除下载的文件
console.log('运行完成后,删除下载的文件\n')
await deleteFile(path);
}
start()
// prettier-ignore
function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),a={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(a,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon()?(this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)})):this.isQuanX()?(this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t))):this.isNode()&&(this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)}))}post(t,e=(()=>{})){if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.post(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method="POST",this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){this.initGotEnv(t);const{url:s,...i}=t;this.got.post(s,i).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)})}}time(t){let e={"M+":(new Date).getMonth()+1,"d+":(new Date).getDate(),"H+":(new Date).getHours(),"m+":(new Date).getMinutes(),"s+":(new Date).getSeconds(),"q+":Math.floor(((new Date).getMonth()+3)/3),S:(new Date).getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,((new Date).getFullYear()+"").substr(4-RegExp.$1.length)));for(let s in e)new RegExp("("+s+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?e[s]:("00"+e[s]).substr((""+e[s]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl;return{"open-url":e,"media-url":s}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)}
/****
*
* @description 腾讯视频好莱坞会员V力值签到,手机签到和领取任务及奖励。
* @author BlueSkyClouds
* @create_at 2020-11-02
*/
const $ = new Env('腾讯视频会员签到');
const notify = $.isNode() ? require('../sendNotify') : '';
let ref_url = ''
const _cookie = process.env.V_COOKIE
const SEND_KEY = process.env.SEND_KEY
const auth = getAuth()
const axios = require('axios')
var date = new Date()
const headers = {
'Referer': 'https://v.qq.com',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.204 Safari/537.36',
'Cookie': _cookie
}
/**
* @description 拼接REF_URL
*/
if (process.env.V_REF_URL) {
if(process.env.V_REF_URL.indexOf('https://access.video.qq.com/user/auth_refresh?') > -1 ) {
ref_url = process.env.V_REF_URL
} else {
ref_url = `https://access.video.qq.com/user/auth_refresh?${process.env.V_REF_URL}`
}
//验证V_REF_URL和cookie是否填写正确
ref_url_ver()
} else {
console.log("V_REF_URL值填写错误")
}
/**
* @description 封装一个解析setCookie的方法
* @param {*} val
* @returns obj
*/
function parseSet(c_list) {
let obj = {}
c_list.map(t=>{
const obj = {}
t.split(', ')[0].split(';').forEach(item=>{
const [key, val] = item.split('=')
obj[key] = val
})
return obj
}).forEach(t=>obj = { ...obj, ...t })
return obj
}
/**
* @description 获取有效的cookie参数
* @param {*} [c=_cookie]
* @returns obj
*/
function getAuth(c = _cookie) {
let needParams = [""]
//适配微信登录
if(_cookie){
if (_cookie.includes("main_login=wx")) {
needParams = ["tvfe_boss_uuid","video_guid","video_platform","pgv_pvid","pgv_info","pgv_pvi","pgv_si","_qpsvr_localtk","RK","ptcz","ptui_loginuin","main_login","access_token","appid","openid","vuserid","vusession"]
} else {
needParams = ["tvfe_boss_uuid","video_guid","video_platform","pgv_pvid","pgv_info","pgv_pvi","pgv_si","_qpsvr_localtk","RK","ptcz","ptui_loginuin","main_login","vqq_access_token","vqq_appid","vqq_openid","vqq_vuserid","vqq_vusession"]
}
}
const obj = {}
if(c){
c.split('; ').forEach(t=>{
const [key, val] = t.split(/\=(.*)$/,2)
needParams.indexOf(key) !=-1 && ( obj[key] = val)
})
}
return obj
}
/**
* @description 刷新每天更新cookie参数
* @returns
*/
function refCookie(url = ref_url) {
return new Promise((resovle, reject)=>{
axios({ url, headers }).then(e =>{
const { vusession } = parseSet(e.headers['set-cookie'])
const { vqq_vusession } = parseSet(e.headers['set-cookie'])
//微信和QQ参数不同
if (vusession) {
auth['vusession'] = vusession
} else {
auth['vqq_vusession'] = vqq_vusession
}
// 刷新cookie后去签到
resovle({
...headers, Cookie: Object.keys(auth).map(i => i + '=' + auth[i]).join('; '),
'Referer': 'https://m.v.qq.com'
})
}).catch(reject)
})
}
/**
* @description 验证ref_url是否正确
*/
function ref_url_ver(url = ref_url,_cookie) {
$.get({
url, headers
}, function(error, response, data) {
if (error) {
$.log(error);
console.log("腾讯视频会员签到", "验证ref_url请求失败 ‼️‼️", error)
} else {
if (data.match(/nick/)) { //通过验证获取QQ昵称参数来判断是否正确
console.log("验证成功,执行主程序")
//console.log(data)
exports.main()
} else {
console.log("验证失败,无法获取个人资料")
}
}
})
}
// 手机端签到
function txVideoSignIn(headers) {
$.get({
url: `https://vip.video.qq.com/fcgi-bin/comm_cgi?name=hierarchical_task_system&cmd=2&_=${ parseInt(Math.random()*1000) }`,headers
}, function(error, response, data) {
if (error) {
$.log(error);
console.log("腾讯视频会员签到", "签到请求失败 ‼️‼️", error)
} else {
if (data.match(/Account Verify Error/)) {
if(SEND_KEY){
notify.sendNotify("腾讯视频会员签到", "签到失败, Cookie失效 ‼️‼️");
console.log("腾讯视频会员签到", "", "签到失败, Cookie失效 ‼️‼️")
}else{
console.log("腾讯视频会员签到", "", "签到失败, Cookie失效 ‼️‼️")
}
} else if (data.match(/checkin_score/)) {
msg = data.match(/checkin_score": (.+?),"msg/)[1]
//通过分数判断是否重复签到
if(msg == '0'){
msg = '签到失败,重复签到 ‼️‼️'
}else{
msg = "签到成功,签到分数:" + msg + "分 🎉"
}
//签到成功才执行任务签到
console.log("腾讯视频会员签到", "", "以下任务仅领取,需要手动完成,如没有完成请无视" )
Collect_task()
//判断是否为Cookie失效时才提醒
if(SEND_KEY){
console.log("腾讯视频会员签到", "", date.getMonth() + 1 + "月" + date.getDate() + "日, " + msg )
}else{
notify.sendNotify("腾讯视频会员签到", msg);
console.log("腾讯视频会员签到", "", date.getMonth() + 1 + "月" + date.getDate() + "日, " + msg )
}
} else if (data.match(/Not VIP/)) {
console.log("腾讯视频会员签到", "", "非会员无法签到" )
} else {
console.log("腾讯视频会员签到", "", "脚本待更新 ‼️‼️")
//输出日志查找原因
console.log(data)
}
}
})
}
//下载任务签到请求
function txVideoDownTask1(headers) {
$.get({
url: `https://vip.video.qq.com/fcgi-bin/comm_cgi?name=spp_MissionFaHuo&cmd=4&task_id=7`, headers
}, function(error, response, data) {
if (error) {
$.log(error);
console.log("腾讯视频会员签到", "下载任务签到请求 ‼️‼️", error)
} else {
if (data.match(/已发过货/)) {
console.log("腾讯视频会员下载任务签到", "", "签到失败, 请勿重复领取任务 ‼️‼️")
} else if (data.match(/score/)) {
msg = data.match(/score":(.*?)}/)[1]
console.log("腾讯视频会员下载任务签到", "", "签到成功,签到分数:" + msg + "分 🎉")
} else {
console.log("腾讯视频会员下载任务签到", "", "签到失败, 任务未完成 ‼️‼️")
}
}
})
}
//赠送任务签到请求
function txVideoDownTask2(headers) {
$.get({
url: `https://vip.video.qq.com/fcgi-bin/comm_cgi?name=spp_MissionFaHuo&cmd=4&task_id=6`, headers
}, function(error, response, data) {
if (error) {
$.log(error);
console.log("腾讯视频会员签到", "赠送任务签到请求 ‼️‼️", error)
} else {
if (data.match(/已发过货/)) {
console.log("腾讯视频会员赠送任务签到", "", "签到失败, 请勿重复领取任务 ‼️‼️")
} else if (data.match(/score/)) {
msg = data.match(/score":(.*?)}/)[1]
console.log("腾讯视频会员赠送任务签到", "", "签到成功,签到分数:" + msg + "分 🎉")
} else {
console.log("腾讯视频会员赠送任务签到", "", "签到失败, 任务未完成 ‼️‼️")
}
}
})
}
//弹幕任务签到请求
function txVideoDownTask3(headers) {
$.get({
url: `https://vip.video.qq.com/fcgi-bin/comm_cgi?name=spp_MissionFaHuo&cmd=4&task_id=3`, headers
}, function(error, response, data) {
if (error) {
$.log(error);
console.log("腾讯视频会员签到", "弹幕任务签到请求 ‼️‼️", error)
} else {
if (data.match(/已发过货/)) {
console.log("腾讯视频会员弹幕任务签到", "", "签到失败, 请勿重复领取任务 ‼️‼️")
} else if (data.match(/score/)) {
msg = data.match(/score":(.*?)}/)[1]
console.log("腾讯视频会员弹幕任务签到", "", "签到成功,签到分数:" + msg + "分 🎉")
} else {
console.log("腾讯视频会员弹幕任务签到", "", "签到失败, 任务未完成 ‼️‼️")
}
}
})
}
//观看60分钟任务签到请求
function txVideoDownTask4(headers) {
$.get({
url: `https://vip.video.qq.com/fcgi-bin/comm_cgi?name=spp_MissionFaHuo&cmd=4&task_id=1`, headers
}, function(error, response, data) {
if (error) {
$.log(error);
console.log("腾讯视频会员签到", "观看任务签到请求 ‼️‼️", error)
} else {
if (data.match(/已发过货/)) {
console.log("腾讯视频会员观看任务签到", "", "签到失败, 请勿重复领取任务 ‼️‼️")
} else if (data.match(/score/)) {
msg = data.match(/score":(.*?)}/)[1]
console.log("腾讯视频会员观看任务签到", "", "签到成功,签到分数:" + msg + "分 🎉")
} else {
console.log("腾讯视频会员观看任务签到", "", "签到失败, 任务未完成 ‼️‼️")
}
}
})
}
//任务领取
function Collect_task() {
refCookie().then(data => {
this.provinces = data
txVideoDownTask1(data)
txVideoDownTask2(data)
txVideoDownTask3(data)
txVideoDownTask4(data)
})
}
//主程序入口
exports.main = () => new Promise(
(resovle, reject) => refCookie()
.then(params=>Promise.all([ txVideoSignIn(params)])
.then(e=>resovle())
.catch(e=>reject())
).catch(e=>{
//如果有错误自行取消下面这行注释
//console.log(e)
console.log('腾讯视频签到通知-Cookie已失效')
})
)
// prettier-ignore
function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),a={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(a,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon()?(this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)})):this.isQuanX()?(this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t))):this.isNode()&&(this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)}))}post(t,e=(()=>{})){if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.post(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method="POST",this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){this.initGotEnv(t);const{url:s,...i}=t;this.got.post(s,i).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)})}}time(t){let e={"M+":(new Date).getMonth()+1,"d+":(new Date).getDate(),"H+":(new Date).getHours(),"m+":(new Date).getMinutes(),"s+":(new Date).getSeconds(),"q+":Math.floor(((new Date).getMonth()+3)/3),S:(new Date).getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,((new Date).getFullYear()+"").substr(4-RegExp.$1.length)));for(let s in e)new RegExp("("+s+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?e[s]:("00"+e[s]).substr((""+e[s]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl;return{"open-url":e,"media-url":s}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};if(this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r))),!this.isMuteLog){let t=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];t.push(e),s&&t.push(s),i&&t.push(i),console.log(t.join("\n")),this.logs=this.logs.concat(t)}}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)}
{
"name": "My-Actions",
"version": "1.0.0",
"description": "",
"main": "Manga.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/BlueskyClouds/My-Actions.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/BlueskyClouds/My-Actions/issues"
},
"homepage": "https://github.com/BlueskyClouds/My-Actions#readme",
"dependencies": {
"download": "^8.0.0",
"request": "^2.88.2",
"axios": "^0.19.2",
"crypto-js": "^4.0.0",
"request-promise": "^4.2.5",
"got": "^11.7.0",
"tough-cookie": "^4.0.0"
}
}

BlueskyClouds’s github stats

My-Actions

个人收集并适配Github Actions的各类签到大杂烩ee

Version Author

本项目已可以实现自动同步上游更改!具体点击

使用方式

  1. 右上角fork本仓库
  2. 点击Settings -> Secrets -> 点击绿色按钮 (如无绿色按钮说明已激活。直接到第三步。)
  3. 新增 new secret 并设置 Secrets:
  4. 双击右上角自己仓库Star触发,如有不使用项目请禁用部分项目
  5. 必须 - 请随便找个文件(例如README.md),加个空格提交一下,否则可能会出现无法定时执行的问题(由于规则更新,可能会Fork后会默认禁用,请手动点击Actions 选择要签到的项目 enable workflows激活)
  6. 定时执行

定时执行

  1. 支持手动执行,具体在Actions中选中要执行的Workflows后再在右侧可以看到Run workflow,点击即可运行此workflow。

  2. 如果嫌上一步麻烦的,也可以直接点击一下star,你会发现所有的workflow都已执行。

  3. 如需修改执行时间自行修改.github\workflows\下面的yaml内的 cron: 执行时间为国际标准时间 时间转换 分钟在前 小时在后 尽量提前半小时,因为触发和下载需要一定时间

本项目需要设置的 Secrets:

名称 内容 说明
IQIYI_COOKIE 爱奇艺authcookie 爱奇艺cookie中 P00001的值 详情文字教程 视频教程 电脑版有效期三个月
BILI_USER 哔哩哔哩账号 B站账号(由于是账号密码登录,Cookie不会过期,不提供消息失效提醒,并只有Server酱提醒,因为懒.)
BILI_PASS 哔哩哔哩密码 B站密码
V_REF_URL 腾讯视频Request URL 电脑端搜索auth_refresh复制整段Request url图片教程
V_COOKIE 腾讯视频Cookie 电脑端搜索auth_refresh复制Cookie图片教程
TELECOM_MOBILE 中国电信手机号 只需要手机号 单账号 多账号将会暴露手机号 自行考虑,多账号使用,分割 部分地区或手机号暂无法签到,自行测试使用
PUSH_KEY Server酱SCKEY值 cookie失效推送server酱的微信通知
BARK_PUSH Bark推送值 此内容支持自建Bark添加整个链接即可(自建链接切记删除最后一个/ 比如你的是https://a.a.com/ 只需要填写https://a.a.com 即可)
BARK_SOUND BARK app推送铃声 BARK app推送铃声,铃声列表去APP查看复制填写
TG_BOT_TOKEN telegram推送 tg推送,填写自己申请@BotFather的Token,如10xxx4:AAFcqxxxxgER5uw , 具体教程
TG_USER_ID telegram推送 tg推送,填写@getuseridbot中获取到的纯数字ID, 具体教程
SEND_KEY 推送开关 如果你想只在COOKIE失效时发送推送信息,就加一个这个,参数值随便写就行

同步Fork后的代码

手动同步

手动同步 https://blog.blueskyclouds.com/jsfx/58.html

自动同步

方案A - 强制远程分支覆盖自己的分支
  1. 参考这里,安装pull插件,并确认此项目已在pull插件的作用下(参考文中1-d)。
  2. 确保.github/pull.yml文件正常存在,yml内上游作者填写正确(此项目已填好,无需更改)。
  3. 确保pull.yml里面是mergeMethod: hardreset(默认就是hardreset)。
  4. ENJOY!上游更改三小时左右就会自动发起同步。
方案B - 保留自己分支的修改

上游变动后pull插件会自动发起pr,但如果有冲突需要自行手动确认。 如果上游更新涉及workflow里的文件内容改动,需要自行手动确认。

  1. 参考这里,安装pull插件,并确认此项目已在pull插件的作用下(参考文中1-d)。
  2. 确保.github/pull.yml文件正常存在,yml内上游作者填写正确(此项目已填好,无需更改)。
  3. 将pull.yml里面的mergeMethod: hardreset修改为mergeMethod: merge保存。
  4. ENJOY!上游更改三小时左右就会自动发起同步。

访问量

requests
rsa
python-dateutil
const $ = new Env();
// =======================================微信server酱通知设置区域===========================================
//此处填你申请的SCKEY.
//注:此处设置github action用户填写到Settings-Secrets里面(Name输入PUSH_KEY)
let SCKEY = '';
// =======================================Bark App通知设置区域===========================================
//此处填你BarkAPP的信息(IP/设备码,例如:https://api.day.app/XXXXXXXX)
//注:此处设置github action用户填写到Settings-Secrets里面(Name输入BARK_PUSH)
let BARK_PUSH = '';
//BARK app推送铃声,铃声列表去APP查看复制填写
//注:此处设置github action用户填写到Settings-Secrets里面(Name输入BARK_SOUND , Value输入app提供的铃声名称,例如:birdsong)
let BARK_SOUND = '';
// =======================================telegram机器人通知设置区域===========================================
//此处填你telegram bot 的Token,例如:1077xxx4424:AAFjv0FcqxxxxxxgEMGfi22B4yh15R5uw
//注:此处设置github action用户填写到Settings-Secrets里面(Name输入TG_BOT_TOKEN)
let TG_BOT_TOKEN = '';
//此处填你接收通知消息的telegram用户的id,例如:129xxx206
//注:此处设置github action用户填写到Settings-Secrets里面(Name输入TG_USER_ID)
let TG_USER_ID = '';
if (process.env.PUSH_KEY) {
SCKEY = process.env.PUSH_KEY;
}
if (process.env.TG_BOT_TOKEN) {
TG_BOT_TOKEN = process.env.TG_BOT_TOKEN;
}
if (process.env.TG_USER_ID) {
TG_USER_ID = process.env.TG_USER_ID;
}
if (process.env.BARK_PUSH) {
if(process.env.BARK_PUSH.indexOf('https') > -1 || process.env.BARK_PUSH.indexOf('http') > -1) {
//兼容BARK自建用户
BARK_PUSH = process.env.BARK_PUSH
} else {
BARK_PUSH = `https://api.day.app/${process.env.BARK_PUSH}`
}
if (process.env.BARK_SOUND) {
BARK_SOUND = process.env.BARK_SOUND
}
} else {
if(BARK_PUSH && BARK_PUSH.indexOf('https') === -1 && BARK_PUSH.indexOf('http') === -1) {
//兼容BARK本地用户只填写设备码的情况
BARK_PUSH = `https://api.day.app/${BARK_PUSH}`
}
}
async function sendNotify(text, desp) {
//提供的通知
await serverNotify(text, desp);
await BarkNotify(text, desp);
await tgBotNotify(text, desp);
}
function serverNotify(text, desp) {
return new Promise(resolve => {
if (SCKEY) {
//微信server酱推送通知一个\n不会换行,需要两个\n才能换行,故做此替换
desp = desp.replace(/[\n\r]/g, '\n\n');
const options = {
url: `https://sc.ftqq.com/${SCKEY}.send`,
body: `text=${text}&desp=${desp}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
$.post(options, (err, resp, data) => {
try {
if (err) {
console.log('\n发送通知调用API失败!!\n')
console.log(err);
} else {
data = JSON.parse(data);
if (data.errno === 0) {
console.log('\nserver酱发送通知消息成功\n')
} else if (data.errno === 1024) {
console.log('\nPUSH_KEY 错误\n')
}
}
} catch (e) {
$.logErr(e, resp);
} finally {
resolve(data);
}
})
} else {
console.log('\n您未提供server酱的SCKEY,取消微信推送消息通知\n');
resolve()
}
})
}
function BarkNotify(text, desp) {
return new Promise(resolve => {
if (BARK_PUSH) {
const options = {
url: `${BARK_PUSH}/${encodeURIComponent(text)}/${encodeURIComponent(desp)}?sound=${BARK_SOUND}`,
}
$.get(options, (err, resp, data) => {
try {
if (err) {
console.log('\nBark APP发送通知调用API失败!!\n')
console.log(err);
} else {
data = JSON.parse(data);
if (data.code === 200) {
console.log('\nBark APP发送通知消息成功\n')
} else {
console.log(`\n${data.message}\n`);
}
}
} catch (e) {
$.logErr(e, resp);
} finally {
resolve();
}
})
} else {
console.log('\n您未提供Bark的APP推送BARK_PUSH,取消Bark推送消息通知\n');
resolve()
}
})
}
function tgBotNotify(text, desp) {
return new Promise(resolve => {
if (TG_BOT_TOKEN && TG_USER_ID) {
const options = {
url: `https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage`,
body: `chat_id=${TG_USER_ID}&text=${text}\n\n${desp}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
$.post(options, (err, resp, data) => {
try {
if (err) {
console.log('\ntelegram发送通知消息失败!!\n')
console.log(err);
} else {
data = JSON.parse(data);
if (data.ok) {
console.log('\nTelegram发送通知消息完成。\n')
} else if (data.error_code === 400) {
console.log('\n请主动给bot发送一条消息并检查接收用户ID是否正确。\n')
} else if (data.error_code === 401){
console.log('\nTelegram bot token 填写错误。\n')
}
}
} catch (e) {
$.logErr(e, resp);
} finally {
resolve(data);
}
})
} else {
console.log('\n您未提供telegram机器人推送所需的TG_BOT_TOKEN和TG_USER_ID,取消telegram推送消息通知\n');
resolve()
}
})
}
module.exports = {
sendNotify,
BarkNotify,
SCKEY,
BARK_PUSH
}
// prettier-ignore
function Env(t,e){class s{constructor(t){this.env=t}send(t,e="GET"){t="string"==typeof t?{url:t}:t;let s=this.get;return"POST"===e&&(s=this.post),new Promise((e,i)=>{s.call(this,t,(t,s,r)=>{t?i(t):e(s)})})}get(t){return this.send.call(this.env,t)}post(t){return this.send.call(this.env,t,"POST")}}return new class{constructor(t,e){this.name=t,this.http=new s(this),this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.isNeedRewrite=!1,this.logSeparator="\n",this.startTime=(new Date).getTime(),Object.assign(this,e),this.log("",`\ud83d\udd14${this.name}, \u5f00\u59cb!`)}isNode(){return"undefined"!=typeof module&&!!module.exports}isQuanX(){return"undefined"!=typeof $task}isSurge(){return"undefined"!=typeof $httpClient&&"undefined"==typeof $loon}isLoon(){return"undefined"!=typeof $loon}toObj(t,e=null){try{return JSON.parse(t)}catch{return e}}toStr(t,e=null){try{return JSON.stringify(t)}catch{return e}}getjson(t,e){let s=e;const i=this.getdata(t);if(i)try{s=JSON.parse(this.getdata(t))}catch{}return s}setjson(t,e){try{return this.setdata(JSON.stringify(t),e)}catch{return!1}}getScript(t){return new Promise(e=>{this.get({url:t},(t,s,i)=>e(i))})}runScript(t,e){return new Promise(s=>{let i=this.getdata("@chavy_boxjs_userCfgs.httpapi");i=i?i.replace(/\n/g,"").trim():i;let r=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");r=r?1*r:20,r=e&&e.timeout?e.timeout:r;const[o,h]=i.split("@"),a={url:`http://${h}/v1/scripting/evaluate`,body:{script_text:t,mock_type:"cron",timeout:r},headers:{"X-Key":o,Accept:"*/*"}};this.post(a,(t,e,i)=>s(i))}).catch(t=>this.logErr(t))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e);if(!s&&!i)return{};{const i=s?t:e;try{return JSON.parse(this.fs.readFileSync(i))}catch(t){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const t=this.path.resolve(this.dataFile),e=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(t),i=!s&&this.fs.existsSync(e),r=JSON.stringify(this.data);s?this.fs.writeFileSync(t,r):i?this.fs.writeFileSync(e,r):this.fs.writeFileSync(t,r)}}lodash_get(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let r=t;for(const t of i)if(r=Object(r)[t],void 0===r)return s;return r}lodash_set(t,e,s){return Object(t)!==t?t:(Array.isArray(e)||(e=e.toString().match(/[^.[\]]+/g)||[]),e.slice(0,-1).reduce((t,s,i)=>Object(t[s])===t[s]?t[s]:t[s]=Math.abs(e[i+1])>>0==+e[i+1]?[]:{},t)[e[e.length-1]]=s,t)}getdata(t){let e=this.getval(t);if(/^@/.test(t)){const[,s,i]=/^@(.*?)\.(.*?)$/.exec(t),r=s?this.getval(s):"";if(r)try{const t=JSON.parse(r);e=t?this.lodash_get(t,i,""):e}catch(t){e=""}}return e}setdata(t,e){let s=!1;if(/^@/.test(e)){const[,i,r]=/^@(.*?)\.(.*?)$/.exec(e),o=this.getval(i),h=i?"null"===o?null:o||"{}":"{}";try{const e=JSON.parse(h);this.lodash_set(e,r,t),s=this.setval(JSON.stringify(e),i)}catch(e){const o={};this.lodash_set(o,r,t),s=this.setval(JSON.stringify(o),i)}}else s=this.setval(t,e);return s}getval(t){return this.isSurge()||this.isLoon()?$persistentStore.read(t):this.isQuanX()?$prefs.valueForKey(t):this.isNode()?(this.data=this.loaddata(),this.data[t]):this.data&&this.data[t]||null}setval(t,e){return this.isSurge()||this.isLoon()?$persistentStore.write(t,e):this.isQuanX()?$prefs.setValueForKey(t,e):this.isNode()?(this.data=this.loaddata(),this.data[e]=t,this.writedata(),!0):this.data&&this.data[e]||null}initGotEnv(t){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,t&&(t.headers=t.headers?t.headers:{},void 0===t.headers.Cookie&&void 0===t.cookieJar&&(t.cookieJar=this.ckjar))}get(t,e=(()=>{})){t.headers&&(delete t.headers["Content-Type"],delete t.headers["Content-Length"]),this.isSurge()||this.isLoon()?(this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.get(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)})):this.isQuanX()?(this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t))):this.isNode()&&(this.initGotEnv(t),this.got(t).on("redirect",(t,e)=>{try{if(t.headers["set-cookie"]){const s=t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();this.ckjar.setCookieSync(s,null),e.cookieJar=this.ckjar}}catch(t){this.logErr(t)}}).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)}))}post(t,e=(()=>{})){if(t.body&&t.headers&&!t.headers["Content-Type"]&&(t.headers["Content-Type"]="application/x-www-form-urlencoded"),t.headers&&delete t.headers["Content-Length"],this.isSurge()||this.isLoon())this.isSurge()&&this.isNeedRewrite&&(t.headers=t.headers||{},Object.assign(t.headers,{"X-Surge-Skip-Scripting":!1})),$httpClient.post(t,(t,s,i)=>{!t&&s&&(s.body=i,s.statusCode=s.status),e(t,s,i)});else if(this.isQuanX())t.method="POST",this.isNeedRewrite&&(t.opts=t.opts||{},Object.assign(t.opts,{hints:!1})),$task.fetch(t).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>e(t));else if(this.isNode()){this.initGotEnv(t);const{url:s,...i}=t;this.got.post(s,i).then(t=>{const{statusCode:s,statusCode:i,headers:r,body:o}=t;e(null,{status:s,statusCode:i,headers:r,body:o},o)},t=>{const{message:s,response:i}=t;e(s,i,i&&i.body)})}}time(t){let e={"M+":(new Date).getMonth()+1,"d+":(new Date).getDate(),"H+":(new Date).getHours(),"m+":(new Date).getMinutes(),"s+":(new Date).getSeconds(),"q+":Math.floor(((new Date).getMonth()+3)/3),S:(new Date).getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,((new Date).getFullYear()+"").substr(4-RegExp.$1.length)));for(let s in e)new RegExp("("+s+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?e[s]:("00"+e[s]).substr((""+e[s]).length)));return t}msg(e=t,s="",i="",r){const o=t=>{if(!t)return t;if("string"==typeof t)return this.isLoon()?t:this.isQuanX()?{"open-url":t}:this.isSurge()?{url:t}:void 0;if("object"==typeof t){if(this.isLoon()){let e=t.openUrl||t.url||t["open-url"],s=t.mediaUrl||t["media-url"];return{openUrl:e,mediaUrl:s}}if(this.isQuanX()){let e=t["open-url"]||t.url||t.openUrl,s=t["media-url"]||t.mediaUrl;return{"open-url":e,"media-url":s}}if(this.isSurge()){let e=t.url||t.openUrl||t["open-url"];return{url:e}}}};this.isMute||(this.isSurge()||this.isLoon()?$notification.post(e,s,i,o(r)):this.isQuanX()&&$notify(e,s,i,o(r)));let h=["","==============\ud83d\udce3\u7cfb\u7edf\u901a\u77e5\ud83d\udce3=============="];h.push(e),s&&h.push(s),i&&h.push(i),console.log(h.join("\n")),this.logs=this.logs.concat(h)}log(...t){t.length>0&&(this.logs=[...this.logs,...t]),console.log(t.join(this.logSeparator))}logErr(t,e){const s=!this.isSurge()&&!this.isQuanX()&&!this.isLoon();s?this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t.stack):this.log("",`\u2757\ufe0f${this.name}, \u9519\u8bef!`,t)}wait(t){return new Promise(e=>setTimeout(e,t))}done(t={}){const e=(new Date).getTime(),s=(e-this.startTime)/1e3;this.log("",`\ud83d\udd14${this.name}, \u7ed3\u675f! \ud83d\udd5b ${s} \u79d2`),this.log(),(this.isSurge()||this.isQuanX()||this.isLoon())&&$done(t)}}(t,e)}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment