shawenguan преди 2 години
родител
ревизия
42a0089646
променени са 3 файла, в които са добавени 704 реда и са изтрити 682 реда
  1. 11 11
      Scripts/gandart/gandartHelper.js
  2. 661 660
      Scripts/util/Env.js
  3. 32 11
      Scripts/util/ToolKit.js

Файловите разлики са ограничени, защото са твърде много
+ 11 - 11
Scripts/gandart/gandartHelper.js


+ 661 - 660
Scripts/util/Env.js

@@ -5,707 +5,708 @@
  */
 
 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)
-        })
-      })
-    }
+    class Http {
+        constructor(env) {
+            this.env = env
+        }
 
-    get(opts) {
-      return this.send.call(this.env, opts)
-    }
+        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)
+                })
+            })
 
-    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.encoding = 'utf-8'
-      this.startTime = new Date().getTime()
-      Object.assign(this, opts)
-      this.log('', `🔔${this.name}, 开始!`)
-    }
+        }
 
-    getEnv() {
-      if ('undefined' !== typeof $environment && $environment['surge-version'])
-        return 'Surge'
-      if ('undefined' !== typeof $environment && $environment['stash-version'])
-        return 'Stash'
-      if ('undefined' !== typeof module && !!module.exports) return 'Node.js'
-      if ('undefined' !== typeof $task) return 'Quantumult X'
-      if ('undefined' !== typeof $loon) return 'Loon'
-      if ('undefined' !== typeof $rocket) return 'Shadowrocket'
-    }
+        get(opts) {
+            return this.send.call(this.env, opts)
+        }
 
-    isNode() {
-      return 'Node.js' === this.getEnv()
+        post(opts) {
+            return this.send.call(this.env, opts, 'POST')
+        }
     }
 
-    isQuanX() {
-      return 'Quantumult X' === this.getEnv()
-    }
+    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.encoding = 'utf-8'
+            this.startTime = new Date().getTime()
+            Object.assign(this, opts)
+            this.log('', `🔔${this.name}, 开始!`)
+        }
 
-    isSurge() {
-      return 'Surge' === this.getEnv()
-    }
+        getEnv() {
+            if ('undefined' !== typeof $environment && $environment['surge-version'])
+                return 'Surge'
+            if ('undefined' !== typeof $environment && $environment['stash-version'])
+                return 'Stash'
+            if ('undefined' !== typeof module && !!module.exports) return 'Node.js'
+            if ('undefined' !== typeof $task) return 'Quantumult X'
+            if ('undefined' !== typeof $loon) return 'Loon'
+            if ('undefined' !== typeof $rocket) return 'Shadowrocket'
+        }
 
-    isLoon() {
-      return 'Loon' === this.getEnv()
-    }
+        isNode() {
+            return 'Node.js' === this.getEnv()
+        }
 
-    isShadowrocket() {
-      return 'Shadowrocket' === this.getEnv()
-    }
+        isQuanX() {
+            return 'Quantumult X' === this.getEnv()
+        }
 
-    isStash() {
-      return 'Stash' === this.getEnv()
-    }
+        isSurge() {
+            return 'Surge' === this.getEnv()
+        }
 
-    toObj(str, defaultValue = null) {
-      try {
-        return JSON.parse(str)
-      } catch {
-        return defaultValue
-      }
-    }
+        isLoon() {
+            return 'Loon' === this.getEnv()
+        }
 
-    toStr(obj, defaultValue = null) {
-      try {
-        return JSON.stringify(obj)
-      } catch {
-        return defaultValue
-      }
-    }
+        isShadowrocket() {
+            return 'Shadowrocket' === this.getEnv()
+        }
 
-    getjson(key, defaultValue) {
-      let json = defaultValue
-      const val = this.getdata(key)
-      if (val) {
-        try {
-          json = JSON.parse(this.getdata(key))
-        } catch { }
-      }
-      return json
-    }
+        isStash() {
+            return 'Stash' === this.getEnv()
+        }
 
-    setjson(val, key) {
-      try {
-        return this.setdata(JSON.stringify(val), key)
-      } catch {
-        return false
-      }
-    }
+        toObj(str, defaultValue = null) {
+            try {
+                return JSON.parse(str)
+            } catch {
+                return defaultValue
+            }
+        }
 
-    getScript(url) {
-      return new Promise((resolve) => {
-        this.get({ url }, (err, resp, body) => resolve(body))
-      })
-    }
+        toStr(obj, defaultValue = null) {
+            try {
+                return JSON.stringify(obj)
+            } catch {
+                return defaultValue
+            }
+        }
 
-    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': '*/*' },
-          timeout: httpapi_timeout
-        }
-        this.post(opts, (err, resp, body) => resolve(body))
-      }).catch((e) => this.logErr(e))
-    }
+        getjson(key, defaultValue) {
+            let json = defaultValue
+            const val = this.getdata(key)
+            if (val) {
+                try {
+                    json = JSON.parse(this.getdata(key))
+                } catch { }
+            }
+            return json
+        }
 
-    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 {}
-    }
+        setjson(val, key) {
+            try {
+                return this.setdata(JSON.stringify(val), key)
+            } catch {
+                return false
+            }
+        }
 
-    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)
-        }
-      }
-    }
+        getScript(url) {
+            return new Promise((resolve) => {
+                this.get({ url }, (err, resp, body) => resolve(body))
+            })
+        }
 
-    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
+        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': '*/*' },
+                    timeout: httpapi_timeout
+                }
+                this.post(opts, (err, resp, body) => resolve(body))
+            }).catch((e) => this.logErr(e))
         }
-      }
-      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
-    }
+        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 {}
+        }
 
-    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
-    }
+        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)
+                }
+            }
+        }
 
-    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
-    }
+        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
+        }
 
-    getval(key) {
-      switch (this.getEnv()) {
-        case 'Surge':
-        case 'Loon':
-        case 'Stash':
-        case 'Shadowrocket':
-          return $persistentStore.read(key)
-        case 'Quantumult X':
-          return $prefs.valueForKey(key)
-        case 'Node.js':
-          this.data = this.loaddata()
-          return this.data[key]
-        default:
-          return (this.data && this.data[key]) || null
-      }
-    }
+        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
+        }
 
-    setval(val, key) {
-      switch (this.getEnv()) {
-        case 'Surge':
-        case 'Loon':
-        case 'Stash':
-        case 'Shadowrocket':
-          return $persistentStore.write(val, key)
-        case 'Quantumult X':
-          return $prefs.setValueForKey(val, key)
-        case 'Node.js':
-          this.data = this.loaddata()
-          this.data[key] = val
-          this.writedata()
-          return true
-        default:
-          return (this.data && this.data[key]) || null
-      }
-    }
+        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
+        }
 
-    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
+        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
         }
-      }
-    }
 
-    get(request, callback = () => { }) {
-      if (request.headers) {
-        delete request.headers['Content-Type']
-        delete request.headers['Content-Length']
-
-        // HTTP/2 全是小写
-        delete request.headers['content-type']
-        delete request.headers['content-length']
-      }
-      switch (this.getEnv()) {
-        case 'Surge':
-        case 'Loon':
-        case 'Stash':
-        case 'Shadowrocket':
-        default:
-          if (this.isSurge() && this.isNeedRewrite) {
-            request.headers = request.headers || {}
-            Object.assign(request.headers, { 'X-Surge-Skip-Scripting': false })
-          }
-          $httpClient.get(request, (err, resp, body) => {
-            if (!err && resp) {
-              resp.body = body
-              resp.statusCode = resp.status ? resp.status : resp.statusCode
-              resp.status = resp.statusCode
+        getval(key) {
+            switch (this.getEnv()) {
+                case 'Surge':
+                case 'Loon':
+                case 'Stash':
+                case 'Shadowrocket':
+                    return $persistentStore.read(key)
+                case 'Quantumult X':
+                    return $prefs.valueForKey(key)
+                case 'Node.js':
+                    this.data = this.loaddata()
+                    return this.data[key]
+                default:
+                    return (this.data && this.data[key]) || null
             }
-            callback(err, resp, body)
-          })
-          break
-        case 'Quantumult X':
-          if (this.isNeedRewrite) {
-            request.opts = request.opts || {}
-            Object.assign(request.opts, { hints: false })
-          }
-          $task.fetch(request).then(
-            (resp) => {
-              const {
-                statusCode: status,
-                statusCode,
-                headers,
-                body,
-                bodyBytes
-              } = resp
-              callback(
-                null,
-                { status, statusCode, headers, body, bodyBytes },
-                body,
-                bodyBytes
-              )
-            },
-            (err) => callback((err && err.error) || 'UndefinedError')
-          )
-          break
-        case 'Node.js':
-          let iconv = require('iconv-lite')
-          this.initGotEnv(request)
-          this.got(request)
-            .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,
-                  rawBody
-                } = resp
-                const body = iconv.decode(rawBody, this.encoding)
-                callback(
-                  null,
-                  { status, statusCode, headers, rawBody, body },
-                  body
-                )
-              },
-              (err) => {
-                const { message: error, response: resp } = err
-                callback(
-                  error,
-                  resp,
-                  resp && iconv.decode(resp.rawBody, this.encoding)
-                )
-              }
-            )
-          break
-      }
-    }
+        }
 
-    post(request, callback = () => { }) {
-      const method = request.method
-        ? request.method.toLocaleLowerCase()
-        : 'post'
-
-      // 如果指定了请求体, 但没指定 `Content-Type`、`content-type`, 则自动生成。
-      if (
-        request.body &&
-        request.headers &&
-        !request.headers['Content-Type'] &&
-        !request.headers['content-type']
-      ) {
-        // HTTP/1、HTTP/2 都支持小写 headers
-        request.headers['content-type'] = 'application/x-www-form-urlencoded'
-      }
-      // 为避免指定错误 `content-length` 这里删除该属性,由工具端 (HttpClient) 负责重新计算并赋值
-      if (request.headers) {
-        delete request.headers['Content-Length']
-        delete request.headers['content-length']
-      }
-      switch (this.getEnv()) {
-        case 'Surge':
-        case 'Loon':
-        case 'Stash':
-        case 'Shadowrocket':
-        default:
-          if (this.isSurge() && this.isNeedRewrite) {
-            request.headers = request.headers || {}
-            Object.assign(request.headers, { 'X-Surge-Skip-Scripting': false })
-          }
-          $httpClient[method](request, (err, resp, body) => {
-            if (!err && resp) {
-              resp.body = body
-              resp.statusCode = resp.status ? resp.status : resp.statusCode
-              resp.status = resp.statusCode
+        setval(val, key) {
+            switch (this.getEnv()) {
+                case 'Surge':
+                case 'Loon':
+                case 'Stash':
+                case 'Shadowrocket':
+                    return $persistentStore.write(val, key)
+                case 'Quantumult X':
+                    return $prefs.setValueForKey(val, key)
+                case 'Node.js':
+                    this.data = this.loaddata()
+                    this.data[key] = val
+                    this.writedata()
+                    return true
+                default:
+                    return (this.data && this.data[key]) || null
             }
-            callback(err, resp, body)
-          })
-          break
-        case 'Quantumult X':
-          request.method = method
-          if (this.isNeedRewrite) {
-            request.opts = request.opts || {}
-            Object.assign(request.opts, { hints: false })
-          }
-          $task.fetch(request).then(
-            (resp) => {
-              const {
-                statusCode: status,
-                statusCode,
-                headers,
-                body,
-                bodyBytes
-              } = resp
-              callback(
-                null,
-                { status, statusCode, headers, body, bodyBytes },
-                body,
-                bodyBytes
-              )
-            },
-            (err) => callback((err && err.error) || 'UndefinedError')
-          )
-          break
-        case 'Node.js':
-          let iconv = require('iconv-lite')
-          this.initGotEnv(request)
-          const { url, ..._request } = request
-          this.got[method](url, _request).then(
-            (resp) => {
-              const { statusCode: status, statusCode, headers, rawBody } = resp
-              const body = iconv.decode(rawBody, this.encoding)
-              callback(
-                null,
-                { status, statusCode, headers, rawBody, body },
-                body
-              )
-            },
-            (err) => {
-              const { message: error, response: resp } = err
-              callback(
-                error,
-                resp,
-                resp && iconv.decode(resp.rawBody, this.encoding)
-              )
+        }
+
+        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
+                }
             }
-          )
-          break
-      }
-    }
-    /**
-     *
-     * 示例:$.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 {string} fmt 格式化参数
-     * @param {number} 可选: 根据指定时间戳返回格式化日期
-     *
-     */
-    time(fmt, ts = null) {
-      const date = ts ? new Date(ts) : new Date()
-      let o = {
-        'M+': date.getMonth() + 1,
-        'd+': date.getDate(),
-        'H+': date.getHours(),
-        'm+': date.getMinutes(),
-        's+': date.getSeconds(),
-        'q+': Math.floor((date.getMonth() + 3) / 3),
-        'S': date.getMilliseconds()
-      }
-      if (/(y+)/.test(fmt))
-        fmt = fmt.replace(
-          RegExp.$1,
-          (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
-    }
+        }
 
-    /**
-     *
-     * @param {Object} options
-     * @returns {String} 将 Object 对象 转换成 queryStr: key=val&name=senku
-     */
-    queryStr(options) {
-      let queryString = ''
-
-      for (const key in options) {
-        let value = options[key]
-        if (value != null && value !== '') {
-          if (typeof value === 'object') {
-            value = JSON.stringify(value)
-          }
-          queryString += `${key}=${value}&`
-        }
-      }
-      queryString = queryString.substring(0, queryString.length - 1)
-
-      return queryString
-    }
+        get(request, callback = () => { }) {
+            if (request.headers) {
+                delete request.headers['Content-Type']
+                delete request.headers['Content-Length']
 
-    /**
-     * 系统通知
-     *
-     * > 通知参数: 同时支持 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) => {
-        switch (typeof rawopts) {
-          case undefined:
-            return rawopts
-          case 'string':
+                // HTTP/2 全是小写
+                delete request.headers['content-type']
+                delete request.headers['content-length']
+            }
             switch (this.getEnv()) {
-              case 'Surge':
-              case 'Stash':
-              default:
-                return { url: rawopts }
-              case 'Loon':
-              case 'Shadowrocket':
-                return rawopts
-              case 'Quantumult X':
-                return { 'open-url': rawopts }
-              case 'Node.js':
-                return undefined
+                case 'Surge':
+                case 'Loon':
+                case 'Stash':
+                case 'Shadowrocket':
+                default:
+                    if (this.isSurge() && this.isNeedRewrite) {
+                        request.headers = request.headers || {}
+                        Object.assign(request.headers, { 'X-Surge-Skip-Scripting': false })
+                    }
+                    $httpClient.get(request, (err, resp, body) => {
+                        if (!err && resp) {
+                            resp.body = body
+                            resp.statusCode = resp.status ? resp.status : resp.statusCode
+                            resp.status = resp.statusCode
+                        }
+                        callback(err, resp, body)
+                    })
+                    break
+                case 'Quantumult X':
+                    if (this.isNeedRewrite) {
+                        request.opts = request.opts || {}
+                        Object.assign(request.opts, { hints: false })
+                    }
+                    $task.fetch(request).then(
+                        (resp) => {
+                            const {
+                                statusCode: status,
+                                statusCode,
+                                headers,
+                                body,
+                                bodyBytes
+                            } = resp
+                            callback(
+                                null,
+                                { status, statusCode, headers, body, bodyBytes },
+                                body,
+                                bodyBytes
+                            )
+                        },
+                        (err) => callback((err && err.error) || 'UndefinedError')
+                    )
+                    break
+                case 'Node.js':
+                    let iconv = require('iconv-lite')
+                    this.initGotEnv(request)
+                    this.got(request)
+                        .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,
+                                    rawBody
+                                } = resp
+                                const body = iconv.decode(rawBody, this.encoding)
+                                callback(
+                                    null,
+                                    { status, statusCode, headers, rawBody, body },
+                                    body
+                                )
+                            },
+                            (err) => {
+                                const { message: error, response: resp } = err
+                                callback(
+                                    error,
+                                    resp,
+                                    resp && iconv.decode(resp.rawBody, this.encoding)
+                                )
+                            }
+                        )
+                    break
+            }
+        }
+
+        post(request, callback = () => { }) {
+            const method = request.method
+                ? request.method.toLocaleLowerCase()
+                : 'post'
+
+            // 如果指定了请求体, 但没指定 `Content-Type`、`content-type`, 则自动生成。
+            if (
+                request.body &&
+                request.headers &&
+                !request.headers['Content-Type'] &&
+                !request.headers['content-type']
+            ) {
+                // HTTP/1、HTTP/2 都支持小写 headers
+                request.headers['content-type'] = 'application/x-www-form-urlencoded'
+            }
+            // 为避免指定错误 `content-length` 这里删除该属性,由工具端 (HttpClient) 负责重新计算并赋值
+            if (request.headers) {
+                delete request.headers['Content-Length']
+                delete request.headers['content-length']
             }
-          case 'object':
             switch (this.getEnv()) {
-              case 'Surge':
-              case 'Stash':
-              case 'Shadowrocket':
-              default: {
-                let openUrl =
-                  rawopts.url || rawopts.openUrl || rawopts['open-url']
-                return { url: openUrl }
-              }
-              case 'Loon': {
-                let openUrl =
-                  rawopts.openUrl || rawopts.url || rawopts['open-url']
-                let mediaUrl = rawopts.mediaUrl || rawopts['media-url']
-                return { openUrl, mediaUrl }
-              }
-              case 'Quantumult X': {
-                let openUrl =
-                  rawopts['open-url'] || rawopts.url || rawopts.openUrl
-                let mediaUrl = rawopts['media-url'] || rawopts.mediaUrl
-                let updatePasteboard =
-                  rawopts['update-pasteboard'] || rawopts.updatePasteboard
-                return {
-                  'open-url': openUrl,
-                  'media-url': mediaUrl,
-                  'update-pasteboard': updatePasteboard
+                case 'Surge':
+                case 'Loon':
+                case 'Stash':
+                case 'Shadowrocket':
+                default:
+                    if (this.isSurge() && this.isNeedRewrite) {
+                        request.headers = request.headers || {}
+                        Object.assign(request.headers, { 'X-Surge-Skip-Scripting': false })
+                    }
+                    $httpClient[method](request, (err, resp, body) => {
+                        if (!err && resp) {
+                            resp.body = body
+                            resp.statusCode = resp.status ? resp.status : resp.statusCode
+                            resp.status = resp.statusCode
+                        }
+                        callback(err, resp, body)
+                    })
+                    break
+                case 'Quantumult X':
+                    request.method = method
+                    if (this.isNeedRewrite) {
+                        request.opts = request.opts || {}
+                        Object.assign(request.opts, { hints: false })
+                    }
+                    $task.fetch(request).then(
+                        (resp) => {
+                            const {
+                                statusCode: status,
+                                statusCode,
+                                headers,
+                                body,
+                                bodyBytes
+                            } = resp
+                            callback(
+                                null,
+                                { status, statusCode, headers, body, bodyBytes },
+                                body,
+                                bodyBytes
+                            )
+                        },
+                        (err) => callback((err && err.error) || 'UndefinedError')
+                    )
+                    break
+                case 'Node.js':
+                    let iconv = require('iconv-lite')
+                    this.initGotEnv(request)
+                    const { url, ..._request } = request
+                    this.got[method](url, _request).then(
+                        (resp) => {
+                            const { statusCode: status, statusCode, headers, rawBody } = resp
+                            const body = iconv.decode(rawBody, this.encoding)
+                            callback(
+                                null,
+                                { status, statusCode, headers, rawBody, body },
+                                body
+                            )
+                        },
+                        (err) => {
+                            const { message: error, response: resp } = err
+                            callback(
+                                error,
+                                resp,
+                                resp && iconv.decode(resp.rawBody, this.encoding)
+                            )
+                        }
+                    )
+                    break
+            }
+        }
+        /**
+         *
+         * 示例:$.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 {string} fmt 格式化参数
+         * @param {number} 可选: 根据指定时间戳返回格式化日期
+         *
+         */
+        time(fmt, ts = null) {
+            const date = ts ? new Date(ts) : new Date()
+            let o = {
+                'M+': date.getMonth() + 1,
+                'd+': date.getDate(),
+                'H+': date.getHours(),
+                'm+': date.getMinutes(),
+                's+': date.getSeconds(),
+                'q+': Math.floor((date.getMonth() + 3) / 3),
+                'S': date.getMilliseconds()
+            }
+            if (/(y+)/.test(fmt))
+                fmt = fmt.replace(
+                    RegExp.$1,
+                    (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
+        }
+
+        /**
+         *
+         * @param {Object} options
+         * @returns {String} 将 Object 对象 转换成 queryStr: key=val&name=senku
+         */
+        queryStr(options) {
+            let queryString = ''
+
+            for (const key in options) {
+                let value = options[key]
+                if (value != null && value !== '') {
+                    if (typeof value === 'object') {
+                        value = JSON.stringify(value)
+                    }
+                    queryString += `${key}=${value}&`
                 }
-              }
-              case 'Node.js':
-                return undefined
             }
-          default:
-            return undefined
-        }
-      }
-      if (!this.isMute) {
-        switch (this.getEnv()) {
-          case 'Surge':
-          case 'Loon':
-          case 'Stash':
-          case 'Shadowrocket':
-          default:
-            $notification.post(title, subt, desc, toEnvOpts(opts))
-            break
-          case 'Quantumult X':
-            $notify(title, subt, desc, toEnvOpts(opts))
-            break
-          case 'Node.js':
-            break
-        }
-      }
-      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)
-      }
-    }
+            queryString = queryString.substring(0, queryString.length - 1)
 
-    log(...logs) {
-      if (logs.length > 0) {
-        this.logs = [...this.logs, ...logs]
-      }
-      console.log(logs.join(this.logSeparator))
-    }
+            return queryString
+        }
 
-    logErr(err, msg) {
-      switch (this.getEnv()) {
-        case 'Surge':
-        case 'Loon':
-        case 'Stash':
-        case 'Shadowrocket':
-        case 'Quantumult X':
-        default:
-          this.log('', `❗️${this.name}, 错误!`, err)
-          break
-        case 'Node.js':
-          this.log('', `❗️${this.name}, 错误!`, err.stack)
-          break
-      }
-    }
+        /**
+         * 系统通知
+         *
+         * > 通知参数: 同时支持 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) => {
+                switch (typeof rawopts) {
+                    case undefined:
+                        return rawopts
+                    case 'string':
+                        switch (this.getEnv()) {
+                            case 'Surge':
+                            case 'Stash':
+                            default:
+                                return { url: rawopts }
+                            case 'Loon':
+                            case 'Shadowrocket':
+                                return rawopts
+                            case 'Quantumult X':
+                                return { 'open-url': rawopts }
+                            case 'Node.js':
+                                return undefined
+                        }
+                    case 'object':
+                        switch (this.getEnv()) {
+                            case 'Surge':
+                            case 'Stash':
+                            case 'Shadowrocket':
+                            default: {
+                                let openUrl =
+                                    rawopts.url || rawopts.openUrl || rawopts['open-url']
+                                return { url: openUrl }
+                            }
+                            case 'Loon': {
+                                let openUrl =
+                                    rawopts.openUrl || rawopts.url || rawopts['open-url']
+                                let mediaUrl = rawopts.mediaUrl || rawopts['media-url']
+                                return { openUrl, mediaUrl }
+                            }
+                            case 'Quantumult X': {
+                                let openUrl =
+                                    rawopts['open-url'] || rawopts.url || rawopts.openUrl
+                                let mediaUrl = rawopts['media-url'] || rawopts.mediaUrl
+                                let updatePasteboard =
+                                    rawopts['update-pasteboard'] || rawopts.updatePasteboard
+                                return {
+                                    'open-url': openUrl,
+                                    'media-url': mediaUrl,
+                                    'update-pasteboard': updatePasteboard
+                                }
+                            }
+                            case 'Node.js':
+                                return undefined
+                        }
+                    default:
+                        return undefined
+                }
+            }
+            if (!this.isMute) {
+                switch (this.getEnv()) {
+                    case 'Surge':
+                    case 'Loon':
+                    case 'Stash':
+                    case 'Shadowrocket':
+                    default:
+                        $notification.post(title, subt, desc, toEnvOpts(opts))
+                        break
+                    case 'Quantumult X':
+                        $notify(title, subt, desc, toEnvOpts(opts))
+                        break
+                    case 'Node.js':
+                        break
+                }
+            }
+            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)
+            }
+        }
 
-    wait(time) {
-      return new Promise((resolve) => setTimeout(resolve, time))
-    }
+        log(...logs) {
+            if (logs.length > 0) {
+                this.logs = [...this.logs, ...logs]
+            }
+            console.log(logs.join(this.logSeparator))
+        }
 
-    done(val = {}) {
-      const endTime = new Date().getTime()
-      const costTime = (endTime - this.startTime) / 1000
-      this.log('', `🔔${this.name}, 结束! 🕛 ${costTime} 秒`)
-      this.log()
-      switch (this.getEnv()) {
-        case 'Surge':
-        case 'Loon':
-        case 'Stash':
-        case 'Shadowrocket':
-        case 'Quantumult X':
-        default:
-          $done(val)
-          break
-        case 'Node.js':
-          process.exit(1)
-          break
-      }
-    }
-  })(name, opts)
+        logErr(err, msg) {
+            switch (this.getEnv()) {
+                case 'Surge':
+                case 'Loon':
+                case 'Stash':
+                case 'Shadowrocket':
+                case 'Quantumult X':
+                default:
+                    this.log('', `❗️${this.name}, 错误!`, err)
+                    break
+                case 'Node.js':
+                    this.log('', `❗️${this.name}, 错误!`, err.stack)
+                    break
+            }
+        }
+
+        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()
+            switch (this.getEnv()) {
+                case 'Surge':
+                case 'Loon':
+                case 'Stash':
+                case 'Shadowrocket':
+                case 'Quantumult X':
+                default:
+                    $done(val)
+                    break
+                case 'Node.js':
+                    process.exit(1)
+                    break
+            }
+        }
+    })(name, opts)
 }

+ 32 - 11
Scripts/util/ToolKit.js

@@ -93,8 +93,8 @@ function ToolKit(scriptName, scriptId, options) {
                     this.node.fs.writeFileSync(
                         fpath,
                         JSON.stringify({}), {
-                            flag: "wx"
-                        },
+                        flag: "wx"
+                    },
                         (err) => console.log(err)
                     );
                 }
@@ -106,8 +106,8 @@ function ToolKit(scriptName, scriptId, options) {
                     this.node.fs.writeFileSync(
                         fpath,
                         JSON.stringify({}), {
-                            flag: "wx"
-                        },
+                        flag: "wx"
+                    },
                         (err) => console.log(err)
                     );
                     this.cache = {};
@@ -133,15 +133,15 @@ function ToolKit(scriptName, scriptId, options) {
                 this.node.fs.writeFileSync(
                     `${pKey}.json`,
                     data, {
-                        flag: "w"
-                    },
+                    flag: "w"
+                },
                     (err) => console.log(err)
                 );
                 this.node.fs.writeFileSync(
                     "root.json",
                     JSON.stringify(this.root, null, 2), {
-                        flag: "w"
-                    },
+                    flag: "w"
+                },
                     (err) => console.log(err)
                 );
             }
@@ -223,7 +223,7 @@ function ToolKit(scriptName, scriptId, options) {
         }
 
         /**
-         * http://boxjs.com/ => 
+         * http://boxjs.com/ =>
          * http://boxjs.com/api/getdata => /api/getdata
          */
         getUrlPath(url) {
@@ -539,7 +539,7 @@ function ToolKit(scriptName, scriptId, options) {
             if (this.isEnableLog) {
                 console.log(`${this.logSeparator}${this.name}执行异常:`)
                 console.log(message)
-                console.log('\n'+`${message.message}`)
+                console.log('\n' + `${message.message}`)
             }
         }
 
@@ -565,7 +565,7 @@ function ToolKit(scriptName, scriptId, options) {
                             message = message.replace(key, this.tgEscapeCharMapping[key])
                         }
                         this.get({
-                            url: encodeURI(`${this.tgNotifyUrl}📌${this.name}`+'\n'+`${message}`)
+                            url: encodeURI(`${this.tgNotifyUrl}📌${this.name}` + '\n' + `${message}`)
                         }, (_error, _statusCode, _body) => {
                             this.log(`Tg通知完毕`)
                         })
@@ -943,5 +943,26 @@ function ToolKit(scriptName, scriptId, options) {
                     format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length))
             return format
         }
+
+        /**
+         *
+         * @param {Object} options
+         * @returns {String} 将 Object 对象 转换成 queryStr: key=val&name=senku
+         */
+        queryStr(options) {
+            let queryString = ''
+
+            for (const key in options) {
+                let value = options[key]
+                if (value != null && value !== '') {
+                    if (typeof value === 'object') {
+                        value = JSON.stringify(value)
+                    }
+                    queryString += `${key}=${value}&`
+                }
+            }
+            queryString = queryString.substring(0, queryString.length - 1)
+            return queryString
+        }
     })(scriptName, scriptId, options)
 }

Някои файлове не бяха показани, защото твърде много файлове са промени