[
  {
    "path": "README.md",
    "content": "# Surge\nRemove weibo ads\n```\n[Script]\nhttp-response ^https?://m?api\\.weibo\\.c(n|om)/2/(statuses/(unread|extend|positives/get|(friends|video)(/|_)timeline)|stories/(video_stream|home_list)|(groups|fangle)/timeline|profile/statuses|comments/build_comments|photo/recommend_list|service/picfeed|searchall|cardlist|page|\\!/photos/pic_recommend_status) requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/wb_ad.js\nhttp-response ^https?://(sdk|wb)app\\.uve\\.weibo\\.com(/interface/sdk/sdkad.php|/wbapplua/wbpullad.lua) requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/wb_launch.js\n[MITM]\nhostname = api.weibo.cn, mapi.weibo.com, *.uve.weibo.com\n```\n\nDisplay netflix ratings（IMDb、douaban）\n```\n[Script]\nhttp-request ^https?://ios\\.prod\\.ftl\\.netflix\\.com/iosui/user/.+path=%5B%22videos%22%2C%\\d+%22%2C%22summary%22%5D script-path=https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating.js\nhttp-response ^https?://ios\\.prod\\.ftl\\.netflix\\.com/iosui/user/.+path=%5B%22videos%22%2C%\\d+%22%2C%22summary%22%5D requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating.js\n[MITM]\nhostname = ios.prod.ftl.netflix.com\n```\n\nDisplay jd historical price\n```\n# 使用不生效或失效的检查一下配置有没有这两条复写，如果有删除试试\n# ^https?:\\/\\/api\\.m\\.jd.com\\/client\\.action\\?functionId=start - reject\n# ^https?:\\/\\/api\\.m\\.jd.com\\/client\\.action\\?functionId=(start|queryMaterialAdverts) - reject\n[Script]\nhttp-response ^https?://api\\.m\\.jd\\.com/client\\.action\\?functionId=(wareBusiness|serverConfig) requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/jd_price.js\n[MITM]\nhostname = api.m.jd.com\n```\n\nDisplay taobao historical price（提供两种方式，根据需求二选一）\n```\n# 使用脚本删除对应 IP，不生效或失效的需要卸载 tb 重装，注意不开脚本进 tb 会失效\n[Script]\nhttp-response ^https?://amdc\\.m\\.taobao\\.com/amdc/mobileDispatch requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/tb_price.js\nhttp-response ^https://trade-acs\\.m\\.taobao\\.com/gw/mtop\\.taobao\\.detail\\.getdetail requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/tb_price.js\n[MITM]\nhostname = trade-acs.m.taobao.com,amdc.m.taobao.com\n```\n\n```\n# 使用规则屏蔽指定 IP 段，有可能误伤其他功能或者应用，可以自己抓包缩小 IP 范围，随时生效\n[Rule]\nIP-CIDR, 203.119.144.0/23, REJECT, no-resolve\nIP-CIDR, 203.119.175.0/24, REJECT, no-resolve\nIP-CIDR, 106.11.162.0/24, REJECT, no-resolve\nIP-CIDR, 47.102.83.0/24, REJECT, no-resolve\n[Script]\nhttp-response ^https://trade-acs\\.m\\.taobao\\.com/gw/mtop\\.taobao\\.detail\\.getdetail requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/tb_price.js\n[MITM]\nhostname = trade-acs.m.taobao.com,amdc.m.taobao.com\n```\n\nDaily work check-in reminder\n```\n[Script]\ncron \"0 9,18 * * 1-5\" script-path=https://raw.githubusercontent.com/yichahucha/surge/master/check_in.js\n```\n\n# Quan-X\n\nRemove weibo ads\n```\n[rewrite_local]\n^https?://m?api\\.weibo\\.c(n|om)/2/(statuses/(unread|extend|positives/get|(friends|video)(/|_)timeline)|stories/(video_stream|home_list)|(groups|fangle)/timeline|profile/statuses|comments/build_comments|photo/recommend_list|service/picfeed|searchall|cardlist|page|\\!/photos/pic_recommend_status) url script-response-body wb_ad.js\n^https?://(sdk|wb)app\\.uve\\.weibo\\.com(/interface/sdk/sdkad.php|/wbapplua/wbpullad.lua) url script-response-body wb_launch.js\n[mitm]\nhostname = api.weibo.cn, mapi.weibo.com, *.uve.weibo.com\n```\n\nDisplay netflix ratings（IMDb、douaban）\n```\n[rewrite_local]\n^https?://ios\\.prod\\.ftl\\.netflix\\.com/iosui/user/.+path=%5B%22videos%22%2C%\\d+%22%2C%22summary%22%5D url script-request-header nf_rating.js\n^https?://ios\\.prod\\.ftl\\.netflix\\.com/iosui/user/.+path=%5B%22videos%22%2C%\\d+%22%2C%22summary%22%5D url script-response-body nf_rating.js\n[mitm]\nhostname = ios.prod.ftl.netflix.com\n```\n\nDisplay jd historical price\n```\n[rewrite_local]\n^https?://api\\.m\\.jd\\.com/client\\.action\\?functionId=(wareBusiness|serverConfig) url script-response-body jd_price.js\n[mitm]\nhostname = api.m.jd.com\n```\n\nDisplay taobao historical price（提供两种方式，根据需求二选一）\n```\n# 使用脚本删除对应 IP，不生效或失效的需要卸载 tb 重装，注意不开脚本进 tb 会失效\n[rewrite_local]\n^https?://amdc\\.m\\.taobao\\.com/amdc/mobileDispatch url script-response-body tb_price.js\n^https://trade-acs\\.m\\.taobao\\.com/gw/mtop\\.taobao\\.detail\\.getdetail url script-response-body tb_price.js\n[mitm]\nhostname = trade-acs.m.taobao.com,amdc.m.taobao.com\n```\n\n```\n# 使用规则屏蔽指定 IP 段，有可能误伤其他功能或者应用，可以自己抓包缩小 IP 范围，随时生效\n[filter_local]\nip-cidr, 203.119.144.0/23, reject\nip-cidr, 203.119.175.0/24, reject\nip-cidr, 106.11.162.0/24, reject\nip-cidr, 47.102.83.0/24, reject\n[rewrite_local]\n^https://trade-acs\\.m\\.taobao\\.com/gw/mtop\\.taobao\\.detail\\.getdetail url script-response-body tb_price.js\n[mitm]\nhostname = trade-acs.m.taobao.com,amdc.m.taobao.com\n```\n\nDaily work check-in reminder\n```\n[task_local]\n0 9,18 * * 1-5 check_in.js\n```\n\n[Issue Group](http://t.me/scriptgroup)\n"
  },
  {
    "path": "check_in.js",
    "content": "/*\nREADME：https://github.com/yichahucha/surge/tree/master\n每日打卡提醒（corn \"0 9,18 * * 1-5\" 周一到周五，早九晚六）+ 每日壹句（有道词典）+ 跳转钉钉打卡页面（下拉通知点击链接）\n*/\n\nconst $tool = new Tool()\n$tool.get('https://dict.youdao.com/infoline/style/cardList?mode=publish&client=mobile&style=daily&size=2', function (error, response, data) {\n    let obj = JSON.parse(data);\n    let date = new Date();\n    let isAM = date.getHours() < 12 ? true : false;\n    let title = 'Clock' + (isAM ? ' in' : ' out') + (isAM ? ' ☀️' : ' 🌙');\n    let subtitle = '';\n    let content = 'dingtalk://dingtalkclient/page/link?url=https://attend.dingtalk.com/attend/index.html';\n    if (!error) {\n        if (obj && obj.length > 1) {\n            let yi = obj[1];\n            content = yi.title + '\\n' + yi.summary + '\\n\\n' + content;\n        }\n    }\n    $tool.notify(title, subtitle, content);\n    $done();\n})\n\nfunction Tool() {\n    _node = (() => {\n        if (typeof require == \"function\") {\n            const request = require('request')\n            return ({ request })\n        } else {\n            return (null)\n        }\n    })()\n    _isSurge = typeof $httpClient != \"undefined\"\n    _isQuanX = typeof $task != \"undefined\"\n    this.isSurge = _isSurge\n    this.isQuanX = _isQuanX\n    this.isResponse = typeof $response != \"undefined\"\n    this.notify = (title, subtitle, message) => {\n        if (_isQuanX) $notify(title, subtitle, message)\n        if (_isSurge) $notification.post(title, subtitle, message)\n        if (_node) console.log(JSON.stringify({ title, subtitle, message }));\n    }\n    this.write = (value, key) => {\n        if (_isQuanX) return $prefs.setValueForKey(value, key)\n        if (_isSurge) return $persistentStore.write(value, key)\n    }\n    this.read = (key) => {\n        if (_isQuanX) return $prefs.valueForKey(key)\n        if (_isSurge) return $persistentStore.read(key)\n    }\n    this.get = (options, callback) => {\n        if (_isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"GET\"\n            $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null))\n        }\n        if (_isSurge) $httpClient.get(options, (error, response, body) => { callback(error, _status(response), body) })\n        if (_node) _node.request(options, (error, response, body) => { callback(error, _status(response), body) })\n    }\n    this.post = (options, callback) => {\n        if (_isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"POST\"\n            $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null))\n        }\n        if (_isSurge) $httpClient.post(options, (error, response, body) => { callback(error, _status(response), body) })\n        if (_node) _node.request.post(options, (error, response, body) => { callback(error, _status(response), body) })\n    }\n    _status = (response) => {\n        if (response) {\n            if (response.status) {\n                response[\"statusCode\"] = response.status\n            } else if (response.statusCode) {\n                response[\"status\"] = response.statusCode\n            }\n        }\n        return response\n    }\n}"
  },
  {
    "path": "jd_price.js",
    "content": "/*\nREADME：https://github.com/yichahucha/surge/tree/master\n */\n\nconst path1 = \"serverConfig\";\nconst path2 = \"wareBusiness\";\nconst consolelog = false;\nconst url = $request.url;\nconst body = $response.body;\nconst $tool = tool();\n\nif (url.indexOf(path1) != -1) {\n    let obj = JSON.parse(body);\n    delete obj.serverConfig.httpdns;\n    $done({ body: JSON.stringify(obj) });\n}\n\nif (url.indexOf(path2) != -1) {\n    let obj = JSON.parse(body);\n    const floors = obj.floors;\n    const commodity_info = floors[floors.length - 1];\n    const shareUrl = commodity_info.data.property.shareUrl;\n    request_history_price(shareUrl, function (data) {\n        if (data) {\n            const lowerword = adword_obj();\n            lowerword.data.ad.textColor = \"#fe0000\";\n            let bestIndex = 0;\n            for (let index = 0; index < floors.length; index++) {\n                const element = floors[index];\n                if (element.mId == lowerword.mId) {\n                    bestIndex = index + 1;\n                    break;\n                } else {\n                    if (element.sortId > lowerword.sortId) {\n                        bestIndex = index;\n                        break;\n                    }\n                }\n            }\n            if (data.ok == 1 && data.single) {\n                const lower = lowerMsgs(data.single)\n                const detail = priceSummary(data)\n                const tip = data.PriceRemark.Tip + \"（仅供参考）\"\n                lowerword.data.ad.adword = `${lower} ${tip}\\n${detail}`;\n                floors.insert(bestIndex, lowerword);\n            }\n            if (data.ok == 0 && data.msg.length > 0) {\n                lowerword.data.ad.adword = \"⚠️ \" + data.msg;\n                floors.insert(bestIndex, lowerword);\n            }\n            $done({ body: JSON.stringify(obj) });\n        } else {\n            $done({ body });\n        }\n    })\n}\n\nfunction lowerMsgs(data) {\n    const lower = data.lowerPriceyh\n    const lowerDate = dateFormat(data.lowerDateyh)\n    const lowerMsg = \"〽️历史最低到手价：¥\" + String(lower) + ` (${lowerDate}) `\n    return lowerMsg\n}\n\nfunction priceSummary(data) {\n    let summary = \"\"\n    let listPriceDetail = data.PriceRemark.ListPriceDetail\n    listPriceDetail.pop()\n    let list = listPriceDetail.concat(historySummary(data.single))\n    list.forEach((item, index) => {\n        if (index == 2) {\n            item.Name = \"双十一价格\"\n        } else if (index == 3) {\n            item.Name = \"六一八价格\"\n        } else if (index == 4) {\n            item.Name = \"三十天最低\"\n        }\n        summary += `\\n${item.Name}${getSpace(8)}${item.Price}${getSpace(8)}${item.Date}${getSpace(8)}${item.Difference}`\n    })\n    return summary\n}\n\nfunction historySummary(single) {\n    const rexMatch = /\\[.*?\\]/g;\n    const rexExec = /\\[(.*),(.*),\"(.*)\"\\]/;\n    let currentPrice, lowest60, lowest180, lowest360\n    let list = single.jiagequshiyh.match(rexMatch);\n    list = list.reverse().slice(0, 360);\n    list.forEach((item, index) => {\n        if (item.length > 0) {\n            const result = rexExec.exec(item);\n            const dateUTC = new Date(eval(result[1]));\n            const date = dateUTC.format(\"yyyy-MM-dd\");\n            let price = parseFloat(result[2]);\n            if (index == 0) {\n                currentPrice = price\n                lowest60 = { Name: \"六十天最低\", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price }\n                lowest180 = { Name: \"一百八最低\", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price }\n                lowest360 = { Name: \"三百六最低\", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price }\n            }\n            if (index < 60 && price <= lowest60.price) {\n                lowest60.price = price\n                lowest60.Price = `¥${String(price)}`\n                lowest60.Date = date\n                lowest60.Difference = difference(currentPrice, price)\n            }\n            if (index < 180 && price <= lowest180.price) {\n                lowest180.price = price\n                lowest180.Price = `¥${String(price)}`\n                lowest180.Date = date\n                lowest180.Difference = difference(currentPrice, price)\n            }\n            if (index < 360 && price <= lowest360.price) {\n                lowest360.price = price\n                lowest360.Price = `¥${String(price)}`\n                lowest360.Date = date\n                lowest360.Difference = difference(currentPrice, price)\n            }\n        }\n    });\n    return [lowest60, lowest180, lowest360];\n}\n\nfunction difference(currentPrice, price) {\n    let difference = strip(currentPrice - price)\n    if (difference == 0) {\n        return \"-\"\n    } else {\n        return `${difference > 0 ? \"↑\" : \"↓\"}${String(difference)}`\n    }\n}\n\nfunction strip(num, precision = 12) {\n    return +parseFloat(num.toPrecision(precision));\n}\n\nfunction request_history_price(share_url, callback) {\n    const options = {\n        url: \"https://apapia-history.manmanbuy.com/ChromeWidgetServices/WidgetServices.ashx\",\n        headers: {\n            \"Content-Type\": \"application/x-www-form-urlencoded;charset=utf-8\",\n            \"User-Agent\": \"Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 - mmbWebBrowse - ios\"\n        },\n        body: \"methodName=getHistoryTrend&p_url=\" + encodeURIComponent(share_url)\n    }\n    $tool.post(options, function (error, response, data) {\n        if (!error) {\n            callback(JSON.parse(data));\n            if (consolelog) console.log(\"Data:\\n\" + data);\n        } else {\n            callback(null, null);\n            if (consolelog) console.log(\"Error:\\n\" + error);\n        }\n    })\n}\n\nfunction dateFormat(cellval) {\n    const date = new Date(parseInt(cellval.replace(\"/Date(\", \"\").replace(\")/\", \"\"), 10));\n    const month = date.getMonth() + 1 < 10 ? \"0\" + (date.getMonth() + 1) : date.getMonth() + 1;\n    const currentDate = date.getDate() < 10 ? \"0\" + date.getDate() : date.getDate();\n    return date.getFullYear() + \"-\" + month + \"-\" + currentDate;\n}\n\nfunction getSpace(length) {\n    let blank = \"\";\n    for (let index = 0; index < length; index++) {\n        blank += \" \";\n    }\n    return blank;\n}\n\nfunction adword_obj() {\n    return {\n        \"bId\": \"eCustom_flo_199\",\n        \"cf\": {\n            \"bgc\": \"#ffffff\",\n            \"spl\": \"empty\"\n        },\n        \"data\": {\n            \"ad\": {\n                \"adword\": \"\",\n                \"textColor\": \"#8C8C8C\",\n                \"color\": \"#f23030\",\n                \"newALContent\": true,\n                \"hasFold\": true,\n                \"class\": \"com.jd.app.server.warecoresoa.domain.AdWordInfo.AdWordInfo\",\n                \"adLinkContent\": \"\",\n                \"adLink\": \"\"\n            }\n        },\n        \"mId\": \"bpAdword\",\n        \"refId\": \"eAdword_0000000028\",\n        \"sortId\": 13\n    }\n}\n\nfunction tool() {\n    const isSurge = typeof $httpClient != \"undefined\"\n    const isQuanX = typeof $task != \"undefined\"\n    const isResponse = typeof $response != \"undefined\"\n    const node = (() => {\n        if (typeof require == \"function\") {\n            const request = require('request')\n            return ({ request })\n        } else {\n            return (null)\n        }\n    })()\n    const notify = (title, subtitle, message) => {\n        if (isQuanX) $notify(title, subtitle, message)\n        if (isSurge) $notification.post(title, subtitle, message)\n        if (node) console.log(JSON.stringify({ title, subtitle, message }));\n    }\n    const write = (value, key) => {\n        if (isQuanX) return $prefs.setValueForKey(value, key)\n        if (isSurge) return $persistentStore.write(value, key)\n    }\n    const read = (key) => {\n        if (isQuanX) return $prefs.valueForKey(key)\n        if (isSurge) return $persistentStore.read(key)\n    }\n    const adapterStatus = (response) => {\n        if (response) {\n            if (response.status) {\n                response[\"statusCode\"] = response.status\n            } else if (response.statusCode) {\n                response[\"status\"] = response.statusCode\n            }\n        }\n        return response\n    }\n    const get = (options, callback) => {\n        if (isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"GET\"\n            $task.fetch(options).then(response => {\n                callback(null, adapterStatus(response), response.body)\n            }, reason => callback(reason.error, null, null))\n        }\n        if (isSurge) $httpClient.get(options, (error, response, body) => {\n            callback(error, adapterStatus(response), body)\n        })\n        if (node) {\n            node.request(options, (error, response, body) => {\n                callback(error, adapterStatus(response), body)\n            })\n        }\n    }\n    const post = (options, callback) => {\n        if (isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"POST\"\n            $task.fetch(options).then(response => {\n                callback(null, adapterStatus(response), response.body)\n            }, reason => callback(reason.error, null, null))\n        }\n        if (isSurge) {\n            $httpClient.post(options, (error, response, body) => {\n                callback(error, adapterStatus(response), body)\n            })\n        }\n        if (node) {\n            node.request.post(options, (error, response, body) => {\n                callback(error, adapterStatus(response), body)\n            })\n        }\n    }\n    return { isQuanX, isSurge, isResponse, notify, write, read, get, post }\n}\n\nArray.prototype.insert = function (index, item) {\n    this.splice(index, 0, item);\n};\n\nDate.prototype.format = function (fmt) {\n    var o = {\n        \"y+\": this.getFullYear(),\n        \"M+\": this.getMonth() + 1,\n        \"d+\": this.getDate(),\n        \"h+\": this.getHours(),\n        \"m+\": this.getMinutes(),\n        \"s+\": this.getSeconds(),\n        \"q+\": Math.floor((this.getMonth() + 3) / 3),\n        \"S+\": this.getMilliseconds()\n    };\n    for (var k in o) {\n        if (new RegExp(\"(\" + k + \")\").test(fmt)) {\n            if (k == \"y+\") {\n                fmt = fmt.replace(RegExp.$1, (\"\" + o[k]).substr(4 - RegExp.$1.length));\n            }\n            else if (k == \"S+\") {\n                var lens = RegExp.$1.length;\n                lens = lens == 1 ? 3 : lens;\n                fmt = fmt.replace(RegExp.$1, (\"00\" + o[k]).substr((\"\" + o[k]).length - 1, lens));\n            }\n            else {\n                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : ((\"00\" + o[k]).substr((\"\" + o[k]).length)));\n            }\n        }\n    }\n    return fmt;\n}\n"
  },
  {
    "path": "jd_price_lite.js",
    "content": "/*\nREADME：https://github.com/yichahucha/surge/tree/master\n */\n\nconst path1 = \"serverConfig\";\nconst path2 = \"wareBusiness\";\nconst consolelog = false;\nconst url = $request.url;\nconst body = $response.body;\nconst $tool = tool();\n\nif (url.indexOf(path1) != -1) {\n    let obj = JSON.parse(body);\n    delete obj.serverConfig.httpdns;\n    $done({ body: JSON.stringify(obj) });\n}\n\nif (url.indexOf(path2) != -1) {\n    $done({ body });\n    let obj = JSON.parse(body);\n    const floors = obj.floors;\n    const commodity_info = floors[floors.length - 1];\n    const shareUrl = commodity_info.data.property.shareUrl;\n    request_history_price(shareUrl, function (data) {\n        if (data) {\n            if (data.ok == 1 && data.single) {\n                const lower = lowerMsgs(data.single)\n                const detail = priceSummary(data)\n                const tip = data.PriceRemark.Tip + \"（仅供参考）\"\n                $tool.notify(\"\", \"\", `${lower} ${tip}\\n${detail}\\n\\n👉查看详情：http://tool.manmanbuy.com/historyLowest.aspx?url=${encodeURI(shareUrl)}`)\n            }\n            if (data.ok == 0 && data.msg.length > 0) {\n                $tool.notify(\"\", \"\", `⚠️ ${data.msg}`)\n            }\n        }\n    })\n}\n\nfunction lowerMsgs(data) {\n    const lower = data.lowerPriceyh\n    const lowerDate = dateFormat(data.lowerDateyh)\n    const lowerMsg = \"〽️历史最低到手价：¥\" + String(lower) + ` (${lowerDate}) `\n    return lowerMsg\n}\n\nfunction priceSummary(data) {\n    let summary = \"\"\n    let listPriceDetail = data.PriceRemark.ListPriceDetail\n    listPriceDetail.pop()\n    let list = listPriceDetail.concat(historySummary(data.single))\n    list.forEach((item, index) => {\n        if (index == 2) {\n            item.Name = \"双十一价格\"\n        } else if (index == 3) {\n            item.Name = \"六一八价格\"\n        } else if (index == 4) {\n            item.Name = \"三十天最低\"\n        }\n        summary += `\\n${item.Name}   ${item.Price}   ${item.Date}   ${item.Difference}`\n    })\n    return summary\n}\n\nfunction historySummary(single) {\n    const rexMatch = /\\[.*?\\]/g;\n    const rexExec = /\\[(.*),(.*),\"(.*)\"\\]/;\n    let currentPrice, lowest60, lowest180, lowest360\n    let list = single.jiagequshiyh.match(rexMatch);\n    list = list.reverse().slice(0, 360);\n    list.forEach((item, index) => {\n        if (item.length > 0) {\n            const result = rexExec.exec(item);\n            const dateUTC = new Date(eval(result[1]));\n            const date = dateUTC.format(\"yyyy-MM-dd\");\n            let price = parseFloat(result[2]);\n            if (index == 0) {\n                currentPrice = price\n                lowest60 = { Name: \"六十天最低\", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price }\n                lowest180 = { Name: \"一百八最低\", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price }\n                lowest360 = { Name: \"三百六最低\", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price }\n            }\n            if (index < 60 && price <= lowest60.price) {\n                lowest60.price = price\n                lowest60.Price = `¥${String(price)}`\n                lowest60.Date = date\n                lowest60.Difference = difference(currentPrice, price)\n            }\n            if (index < 180 && price <= lowest180.price) {\n                lowest180.price = price\n                lowest180.Price = `¥${String(price)}`\n                lowest180.Date = date\n                lowest180.Difference = difference(currentPrice, price)\n            }\n            if (index < 360 && price <= lowest360.price) {\n                lowest360.price = price\n                lowest360.Price = `¥${String(price)}`\n                lowest360.Date = date\n                lowest360.Difference = difference(currentPrice, price)\n            }\n        }\n    });\n    return [lowest60, lowest180, lowest360];\n}\n\nfunction difference(currentPrice, price) {\n    let difference = strip(currentPrice - price)\n    if (difference == 0) {\n        return \"-\"\n    } else {\n        return `${difference > 0 ? \"↑\" : \"↓\"}${String(difference)}`\n    }\n}\n\nfunction strip(num, precision = 12) {\n    return +parseFloat(num.toPrecision(precision));\n}\n\nfunction request_history_price(share_url, callback) {\n    const options = {\n        url: \"https://apapia-history.manmanbuy.com/ChromeWidgetServices/WidgetServices.ashx\",\n        headers: {\n            \"Content-Type\": \"application/x-www-form-urlencoded;charset=utf-8\",\n            \"User-Agent\": \"Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 - mmbWebBrowse - ios\"\n        },\n        body: \"methodName=getHistoryTrend&p_url=\" + encodeURIComponent(share_url)\n    }\n    $tool.post(options, function (error, response, data) {\n        if (!error) {\n            callback(JSON.parse(data));\n            if (consolelog) console.log(\"Data:\\n\" + data);\n        } else {\n            callback(null, null);\n            if (consolelog) console.log(\"Error:\\n\" + error);\n        }\n    })\n}\n\nfunction dateFormat(cellval) {\n    const date = new Date(parseInt(cellval.replace(\"/Date(\", \"\").replace(\")/\", \"\"), 10));\n    const month = date.getMonth() + 1 < 10 ? \"0\" + (date.getMonth() + 1) : date.getMonth() + 1;\n    const currentDate = date.getDate() < 10 ? \"0\" + date.getDate() : date.getDate();\n    return date.getFullYear() + \"-\" + month + \"-\" + currentDate;\n}\n\nfunction tool() {\n    const isSurge = typeof $httpClient != \"undefined\"\n    const isQuanX = typeof $task != \"undefined\"\n    const node = (() => {\n        if (typeof require == \"function\") {\n            const request = require('request')\n            return ({ request })\n        } else {\n            return (null)\n        }\n    })()\n    const notify = (title, subtitle, message) => {\n        if (isQuanX) $notify(title, subtitle, message)\n        if (isSurge) $notification.post(title, subtitle, message)\n        if (node) console.log(JSON.stringify({ title, subtitle, message }));\n    }\n    const setCache = (value, key) => {\n        if (isQuanX) return $prefs.setValueForKey(value, key)\n        if (isSurge) return $persistentStore.write(value, key)\n    }\n    const getCache = (key) => {\n        if (isQuanX) return $prefs.valueForKey(key)\n        if (isSurge) return $persistentStore.read(key)\n    }\n    const adapterStatus = (response) => {\n        if (response.status) {\n            response[\"statusCode\"] = response.status\n        } else if (response.statusCode) {\n            response[\"status\"] = response.statusCode\n        }\n        return response\n    }\n    const get = (options, callback) => {\n        if (isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"GET\"\n            $task.fetch(options).then(response => {\n                callback(null, adapterStatus(response), response.body)\n            }, reason => callback(reason.error, null, null))\n        }\n        if (isSurge) $httpClient.get(options, (error, response, body) => {\n            callback(error, adapterStatus(response), body)\n        })\n        if (node) {\n            node.request(options, (error, response, body) => {\n                callback(error, adapterStatus(response), body)\n            })\n        }\n    }\n    const post = (options, callback) => {\n        if (isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"POST\"\n            $task.fetch(options).then(response => {\n                callback(null, adapterStatus(response), response.body)\n            }, reason => callback(reason.error, null, null))\n        }\n        if (isSurge) {\n            $httpClient.post(options, (error, response, body) => {\n                callback(error, adapterStatus(response), body)\n            })\n        }\n        if (node) {\n            node.request.post(options, (error, response, body) => {\n                callback(error, adapterStatus(response), body)\n            })\n        }\n    }\n    return { isQuanX, isSurge, notify, setCache, getCache, get, post }\n}\n\nArray.prototype.insert = function (index, item) {\n    this.splice(index, 0, item);\n};\n\nDate.prototype.format = function (fmt) {\n    var o = {\n        \"y+\": this.getFullYear(),\n        \"M+\": this.getMonth() + 1,\n        \"d+\": this.getDate(),\n        \"h+\": this.getHours(),\n        \"m+\": this.getMinutes(),\n        \"s+\": this.getSeconds(),\n        \"q+\": Math.floor((this.getMonth() + 3) / 3),\n        \"S+\": this.getMilliseconds()\n    };\n    for (var k in o) {\n        if (new RegExp(\"(\" + k + \")\").test(fmt)) {\n            if (k == \"y+\") {\n                fmt = fmt.replace(RegExp.$1, (\"\" + o[k]).substr(4 - RegExp.$1.length));\n            }\n            else if (k == \"S+\") {\n                var lens = RegExp.$1.length;\n                lens = lens == 1 ? 3 : lens;\n                fmt = fmt.replace(RegExp.$1, (\"00\" + o[k]).substr((\"\" + o[k]).length - 1, lens));\n            }\n            else {\n                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : ((\"00\" + o[k]).substr((\"\" + o[k]).length)));\n            }\n        }\n    }\n    return fmt;\n}\n"
  },
  {
    "path": "nf_rating.js",
    "content": "/*\nREADME：https://github.com/yichahucha/surge/tree/master\n */\n\nconst $tool = new Tool()\nconst consoleLog = false;\nconst imdbApikeyCacheKey = \"IMDbApikey\";\nconst netflixTitleCacheKey = \"NetflixTitle\";\n\nif (!$tool.isResponse) {\n    let url = $request.url;\n    const urlDecode = decodeURIComponent(url);\n    const videos = urlDecode.match(/\"videos\",\"(\\d+)\"/);\n    const videoID = videos[1];\n    const map = getTitleMap();\n    const title = map[videoID];\n    const isEnglish = url.match(/languages=en/) ? true : false;\n    if (!title && !isEnglish) {\n        const currentSummary = urlDecode.match(/\\[\"videos\",\"(\\d+)\",\"current\",\"summary\"\\]/);\n        url = url.replace(\"&path=\" + encodeURIComponent(currentSummary[0]), \"\");\n        url = url.replace(/&languages=(.*?)&/, \"&languages=en-US&\");\n    }\n    url += \"&path=\" + encodeURIComponent(`[${videos[0]},\"details\"]`);\n    $done({ url });\n} else {\n    var IMDbApikeys = IMDbApikeys();\n    var IMDbApikey = $tool.read(imdbApikeyCacheKey);\n    if (!IMDbApikey) updateIMDbApikey();\n    let obj = JSON.parse($response.body);\n    if (consoleLog) console.log(\"Netflix Original Body:\\n\" + $response.body);\n    const videoID = obj.paths[0][1];\n    const video = obj.value.videos[videoID];\n    const map = getTitleMap();\n    let title = map[videoID];\n    if (!title) {\n        title = video.summary.title;\n        setTitleMap(videoID, title, map);\n    }\n    let year = null;\n    let type = video.summary.type;\n    if (type == \"movie\") {\n        year = video.details.releaseYear;\n    } else if (type == \"show\") {\n        type = \"series\";\n    }\n    delete video.details;\n    const requestRatings = async () => {\n        const IMDb = await requestIMDbRating(title, year, type);\n        const Douban = await requestDoubanRating(IMDb.id);\n        const IMDbrating = IMDb.msg.rating;\n        const tomatoes = IMDb.msg.tomatoes;\n        const country = IMDb.msg.country;\n        const doubanRating = Douban.rating;\n        const message = `${country}\\n${IMDbrating}\\n${doubanRating}${tomatoes.length > 0 ? \"\\n\" + tomatoes + \"\\n\" : \"\\n\"}`;\n        return message;\n    }\n    let msg = \"\";\n    requestRatings()\n        .then(message => msg = message)\n        .catch(error => msg = error + \"\\n\")\n        .finally(() => {\n            let summary = obj.value.videos[videoID].summary;\n            summary[\"supplementalMessage\"] = `${msg}${summary && summary.supplementalMessage ? \"\\n\" + summary.supplementalMessage : \"\"}`;\n            if (consoleLog) console.log(\"Netflix Modified Body:\\n\" + JSON.stringify(obj));\n            $done({ body: JSON.stringify(obj) });\n        });\n}\n\nfunction getTitleMap() {\n    const map = $tool.read(netflixTitleCacheKey);\n    return map ? JSON.parse(map) : {};\n}\n\nfunction setTitleMap(id, title, map) {\n    map[id] = title;\n    $tool.write(JSON.stringify(map), netflixTitleCacheKey);\n}\n\nfunction requestDoubanRating(imdbId) {\n    return new Promise(function (resolve, reject) {\n        const url = \"https://api.douban.com/v2/movie/imdb/\" + imdbId + \"?apikey=0df993c66c0c636e29ecbb5344252a4a\";\n        if (consoleLog) console.log(\"Netflix Douban Rating URL:\\n\" + url);\n        $tool.get(url, function (error, response, data) {\n            if (!error) {\n                if (consoleLog) console.log(\"Netflix Douban Rating Data:\\n\" + data);\n                if (response.status == 200) {\n                    const obj = JSON.parse(data);\n                    const rating = get_douban_rating_message(obj);\n                    resolve({ rating });\n                } else {\n                    resolve({ rating: \"Douban:  \" + errorTip().noData });\n                }\n            } else {\n                if (consoleLog) console.log(\"Netflix Douban Rating Error:\\n\" + error);\n                resolve({ rating: \"Douban:  \" + errorTip().error });\n            }\n        });\n    });\n}\n\nfunction requestIMDbRating(title, year, type) {\n    return new Promise(function (resolve, reject) {\n        let url = \"https://www.omdbapi.com/?t=\" + encodeURI(title) + \"&apikey=\" + IMDbApikey;\n        if (year) url += \"&y=\" + year;\n        if (type) url += \"&type=\" + type;\n        if (consoleLog) console.log(\"Netflix IMDb Rating URL:\\n\" + url);\n        $tool.get(url, function (error, response, data) {\n            if (!error) {\n                if (consoleLog) console.log(\"Netflix IMDb Rating Data:\\n\" + data);\n                if (response.status == 200) {\n                    const obj = JSON.parse(data);\n                    if (obj.Response != \"False\") {\n                        const id = obj.imdbID;\n                        const msg = get_IMDb_message(obj);\n                        resolve({ id, msg });\n                    } else {\n                        reject(errorTip().noData);\n                    }\n                } else if (response.status == 401) {\n                    if (IMDbApikeys.length > 1) {\n                        updateIMDbApikey();\n                        requestIMDbRating(title, year, type);\n                    } else {\n                        reject(errorTip().noData);\n                    }\n                } else {\n                    reject(errorTip().noData);\n                }\n            } else {\n                if (consoleLog) console.log(\"Netflix IMDb Rating Error:\\n\" + error);\n                reject(errorTip().error);\n            }\n        });\n    });\n}\n\nfunction updateIMDbApikey() {\n    if (IMDbApikey) IMDbApikeys.splice(IMDbApikeys.indexOf(IMDbApikey), 1);\n    const index = Math.floor(Math.random() * IMDbApikeys.length);\n    IMDbApikey = IMDbApikeys[index];\n    $tool.write(IMDbApikey, imdbApikeyCacheKey);\n}\n\nfunction get_IMDb_message(data) {\n    let rating_message = \"IMDb:  ⭐️ N/A\";\n    let tomatoes_message = \"\";\n    let country_message = \"\";\n    let ratings = data.Ratings;\n    if (ratings.length > 0) {\n        const imdb_source = ratings[0][\"Source\"];\n        if (imdb_source == \"Internet Movie Database\") {\n            const imdb_votes = data.imdbVotes;\n            const imdb_rating = ratings[0][\"Value\"];\n            rating_message = \"IMDb:  ⭐️ \" + imdb_rating + \"    \" + \"\" + imdb_votes;\n            if (data.Type == \"movie\") {\n                if (ratings.length > 1) {\n                    const source = ratings[1][\"Source\"];\n                    if (source == \"Rotten Tomatoes\") {\n                        const tomatoes = ratings[1][\"Value\"];\n                        tomatoes_message = \"Tomatoes:  🍅 \" + tomatoes;\n                    }\n                }\n            }\n        }\n    }\n    country_message = get_country_message(data.Country);\n    return { rating: rating_message, tomatoes: tomatoes_message, country: country_message }\n}\n\nfunction get_douban_rating_message(data) {\n    const average = data.rating.average;\n    const numRaters = data.rating.numRaters;\n    const rating_message = `Douban:  ⭐️ ${average.length > 0 ? average + \"/10\" : \"N/A\"}   ${numRaters == 0 ? \"\" : parseFloat(numRaters).toLocaleString()}`;\n    return rating_message;\n}\n\nfunction get_country_message(data) {\n    const country = data;\n    const countrys = country.split(\", \");\n    let emoji_country = \"\";\n    countrys.forEach(item => {\n        emoji_country += countryEmoji(item) + \" \" + item + \", \";\n    });\n    return emoji_country.slice(0, -2);\n}\n\nfunction errorTip() {\n    return { noData: \"⭐️ N/A\", error: \"❌ N/A\" }\n}\n\nfunction IMDbApikeys() {\n    const apikeys = [\n        \"PlzBanMe\", \"4e89234e\",\n        \"f75e0253\", \"d8bb2d6b\",\n        \"ae64ce8d\", \"7218d678\",\n        \"b2650e38\", \"8c4a29ab\",\n        \"9bd135c2\", \"953dbabe\",\n        \"1a66ef12\", \"3e7ea721\",\n        \"457fc4ff\", \"d2131426\",\n        \"9cc1a9b7\", \"e53c2c11\",\n        \"f6dfce0e\", \"b9db622f\",\n        \"e6bde2b9\", \"d324dbab\",\n        \"d7904fa3\", \"aeaf88b9\"];\n    return apikeys;\n}\n\nfunction countryEmoji(name) {\n    const emojiMap = {\n        \"Chequered\": \"🏁\",\n        \"Triangular\": \"🚩\",\n        \"Crossed\": \"🎌\",\n        \"Black\": \"🏴\",\n        \"White\": \"🏳\",\n        \"Rainbow\": \"🏳️‍🌈\",\n        \"Pirate\": \"🏴‍☠️\",\n        \"Ascension Island\": \"🇦🇨\",\n        \"Andorra\": \"🇦🇩\",\n        \"United Arab Emirates\": \"🇦🇪\",\n        \"Afghanistan\": \"🇦🇫\",\n        \"Antigua & Barbuda\": \"🇦🇬\",\n        \"Anguilla\": \"🇦🇮\",\n        \"Albania\": \"🇦🇱\",\n        \"Armenia\": \"🇦🇲\",\n        \"Angola\": \"🇦🇴\",\n        \"Antarctica\": \"🇦🇶\",\n        \"Argentina\": \"🇦🇷\",\n        \"American Samoa\": \"🇦🇸\",\n        \"Austria\": \"🇦🇹\",\n        \"Australia\": \"🇦🇺\",\n        \"Aruba\": \"🇦🇼\",\n        \"Åland Islands\": \"🇦🇽\",\n        \"Azerbaijan\": \"🇦🇿\",\n        \"Bosnia & Herzegovina\": \"🇧🇦\",\n        \"Barbados\": \"🇧🇧\",\n        \"Bangladesh\": \"🇧🇩\",\n        \"Belgium\": \"🇧🇪\",\n        \"Burkina Faso\": \"🇧🇫\",\n        \"Bulgaria\": \"🇧🇬\",\n        \"Bahrain\": \"🇧🇭\",\n        \"Burundi\": \"🇧🇮\",\n        \"Benin\": \"🇧🇯\",\n        \"St. Barthélemy\": \"🇧🇱\",\n        \"Bermuda\": \"🇧🇲\",\n        \"Brunei\": \"🇧🇳\",\n        \"Bolivia\": \"🇧🇴\",\n        \"Caribbean Netherlands\": \"🇧🇶\",\n        \"Brazil\": \"🇧🇷\",\n        \"Bahamas\": \"🇧🇸\",\n        \"Bhutan\": \"🇧🇹\",\n        \"Bouvet Island\": \"🇧🇻\",\n        \"Botswana\": \"🇧🇼\",\n        \"Belarus\": \"🇧🇾\",\n        \"Belize\": \"🇧🇿\",\n        \"Canada\": \"🇨🇦\",\n        \"Cocos (Keeling) Islands\": \"🇨🇨\",\n        \"Congo - Kinshasa\": \"🇨🇩\",\n        \"Congo\": \"🇨🇩\",\n        \"Central African Republic\": \"🇨🇫\",\n        \"Congo - Brazzaville\": \"🇨🇬\",\n        \"Switzerland\": \"🇨🇭\",\n        \"Côte d’Ivoire\": \"🇨🇮\",\n        \"Cook Islands\": \"🇨🇰\",\n        \"Chile\": \"🇨🇱\",\n        \"Cameroon\": \"🇨🇲\",\n        \"China\": \"🇨🇳\",\n        \"Colombia\": \"🇨🇴\",\n        \"Clipperton Island\": \"🇨🇵\",\n        \"Costa Rica\": \"🇨🇷\",\n        \"Cuba\": \"🇨🇺\",\n        \"Cape Verde\": \"🇨🇻\",\n        \"Curaçao\": \"🇨🇼\",\n        \"Christmas Island\": \"🇨🇽\",\n        \"Cyprus\": \"🇨🇾\",\n        \"Czechia\": \"🇨🇿\",\n        \"Czech Republic\": \"🇨🇿\",\n        \"Germany\": \"🇩🇪\",\n        \"Diego Garcia\": \"🇩🇬\",\n        \"Djibouti\": \"🇩🇯\",\n        \"Denmark\": \"🇩🇰\",\n        \"Dominica\": \"🇩🇲\",\n        \"Dominican Republic\": \"🇩🇴\",\n        \"Algeria\": \"🇩🇿\",\n        \"Ceuta & Melilla\": \"🇪🇦\",\n        \"Ecuador\": \"🇪🇨\",\n        \"Estonia\": \"🇪🇪\",\n        \"Egypt\": \"🇪🇬\",\n        \"Western Sahara\": \"🇪🇭\",\n        \"Eritrea\": \"🇪🇷\",\n        \"Spain\": \"🇪🇸\",\n        \"Ethiopia\": \"🇪🇹\",\n        \"European Union\": \"🇪🇺\",\n        \"Finland\": \"🇫🇮\",\n        \"Fiji\": \"🇫🇯\",\n        \"Falkland Islands\": \"🇫🇰\",\n        \"Micronesia\": \"🇫🇲\",\n        \"Faroe Islands\": \"🇫🇴\",\n        \"France\": \"🇫🇷\",\n        \"Gabon\": \"🇬🇦\",\n        \"United Kingdom\": \"🇬🇧\",\n        \"UK\": \"🇬🇧\",\n        \"Grenada\": \"🇬🇩\",\n        \"Georgia\": \"🇬🇪\",\n        \"French Guiana\": \"🇬🇫\",\n        \"Guernsey\": \"🇬🇬\",\n        \"Ghana\": \"🇬🇭\",\n        \"Gibraltar\": \"🇬🇮\",\n        \"Greenland\": \"🇬🇱\",\n        \"Gambia\": \"🇬🇲\",\n        \"Guinea\": \"🇬🇳\",\n        \"Guadeloupe\": \"🇬🇵\",\n        \"Equatorial Guinea\": \"🇬🇶\",\n        \"Greece\": \"🇬🇷\",\n        \"South Georgia & South Sandwich Is lands\": \"🇬🇸\",\n        \"Guatemala\": \"🇬🇹\",\n        \"Guam\": \"🇬🇺\",\n        \"Guinea-Bissau\": \"🇬🇼\",\n        \"Guyana\": \"🇬🇾\",\n        \"Hong Kong SAR China\": \"🇭🇰\",\n        \"Hong Kong\": \"🇭🇰\",\n        \"Heard & McDonald Islands\": \"🇭🇲\",\n        \"Honduras\": \"🇭🇳\",\n        \"Croatia\": \"🇭🇷\",\n        \"Haiti\": \"🇭🇹\",\n        \"Hungary\": \"🇭🇺\",\n        \"Canary Islands\": \"🇮🇨\",\n        \"Indonesia\": \"🇮🇩\",\n        \"Ireland\": \"🇮🇪\",\n        \"Israel\": \"🇮🇱\",\n        \"Isle of Man\": \"🇮🇲\",\n        \"India\": \"🇮🇳\",\n        \"British Indian Ocean Territory\": \"🇮🇴\",\n        \"Iraq\": \"🇮🇶\",\n        \"Iran\": \"🇮🇷\",\n        \"Iceland\": \"🇮🇸\",\n        \"Italy\": \"🇮🇹\",\n        \"Jersey\": \"🇯🇪\",\n        \"Jamaica\": \"🇯🇲\",\n        \"Jordan\": \"🇯🇴\",\n        \"Japan\": \"🇯🇵\",\n        \"Kenya\": \"🇰🇪\",\n        \"Kyrgyzstan\": \"🇰🇬\",\n        \"Cambodia\": \"🇰🇭\",\n        \"Kiribati\": \"🇰🇮\",\n        \"Comoros\": \"🇰🇲\",\n        \"St. Kitts & Nevis\": \"🇰🇳\",\n        \"North Korea\": \"🇰🇵\",\n        \"South Korea\": \"🇰🇷\",\n        \"Kuwait\": \"🇰🇼\",\n        \"Cayman Islands\": \"🇰🇾\",\n        \"Kazakhstan\": \"🇰🇿\",\n        \"Laos\": \"🇱🇦\",\n        \"Lebanon\": \"🇱🇧\",\n        \"St. Lucia\": \"🇱🇨\",\n        \"Liechtenstein\": \"🇱🇮\",\n        \"Sri Lanka\": \"🇱🇰\",\n        \"Liberia\": \"🇱🇷\",\n        \"Lesotho\": \"🇱🇸\",\n        \"Lithuania\": \"🇱🇹\",\n        \"Luxembourg\": \"🇱🇺\",\n        \"Latvia\": \"🇱🇻\",\n        \"Libya\": \"🇱🇾\",\n        \"Morocco\": \"🇲🇦\",\n        \"Monaco\": \"🇲🇨\",\n        \"Moldova\": \"🇲🇩\",\n        \"Montenegro\": \"🇲🇪\",\n        \"St. Martin\": \"🇲🇫\",\n        \"Madagascar\": \"🇲🇬\",\n        \"Marshall Islands\": \"🇲🇭\",\n        \"North Macedonia\": \"🇲🇰\",\n        \"Mali\": \"🇲🇱\",\n        \"Myanmar (Burma)\": \"🇲🇲\",\n        \"Mongolia\": \"🇲🇳\",\n        \"Macau Sar China\": \"🇲🇴\",\n        \"Northern Mariana Islands\": \"🇲🇵\",\n        \"Martinique\": \"🇲🇶\",\n        \"Mauritania\": \"🇲🇷\",\n        \"Montserrat\": \"🇲🇸\",\n        \"Malta\": \"🇲🇹\",\n        \"Mauritius\": \"🇲🇺\",\n        \"Maldives\": \"🇲🇻\",\n        \"Malawi\": \"🇲🇼\",\n        \"Mexico\": \"🇲🇽\",\n        \"Malaysia\": \"🇲🇾\",\n        \"Mozambique\": \"🇲🇿\",\n        \"Namibia\": \"🇳🇦\",\n        \"New Caledonia\": \"🇳🇨\",\n        \"Niger\": \"🇳🇪\",\n        \"Norfolk Island\": \"🇳🇫\",\n        \"Nigeria\": \"🇳🇬\",\n        \"Nicaragua\": \"🇳🇮\",\n        \"Netherlands\": \"🇳🇱\",\n        \"Norway\": \"🇳🇴\",\n        \"Nepal\": \"🇳🇵\",\n        \"Nauru\": \"🇳🇷\",\n        \"Niue\": \"🇳🇺\",\n        \"New Zealand\": \"🇳🇿\",\n        \"Oman\": \"🇴🇲\",\n        \"Panama\": \"🇵🇦\",\n        \"Peru\": \"🇵🇪\",\n        \"French Polynesia\": \"🇵🇫\",\n        \"Papua New Guinea\": \"🇵🇬\",\n        \"Philippines\": \"🇵🇭\",\n        \"Pakistan\": \"🇵🇰\",\n        \"Poland\": \"🇵🇱\",\n        \"St. Pierre & Miquelon\": \"🇵🇲\",\n        \"Pitcairn Islands\": \"🇵🇳\",\n        \"Puerto Rico\": \"🇵🇷\",\n        \"Palestinian Territories\": \"🇵🇸\",\n        \"Portugal\": \"🇵🇹\",\n        \"Palau\": \"🇵🇼\",\n        \"Paraguay\": \"🇵🇾\",\n        \"Qatar\": \"🇶🇦\",\n        \"Réunion\": \"🇷🇪\",\n        \"Romania\": \"🇷🇴\",\n        \"Serbia\": \"🇷🇸\",\n        \"Russia\": \"🇷🇺\",\n        \"Rwanda\": \"🇷🇼\",\n        \"Saudi Arabia\": \"🇸🇦\",\n        \"Solomon Islands\": \"🇸🇧\",\n        \"Seychelles\": \"🇸🇨\",\n        \"Sudan\": \"🇸🇩\",\n        \"Sweden\": \"🇸🇪\",\n        \"Singapore\": \"🇸🇬\",\n        \"St. Helena\": \"🇸🇭\",\n        \"Slovenia\": \"🇸🇮\",\n        \"Svalbard & Jan Mayen\": \"🇸🇯\",\n        \"Slovakia\": \"🇸🇰\",\n        \"Sierra Leone\": \"🇸🇱\",\n        \"San Marino\": \"🇸🇲\",\n        \"Senegal\": \"🇸🇳\",\n        \"Somalia\": \"🇸🇴\",\n        \"Suriname\": \"🇸🇷\",\n        \"South Sudan\": \"🇸🇸\",\n        \"São Tomé & Príncipe\": \"🇸🇹\",\n        \"El Salvador\": \"🇸🇻\",\n        \"Sint Maarten\": \"🇸🇽\",\n        \"Syria\": \"🇸🇾\",\n        \"Swaziland\": \"🇸🇿\",\n        \"Tristan Da Cunha\": \"🇹🇦\",\n        \"Turks & Caicos Islands\": \"🇹🇨\",\n        \"Chad\": \"🇹🇩\",\n        \"French Southern Territories\": \"🇹🇫\",\n        \"Togo\": \"🇹🇬\",\n        \"Thailand\": \"🇹🇭\",\n        \"Tajikistan\": \"🇹🇯\",\n        \"Tokelau\": \"🇹🇰\",\n        \"Timor-Leste\": \"🇹🇱\",\n        \"Turkmenistan\": \"🇹🇲\",\n        \"Tunisia\": \"🇹🇳\",\n        \"Tonga\": \"🇹🇴\",\n        \"Turkey\": \"🇹🇷\",\n        \"Trinidad & Tobago\": \"🇹🇹\",\n        \"Tuvalu\": \"🇹🇻\",\n        \"Taiwan\": \"🇨🇳\",\n        \"Tanzania\": \"🇹🇿\",\n        \"Ukraine\": \"🇺🇦\",\n        \"Uganda\": \"🇺🇬\",\n        \"U.S. Outlying Islands\": \"🇺🇲\",\n        \"United Nations\": \"🇺🇳\",\n        \"United States\": \"🇺🇸\",\n        \"USA\": \"🇺🇸\",\n        \"Uruguay\": \"🇺🇾\",\n        \"Uzbekistan\": \"🇺🇿\",\n        \"Vatican City\": \"🇻🇦\",\n        \"St. Vincent & Grenadines\": \"🇻🇨\",\n        \"Venezuela\": \"🇻🇪\",\n        \"British Virgin Islands\": \"🇻🇬\",\n        \"U.S. Virgin Islands\": \"🇻🇮\",\n        \"Vietnam\": \"🇻🇳\",\n        \"Vanuatu\": \"🇻🇺\",\n        \"Wallis & Futuna\": \"🇼🇫\",\n        \"Samoa\": \"🇼🇸\",\n        \"Kosovo\": \"🇽🇰\",\n        \"Yemen\": \"🇾🇪\",\n        \"Mayotte\": \"🇾🇹\",\n        \"South Africa\": \"🇿🇦\",\n        \"Zambia\": \"🇿🇲\",\n        \"Zimbabwe\": \"🇿🇼\",\n        \"England\": \"🏴󠁧󠁢󠁥󠁮󠁧󠁿\",\n        \"Scotland\": \"🏴󠁧󠁢󠁳󠁣󠁴󠁿\",\n        \"Wales\": \"🏴󠁧󠁢󠁷󠁬󠁳󠁿\",\n    }\n    return emojiMap[name] ? emojiMap[name] : emojiMap[\"Chequered\"];\n}\n\nfunction Tool() {\n    _node = (() => {\n        if (typeof require == \"function\") {\n            const request = require('request')\n            return ({ request })\n        } else {\n            return (null)\n        }\n    })()\n    _isSurge = typeof $httpClient != \"undefined\"\n    _isQuanX = typeof $task != \"undefined\"\n    this.isSurge = _isSurge\n    this.isQuanX = _isQuanX\n    this.isResponse = typeof $response != \"undefined\"\n    this.notify = (title, subtitle, message) => {\n        if (_isQuanX) $notify(title, subtitle, message)\n        if (_isSurge) $notification.post(title, subtitle, message)\n        if (_node) console.log(JSON.stringify({ title, subtitle, message }));\n    }\n    this.write = (value, key) => {\n        if (_isQuanX) return $prefs.setValueForKey(value, key)\n        if (_isSurge) return $persistentStore.write(value, key)\n    }\n    this.read = (key) => {\n        if (_isQuanX) return $prefs.valueForKey(key)\n        if (_isSurge) return $persistentStore.read(key)\n    }\n    this.get = (options, callback) => {\n        if (_isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"GET\"\n            $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null))\n        }\n        if (_isSurge) $httpClient.get(options, (error, response, body) => { callback(error, _status(response), body) })\n        if (_node) _node.request(options, (error, response, body) => { callback(error, _status(response), body) })\n    }\n    this.post = (options, callback) => {\n        if (_isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"POST\"\n            $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null))\n        }\n        if (_isSurge) $httpClient.post(options, (error, response, body) => { callback(error, _status(response), body) })\n        if (_node) _node.request.post(options, (error, response, body) => { callback(error, _status(response), body) })\n    }\n    _status = (response) => {\n        if (response) {\n            if (response.status) {\n                response[\"statusCode\"] = response.status\n            } else if (response.statusCode) {\n                response[\"status\"] = response.statusCode\n            }\n        }\n        return response\n    }\n}"
  },
  {
    "path": "tb_price.js",
    "content": "/*\nREADME：https://github.com/yichahucha/surge/tree/master\n */\n\nconst $tool = new Tool()\nconst $base64 = new Base64()\nconst consoleLog = false\nconst url = $request.url\nconst body = $response.body\nconst path1 = \"/amdc/mobileDispatch\"\nconst path2 = \"/gw/mtop.taobao.detail.getdetail\"\n\nif (url.indexOf(path1) != -1) {\n    let obj = JSON.parse($base64.decode(body))\n    let dns = obj.dns\n    if (dns && dns.length > 0) {\n        let i = dns.length;\n        while (i--) {\n            const element = dns[i];\n            let host = \"trade-acs.m.taobao.com\"\n            if (element.host == host) {\n                element.ips = []\n                if (consoleLog) console.log(JSON.stringify(element))\n            }\n        }\n    }\n    $done({ body: $base64.encode(JSON.stringify(obj)) })\n}\n\nif (url.indexOf(path2) != -1) {\n    const body = $response.body\n    let obj = JSON.parse(body)\n    let apiStack = obj.data.apiStack[0]\n    let value = JSON.parse(apiStack.value)\n    if (value.global) {\n        let tradeConsumerProtection = value.global.data.tradeConsumerProtection\n        if (!tradeConsumerProtection) {\n            value.global.data[\"tradeConsumerProtection\"] = customTradeConsumerProtection()\n        }\n        tradeConsumerProtection = value.global.data.tradeConsumerProtection\n        let service = tradeConsumerProtection.tradeConsumerService.service\n        let nonService = tradeConsumerProtection.tradeConsumerService.nonService\n\n        let item = obj.data.item\n        let shareUrl = `https://item.taobao.com/item.htm?id=${item.itemId}`\n\n        requestPrice(shareUrl, function (data) {\n            if (data) {\n                if (data.ok == 1 && data.single) {\n                    const lower = lowerMsgs(data.single)\n                    const tbitems = priceSummary(data)\n                    const tip = data.PriceRemark.Tip\n                    service.items = service.items.concat(nonService.items)\n                    service.items.unshift(customItem(lower[1], `${lower[0]} ${tip}` + \"（仅供参考）\"))\n                    nonService.title = \"价格详情\"\n                    nonService.items = tbitems\n                }\n                if (data.ok == 0 && data.msg.length > 0) {\n                    service.items.unshift(customItem(\"历史价格\", data.msg))\n                }\n                apiStack.value = JSON.stringify(value)\n                $done({ body: JSON.stringify(obj) })\n            } else {\n                $done({ body })\n            }\n        })\n    } else {\n        $done({ body })\n    }\n}\n\nfunction lowerMsgs(data) {\n    const lower = data.lowerPriceyh\n    const lowerDate = dateFormat(data.lowerDateyh)\n    const lowerMsg = \"最低到手价：¥\" + String(lower) + `（${lowerDate}）`\n    const lowerMsg1 = \"历史最低¥\" + String(lower)\n    return [lowerMsg, lowerMsg1]\n}\n\nfunction priceSummary(data) {\n    let tbitems = []\n    let summary = \"\"\n    let listPriceDetail = data.PriceRemark.ListPriceDetail\n    listPriceDetail.pop()\n    let list = listPriceDetail.concat(historySummary(data.single))\n    list.forEach((item, index) => {\n        if (index == 2) {\n            item.Name = \"双十一价格\"\n        } else if (index == 3) {\n            item.Name = \"六一八价格\"\n        } else if (index == 4) {\n            item.Name = \"三十天最低\"\n        }\n        summary = `${item.Name}${getSpace(10)}${item.Price}${getSpace(10)}${item.Date}`\n        tbitems.push(customItem(summary))\n    })\n    return tbitems\n}\n\nfunction historySummary(single) {\n    const rexMatch = /\\[.*?\\]/g;\n    const rexExec = /\\[(.*),(.*),\"(.*)\"\\]/;\n    let currentPrice, lowest60, lowest180, lowest360\n    let list = single.jiagequshiyh.match(rexMatch);\n    list = list.reverse().slice(0, 360);\n    list.forEach((item, index) => {\n        if (item.length > 0) {\n            const result = rexExec.exec(item);\n            const dateUTC = new Date(eval(result[1]));\n            const date = dateUTC.format(\"yyyy-MM-dd\");\n            let price = parseFloat(result[2]);\n            if (index == 0) {\n                currentPrice = price\n                lowest60 = { Name: \"六十天最低\", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price }\n                lowest180 = { Name: \"一百八最低\", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price }\n                lowest360 = { Name: \"三百六最低\", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price }\n            }\n            if (index < 60 && price <= lowest60.price) {\n                lowest60.price = price\n                lowest60.Price = `¥${String(price)}`\n                lowest60.Date = date\n                lowest60.Difference = difference(currentPrice, price)\n            }\n            if (index < 180 && price <= lowest180.price) {\n                lowest180.price = price\n                lowest180.Price = `¥${String(price)}`\n                lowest180.Date = date\n                lowest180.Difference = difference(currentPrice, price)\n            }\n            if (index < 360 && price <= lowest360.price) {\n                lowest360.price = price\n                lowest360.Price = `¥${String(price)}`\n                lowest360.Date = date\n                lowest360.Difference = difference(currentPrice, price)\n            }\n        }\n    });\n    return [lowest60, lowest180, lowest360];\n}\n\nfunction difference(currentPrice, price) {\n    let difference = strip(currentPrice - price)\n    if (difference == 0) {\n        return \"-\"\n    } else {\n        return `${difference > 0 ? \"↑\" : \"↓\"}${String(difference)}`\n    }\n}\n\nfunction strip(num, precision = 12) {\n    return +parseFloat(num.toPrecision(precision));\n}\n\nfunction requestPrice(share_url, callback) {\n    const options = {\n        url: \"https://apapia-history.manmanbuy.com/ChromeWidgetServices/WidgetServices.ashx\",\n        headers: {\n            \"Content-Type\": \"application/x-www-form-urlencoded;charset=utf-8\",\n            \"User-Agent\": \"Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 - mmbWebBrowse - ios\"\n        },\n        body: \"methodName=getHistoryTrend&p_url=\" + encodeURIComponent(share_url)\n    }\n    $tool.post(options, function (error, response, data) {\n        if (!error) {\n            callback(JSON.parse(data));\n            if (consolelog) console.log(\"Data:\\n\" + data);\n        } else {\n            callback(null, null);\n            if (consolelog) console.log(\"Error:\\n\" + error);\n        }\n    })\n}\n\nfunction dateFormat(cellval) {\n    const date = new Date(parseInt(cellval.replace(\"/Date(\", \"\").replace(\")/\", \"\"), 10));\n    const month = date.getMonth() + 1 < 10 ? \"0\" + (date.getMonth() + 1) : date.getMonth() + 1;\n    const currentDate = date.getDate() < 10 ? \"0\" + date.getDate() : date.getDate();\n    return date.getFullYear() + \"-\" + month + \"-\" + currentDate;\n}\n\nfunction getSpace(length) {\n    let blank = \"\";\n    for (let index = 0; index < length; index++) {\n        blank += \" \";\n    }\n    return blank;\n}\n\nfunction customItem(title, desc) {\n    return {\n        icon: \"https://s2.ax1x.com/2020/02/16/3STeIJ.png\",\n        title: title,\n        desc: desc\n    }\n}\n\nfunction customTradeConsumerProtection() {\n    return {\n        \"tradeConsumerService\": {\n            \"service\": {\n                \"items\": [\n                ],\n                \"icon\": \"\",\n                \"title\": \"基础服务\"\n            },\n            \"nonService\": {\n                \"items\": [\n                ],\n                \"title\": \"其他\"\n            }\n        },\n        \"passValue\": \"all\",\n        \"url\": \"https://h5.m.taobao.com/app/detailsubpage/consumer/index.js\",\n        \"type\": \"0\"\n    }\n}\n\nArray.prototype.insert = function (index, item) {\n    this.splice(index, 0, item);\n};\n\nDate.prototype.format = function (fmt) {\n    var o = {\n        \"y+\": this.getFullYear(),\n        \"M+\": this.getMonth() + 1,\n        \"d+\": this.getDate(),\n        \"h+\": this.getHours(),\n        \"m+\": this.getMinutes(),\n        \"s+\": this.getSeconds(),\n        \"q+\": Math.floor((this.getMonth() + 3) / 3),\n        \"S+\": this.getMilliseconds()\n    };\n    for (var k in o) {\n        if (new RegExp(\"(\" + k + \")\").test(fmt)) {\n            if (k == \"y+\") {\n                fmt = fmt.replace(RegExp.$1, (\"\" + o[k]).substr(4 - RegExp.$1.length));\n            }\n            else if (k == \"S+\") {\n                var lens = RegExp.$1.length;\n                lens = lens == 1 ? 3 : lens;\n                fmt = fmt.replace(RegExp.$1, (\"00\" + o[k]).substr((\"\" + o[k]).length - 1, lens));\n            }\n            else {\n                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : ((\"00\" + o[k]).substr((\"\" + o[k]).length)));\n            }\n        }\n    }\n    return fmt;\n}\n\nfunction Tool() {\n    _node = (() => {\n        if (typeof require == \"function\") {\n            const request = require('request')\n            return ({ request })\n        } else {\n            return (null)\n        }\n    })()\n    _isSurge = typeof $httpClient != \"undefined\"\n    _isQuanX = typeof $task != \"undefined\"\n    this.isSurge = _isSurge\n    this.isQuanX = _isQuanX\n    this.isResponse = typeof $response != \"undefined\"\n    this.notify = (title, subtitle, message) => {\n        if (_isQuanX) $notify(title, subtitle, message)\n        if (_isSurge) $notification.post(title, subtitle, message)\n        if (_node) console.log(JSON.stringify({ title, subtitle, message }));\n    }\n    this.write = (value, key) => {\n        if (_isQuanX) return $prefs.setValueForKey(value, key)\n        if (_isSurge) return $persistentStore.write(value, key)\n    }\n    this.read = (key) => {\n        if (_isQuanX) return $prefs.valueForKey(key)\n        if (_isSurge) return $persistentStore.read(key)\n    }\n    this.get = (options, callback) => {\n        if (_isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"GET\"\n            $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null))\n        }\n        if (_isSurge) $httpClient.get(options, (error, response, body) => { callback(error, _status(response), body) })\n        if (_node) _node.request(options, (error, response, body) => { callback(error, _status(response), body) })\n    }\n    this.post = (options, callback) => {\n        if (_isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"POST\"\n            $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null))\n        }\n        if (_isSurge) $httpClient.post(options, (error, response, body) => { callback(error, _status(response), body) })\n        if (_node) _node.request.post(options, (error, response, body) => { callback(error, _status(response), body) })\n    }\n    _status = (response) => {\n        if (response) {\n            if (response.status) {\n                response[\"statusCode\"] = response.status\n            } else if (response.statusCode) {\n                response[\"status\"] = response.statusCode\n            }\n        }\n        return response\n    }\n}\n\nfunction Base64() {\n    // private property\n    _keyStr = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n    // public method for encoding\n    this.encode = function (input) {\n        var output = \"\";\n        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;\n        var i = 0;\n        input = _utf8_encode(input);\n        while (i < input.length) {\n            chr1 = input.charCodeAt(i++);\n            chr2 = input.charCodeAt(i++);\n            chr3 = input.charCodeAt(i++);\n            enc1 = chr1 >> 2;\n            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n            enc4 = chr3 & 63;\n            if (isNaN(chr2)) {\n                enc3 = enc4 = 64;\n            } else if (isNaN(chr3)) {\n                enc4 = 64;\n            }\n            output = output +\n                _keyStr.charAt(enc1) + _keyStr.charAt(enc2) +\n                _keyStr.charAt(enc3) + _keyStr.charAt(enc4);\n        }\n        return output;\n    }\n    // public method for decoding\n    this.decode = function (input) {\n        var output = \"\";\n        var chr1, chr2, chr3;\n        var enc1, enc2, enc3, enc4;\n        var i = 0;\n        input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n        while (i < input.length) {\n            enc1 = _keyStr.indexOf(input.charAt(i++));\n            enc2 = _keyStr.indexOf(input.charAt(i++));\n            enc3 = _keyStr.indexOf(input.charAt(i++));\n            enc4 = _keyStr.indexOf(input.charAt(i++));\n            chr1 = (enc1 << 2) | (enc2 >> 4);\n            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n            chr3 = ((enc3 & 3) << 6) | enc4;\n            output = output + String.fromCharCode(chr1);\n            if (enc3 != 64) {\n                output = output + String.fromCharCode(chr2);\n            }\n            if (enc4 != 64) {\n                output = output + String.fromCharCode(chr3);\n            }\n        }\n        output = _utf8_decode(output);\n        return output;\n    }\n    // private method for UTF-8 encoding\n    _utf8_encode = function (string) {\n        string = string.replace(/\\r\\n/g, \"\\n\");\n        var utftext = \"\";\n        for (var n = 0; n < string.length; n++) {\n            var c = string.charCodeAt(n);\n            if (c < 128) {\n                utftext += String.fromCharCode(c);\n            } else if ((c > 127) && (c < 2048)) {\n                utftext += String.fromCharCode((c >> 6) | 192);\n                utftext += String.fromCharCode((c & 63) | 128);\n            } else {\n                utftext += String.fromCharCode((c >> 12) | 224);\n                utftext += String.fromCharCode(((c >> 6) & 63) | 128);\n                utftext += String.fromCharCode((c & 63) | 128);\n            }\n\n        }\n        return utftext;\n    }\n    // private method for UTF-8 decoding\n    _utf8_decode = function (utftext) {\n        var string = \"\";\n        var i = 0;\n        var c = c1 = c2 = 0;\n        while (i < utftext.length) {\n            c = utftext.charCodeAt(i);\n            if (c < 128) {\n                string += String.fromCharCode(c);\n                i++;\n            } else if ((c > 191) && (c < 224)) {\n                c2 = utftext.charCodeAt(i + 1);\n                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));\n                i += 2;\n            } else {\n                c2 = utftext.charCodeAt(i + 1);\n                c3 = utftext.charCodeAt(i + 2);\n                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));\n                i += 3;\n            }\n        }\n        return string;\n    }\n}\n"
  },
  {
    "path": "tb_price_lite.js",
    "content": "/*\nREADME：https://github.com/yichahucha/surge/tree/master\n */\n\nconst $tool = new Tool()\nconst $base64 = new Base64()\nconst consoleLog = false\nconst url = $request.url\nconst body = $response.body\nconst path1 = \"/amdc/mobileDispatch\"\nconst path2 = \"/gw/mtop.taobao.detail.getdetail\"\n\nif (url.indexOf(path1) != -1) {\n    let obj = JSON.parse($base64.decode(body))\n    let dns = obj.dns\n    if (dns && dns.length > 0) {\n        let i = dns.length;\n        while (i--) {\n            const element = dns[i];\n            let host = \"trade-acs.m.taobao.com\"\n            if (element.host == host) {\n                element.ips = []\n                if (consoleLog) console.log(JSON.stringify(element))\n            }\n        }\n    }\n    $done({ body: $base64.encode(JSON.stringify(obj)) })\n}\n\nif (url.indexOf(path2) != -1) {\n    $done({ body })\n    const obj = JSON.parse(body)\n    let item = obj.data.item\n    let shareUrl = `https://item.taobao.com/item.htm?id=${item.itemId}`\n    requestPrice(shareUrl, function (data) {\n        if (data) {\n            if (data.ok == 1 && data.single) {\n                const lower = lowerMsgs(data.single)\n                const detail = priceSummary(data)\n                const tip = data.PriceRemark.Tip + \"（仅供参考）\"\n                $tool.notify(\"\", \"\", `${lower} ${tip}\\n${detail}\\n\\n👉查看详情：http://tool.manmanbuy.com/historyLowest.aspx?url=${encodeURI(shareUrl)}`)\n            }\n            if (data.ok == 0 && data.msg.length > 0) {\n                $tool.notify(\"\", \"\", `⚠️ ${data.msg}`)\n            }\n        }\n    })\n}\n\nfunction lowerMsgs(data) {\n    const lower = data.lowerPriceyh\n    const lowerDate = dateFormat(data.lowerDateyh)\n    const lowerMsg = \"〽️历史最低到手价：¥\" + String(lower) + `（${lowerDate}）`\n    return lowerMsg\n}\n\nfunction priceSummary(data) {\n    let summary = \"\"\n    let listPriceDetail = data.PriceRemark.ListPriceDetail\n    listPriceDetail.pop()\n    let list = listPriceDetail.concat(historySummary(data.single))\n    list.forEach((item, index) => {\n        if (index == 2) {\n            item.Name = \"双十一价格\"\n        } else if (index == 3) {\n            item.Name = \"六一八价格\"\n        } else if (index == 4) {\n            item.Name = \"三十天最低\"\n        }\n        summary += `\\n${item.Name}   ${item.Price}   ${item.Date}   ${item.Difference}`\n    })\n    return summary\n}\n\nfunction historySummary(single) {\n    const rexMatch = /\\[.*?\\]/g;\n    const rexExec = /\\[(.*),(.*),\"(.*)\"\\]/;\n    let currentPrice, lowest60, lowest180, lowest360\n    let list = single.jiagequshiyh.match(rexMatch);\n    list = list.reverse().slice(0, 360);\n    list.forEach((item, index) => {\n        if (item.length > 0) {\n            const result = rexExec.exec(item);\n            const dateUTC = new Date(eval(result[1]));\n            const date = dateUTC.format(\"yyyy-MM-dd\");\n            let price = parseFloat(result[2]);\n            if (index == 0) {\n                currentPrice = price\n                lowest60 = { Name: \"六十天最低\", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price }\n                lowest180 = { Name: \"一百八最低\", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price }\n                lowest360 = { Name: \"三百六最低\", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price }\n            }\n            if (index < 60 && price <= lowest60.price) {\n                lowest60.price = price\n                lowest60.Price = `¥${String(price)}`\n                lowest60.Date = date\n                lowest60.Difference = difference(currentPrice, price)\n            }\n            if (index < 180 && price <= lowest180.price) {\n                lowest180.price = price\n                lowest180.Price = `¥${String(price)}`\n                lowest180.Date = date\n                lowest180.Difference = difference(currentPrice, price)\n            }\n            if (index < 360 && price <= lowest360.price) {\n                lowest360.price = price\n                lowest360.Price = `¥${String(price)}`\n                lowest360.Date = date\n                lowest360.Difference = difference(currentPrice, price)\n            }\n        }\n    });\n    return [lowest60, lowest180, lowest360];\n}\n\nfunction difference(currentPrice, price) {\n    let difference = strip(currentPrice - price)\n    if (difference == 0) {\n        return \"-\"\n    } else {\n        return `${difference > 0 ? \"↑\" : \"↓\"}${String(difference)}`\n    }\n}\n\nfunction strip(num, precision = 12) {\n    return +parseFloat(num.toPrecision(precision));\n}\n\nfunction requestPrice(share_url, callback) {\n    const options = {\n        url: \"https://apapia-history.manmanbuy.com/ChromeWidgetServices/WidgetServices.ashx\",\n        headers: {\n            \"Content-Type\": \"application/x-www-form-urlencoded;charset=utf-8\",\n            \"User-Agent\": \"Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 - mmbWebBrowse - ios\"\n        },\n        body: \"methodName=getHistoryTrend&p_url=\" + encodeURIComponent(share_url)\n    }\n    $tool.post(options, function (error, response, data) {\n        if (!error) {\n            callback(JSON.parse(data));\n            if (consolelog) console.log(\"Data:\\n\" + data);\n        } else {\n            callback(null, null);\n            if (consolelog) console.log(\"Error:\\n\" + error);\n        }\n    })\n}\n\nfunction dateFormat(cellval) {\n    const date = new Date(parseInt(cellval.replace(\"/Date(\", \"\").replace(\")/\", \"\"), 10));\n    const month = date.getMonth() + 1 < 10 ? \"0\" + (date.getMonth() + 1) : date.getMonth() + 1;\n    const currentDate = date.getDate() < 10 ? \"0\" + date.getDate() : date.getDate();\n    return date.getFullYear() + \"-\" + month + \"-\" + currentDate;\n}\n\nArray.prototype.insert = function (index, item) {\n    this.splice(index, 0, item);\n};\n\nDate.prototype.format = function (fmt) {\n    var o = {\n        \"y+\": this.getFullYear(),\n        \"M+\": this.getMonth() + 1,\n        \"d+\": this.getDate(),\n        \"h+\": this.getHours(),\n        \"m+\": this.getMinutes(),\n        \"s+\": this.getSeconds(),\n        \"q+\": Math.floor((this.getMonth() + 3) / 3),\n        \"S+\": this.getMilliseconds()\n    };\n    for (var k in o) {\n        if (new RegExp(\"(\" + k + \")\").test(fmt)) {\n            if (k == \"y+\") {\n                fmt = fmt.replace(RegExp.$1, (\"\" + o[k]).substr(4 - RegExp.$1.length));\n            }\n            else if (k == \"S+\") {\n                var lens = RegExp.$1.length;\n                lens = lens == 1 ? 3 : lens;\n                fmt = fmt.replace(RegExp.$1, (\"00\" + o[k]).substr((\"\" + o[k]).length - 1, lens));\n            }\n            else {\n                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : ((\"00\" + o[k]).substr((\"\" + o[k]).length)));\n            }\n        }\n    }\n    return fmt;\n}\n\nfunction Tool() {\n    _node = (() => {\n        if (typeof require == \"function\") {\n            const request = require('request')\n            return ({ request })\n        } else {\n            return (null)\n        }\n    })()\n    _isSurge = typeof $httpClient != \"undefined\"\n    _isQuanX = typeof $task != \"undefined\"\n    this.isSurge = _isSurge\n    this.isQuanX = _isQuanX\n    this.isResponse = typeof $response != \"undefined\"\n    this.notify = (title, subtitle, message) => {\n        if (_isQuanX) $notify(title, subtitle, message)\n        if (_isSurge) $notification.post(title, subtitle, message)\n        if (_node) console.log(JSON.stringify({ title, subtitle, message }));\n    }\n    this.write = (value, key) => {\n        if (_isQuanX) return $prefs.setValueForKey(value, key)\n        if (_isSurge) return $persistentStore.write(value, key)\n    }\n    this.read = (key) => {\n        if (_isQuanX) return $prefs.valueForKey(key)\n        if (_isSurge) return $persistentStore.read(key)\n    }\n    this.get = (options, callback) => {\n        if (_isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"GET\"\n            $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null))\n        }\n        if (_isSurge) $httpClient.get(options, (error, response, body) => { callback(error, _status(response), body) })\n        if (_node) _node.request(options, (error, response, body) => { callback(error, _status(response), body) })\n    }\n    this.post = (options, callback) => {\n        if (_isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"POST\"\n            $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null))\n        }\n        if (_isSurge) $httpClient.post(options, (error, response, body) => { callback(error, _status(response), body) })\n        if (_node) _node.request.post(options, (error, response, body) => { callback(error, _status(response), body) })\n    }\n    _status = (response) => {\n        if (response) {\n            if (response.status) {\n                response[\"statusCode\"] = response.status\n            } else if (response.statusCode) {\n                response[\"status\"] = response.statusCode\n            }\n        }\n        return response\n    }\n}\n\nfunction Base64() {\n    // private property\n    _keyStr = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n    // public method for encoding\n    this.encode = function (input) {\n        var output = \"\";\n        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;\n        var i = 0;\n        input = _utf8_encode(input);\n        while (i < input.length) {\n            chr1 = input.charCodeAt(i++);\n            chr2 = input.charCodeAt(i++);\n            chr3 = input.charCodeAt(i++);\n            enc1 = chr1 >> 2;\n            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n            enc4 = chr3 & 63;\n            if (isNaN(chr2)) {\n                enc3 = enc4 = 64;\n            } else if (isNaN(chr3)) {\n                enc4 = 64;\n            }\n            output = output +\n                _keyStr.charAt(enc1) + _keyStr.charAt(enc2) +\n                _keyStr.charAt(enc3) + _keyStr.charAt(enc4);\n        }\n        return output;\n    }\n    // public method for decoding\n    this.decode = function (input) {\n        var output = \"\";\n        var chr1, chr2, chr3;\n        var enc1, enc2, enc3, enc4;\n        var i = 0;\n        input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n        while (i < input.length) {\n            enc1 = _keyStr.indexOf(input.charAt(i++));\n            enc2 = _keyStr.indexOf(input.charAt(i++));\n            enc3 = _keyStr.indexOf(input.charAt(i++));\n            enc4 = _keyStr.indexOf(input.charAt(i++));\n            chr1 = (enc1 << 2) | (enc2 >> 4);\n            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n            chr3 = ((enc3 & 3) << 6) | enc4;\n            output = output + String.fromCharCode(chr1);\n            if (enc3 != 64) {\n                output = output + String.fromCharCode(chr2);\n            }\n            if (enc4 != 64) {\n                output = output + String.fromCharCode(chr3);\n            }\n        }\n        output = _utf8_decode(output);\n        return output;\n    }\n    // private method for UTF-8 encoding\n    _utf8_encode = function (string) {\n        string = string.replace(/\\r\\n/g, \"\\n\");\n        var utftext = \"\";\n        for (var n = 0; n < string.length; n++) {\n            var c = string.charCodeAt(n);\n            if (c < 128) {\n                utftext += String.fromCharCode(c);\n            } else if ((c > 127) && (c < 2048)) {\n                utftext += String.fromCharCode((c >> 6) | 192);\n                utftext += String.fromCharCode((c & 63) | 128);\n            } else {\n                utftext += String.fromCharCode((c >> 12) | 224);\n                utftext += String.fromCharCode(((c >> 6) & 63) | 128);\n                utftext += String.fromCharCode((c & 63) | 128);\n            }\n\n        }\n        return utftext;\n    }\n    // private method for UTF-8 decoding\n    _utf8_decode = function (utftext) {\n        var string = \"\";\n        var i = 0;\n        var c = c1 = c2 = 0;\n        while (i < utftext.length) {\n            c = utftext.charCodeAt(i);\n            if (c < 128) {\n                string += String.fromCharCode(c);\n                i++;\n            } else if ((c > 191) && (c < 224)) {\n                c2 = utftext.charCodeAt(i + 1);\n                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));\n                i += 2;\n            } else {\n                c2 = utftext.charCodeAt(i + 1);\n                c3 = utftext.charCodeAt(i + 2);\n                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));\n                i += 3;\n            }\n        }\n        return string;\n    }\n}\n"
  },
  {
    "path": "tool.js",
    "content": "// 统一 Surge、QuanX、Node 相关脚本 API, 方便开发、调试\n// 包括 Node（request 模块）、Surge（$httpClient，$notification，$persistentStore 模块）、QuanX（$task，$notify，$prefs 模块）\n\nconst $tool = new Tool()\n// notify\n$tool.notify(\"title\", \"subtitle\", \"message\")\n// cache\n$tool.write(\"value\", \"key\")\n$tool.read(\"key\")\n// get\n$tool.get(\"http://www.baidu.com\", function (error, response, body) {\n    // response.status response.statusCode response.headers\n    if (!error) {\n        if (response.statusCode == 200) {\n            console.log(body)\n        }\n    } else {\n        console.log(error)\n    }\n})\n// post\nconst request = {\n    url: \"https://www.baidu.com\",\n    body: \"\"\n    //...\n}\n$tool.post(request, function (error, response, body) {\n    // response.status response.statusCode response.headers\n    if (!error) {\n        if (response.statusCode == 200) {\n            console.log(body)\n        }\n    } else {\n        console.log(error)\n    }\n})\n\nfunction Tool() {\n    _node = (() => {\n        if (typeof require == \"function\") {\n            const request = require('request')\n            return ({ request })\n        } else {\n            return (null)\n        }\n    })()\n    _isSurge = typeof $httpClient != \"undefined\"\n    _isQuanX = typeof $task != \"undefined\"\n    this.isSurge = _isSurge\n    this.isQuanX = _isQuanX\n    this.isResponse = typeof $response != \"undefined\"\n    this.notify = (title, subtitle, message) => {\n        if (_isQuanX) $notify(title, subtitle, message)\n        if (_isSurge) $notification.post(title, subtitle, message)\n        if (_node) console.log(JSON.stringify({ title, subtitle, message }));\n    }\n    this.write = (value, key) => {\n        if (_isQuanX) return $prefs.setValueForKey(value, key)\n        if (_isSurge) return $persistentStore.write(value, key)\n    }\n    this.read = (key) => {\n        if (_isQuanX) return $prefs.valueForKey(key)\n        if (_isSurge) return $persistentStore.read(key)\n    }\n    this.get = (options, callback) => {\n        if (_isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"GET\"\n            $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null))\n        }\n        if (_isSurge) $httpClient.get(options, (error, response, body) => { callback(error, _status(response), body) })\n        if (_node) _node.request(options, (error, response, body) => { callback(error, _status(response), body) })\n    }\n    this.post = (options, callback) => {\n        if (_isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"POST\"\n            $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null))\n        }\n        if (_isSurge) $httpClient.post(options, (error, response, body) => { callback(error, _status(response), body) })\n        if (_node) _node.request.post(options, (error, response, body) => { callback(error, _status(response), body) })\n    }\n    _status = (response) => {\n        if (response) {\n            if (response.status) {\n                response[\"statusCode\"] = response.status\n            } else if (response.statusCode) {\n                response[\"status\"] = response.statusCode\n            }\n        }\n        return response\n    }\n}\n\nfunction tool() {\n    const isSurge = typeof $httpClient != \"undefined\"\n    const isQuanX = typeof $task != \"undefined\"\n    const isResponse = typeof $response != \"undefined\"\n    const node = (() => {\n        if (typeof require == \"function\") {\n            const request = require('request')\n            return ({ request })\n        } else {\n            return (null)\n        }\n    })()\n    const notify = (title, subtitle, message) => {\n        if (isQuanX) $notify(title, subtitle, message)\n        if (isSurge) $notification.post(title, subtitle, message)\n        if (node) console.log(JSON.stringify({ title, subtitle, message }));\n    }\n    const write = (value, key) => {\n        if (isQuanX) return $prefs.setValueForKey(value, key)\n        if (isSurge) return $persistentStore.write(value, key)\n    }\n    const read = (key) => {\n        if (isQuanX) return $prefs.valueForKey(key)\n        if (isSurge) return $persistentStore.read(key)\n    }\n    const adapterStatus = (response) => {\n        if (response) {\n            if (response.status) {\n                response[\"statusCode\"] = response.status\n            } else if (response.statusCode) {\n                response[\"status\"] = response.statusCode\n            }\n        }\n        return response\n    }\n    const get = (options, callback) => {\n        if (isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"GET\"\n            $task.fetch(options).then(response => {\n                callback(null, adapterStatus(response), response.body)\n            }, reason => callback(reason.error, null, null))\n        }\n        if (isSurge) $httpClient.get(options, (error, response, body) => {\n            callback(error, adapterStatus(response), body)\n        })\n        if (node) {\n            node.request(options, (error, response, body) => {\n                callback(error, adapterStatus(response), body)\n            })\n        }\n    }\n    const post = (options, callback) => {\n        if (isQuanX) {\n            if (typeof options == \"string\") options = { url: options }\n            options[\"method\"] = \"POST\"\n            $task.fetch(options).then(response => {\n                callback(null, adapterStatus(response), response.body)\n            }, reason => callback(reason.error, null, null))\n        }\n        if (isSurge) {\n            $httpClient.post(options, (error, response, body) => {\n                callback(error, adapterStatus(response), body)\n            })\n        }\n        if (node) {\n            node.request.post(options, (error, response, body) => {\n                callback(error, adapterStatus(response), body)\n            })\n        }\n    }\n    return { isQuanX, isSurge, isResponse, notify, write, read, get, post }\n}"
  },
  {
    "path": "wb_ad.js",
    "content": "/*\nREADME：https://github.com/yichahucha/surge/tree/master\n */\n\nconst path1 = \"/groups/timeline\";\nconst path2 = \"/statuses/unread\";\nconst path3 = \"/statuses/extend\";\nconst path4 = \"/comments/build_comments\";\nconst path5 = \"/photo/recommend_list\";\nconst path6 = \"/stories/video_stream\";\nconst path7 = \"/statuses/positives/get\";\nconst path8 = \"/stories/home_list\";\nconst path9 = \"/profile/statuses\";\nconst path10 = \"/statuses/friends/timeline\";\nconst path11 = \"/service/picfeed\";\nconst path12 = \"/fangle/timeline\";\nconst path13 = \"/searchall\";\nconst path14 = \"/cardlist\";\nconst path15 = \"/statuses/video_timeline\";\nconst path16 = \"/page\";\nconst path17 = \"/statuses/friends_timeline\";\nconst path18 = \"/!/photos/pic_recommend_status\";\n\nconst url = $request.url;\nvar body = $response.body;\n\nif (\n    url.indexOf(path1) != -1 ||\n    url.indexOf(path2) != -1 ||\n    url.indexOf(path10) != -1 ||\n    url.indexOf(path15) != -1 ||\n    url.indexOf(path17) != -1\n) {\n    let obj = JSON.parse(body);\n    if (obj.statuses) obj.statuses = filter_timeline_statuses(obj.statuses);\n    if (obj.advertises) obj.advertises = [];\n    if (obj.ad) obj.ad = [];\n    if (obj.num) obj.num = obj.original_num;\n    if (obj.trends) obj.trends = [];\n    body = JSON.stringify(obj);\n}\n\nif (url.indexOf(path3) != -1) {\n    let obj = JSON.parse(body);\n    if (obj.trend) delete obj.trend;\n    body = JSON.stringify(obj);\n}\n\nif (url.indexOf(path4) != -1) {\n    let obj = JSON.parse(body);\n    obj.recommend_max_id = 0;\n    if (obj.status) {\n        if (obj.top_hot_structs) {\n            obj.max_id = obj.top_hot_structs.call_back_struct.max_id;\n            delete obj.top_hot_structs;\n        }\n        if (obj.datas) obj.datas = filter_comments(obj.datas);\n    } else {\n        obj.datas = [];\n    }\n    body = JSON.stringify(obj);\n}\n\nif (url.indexOf(path5) != -1 ||\n    url.indexOf(path18) != -1) {\n    let obj = JSON.parse(body);\n    obj.data = {};\n    body = JSON.stringify(obj);\n}\n\nif (url.indexOf(path6) != -1) {\n    let obj = JSON.parse(body);\n    let segments = obj.segments;\n    if (segments && segments.length > 0) {\n        let i = segments.length;\n        while (i--) {\n            const element = segments[i];\n            let is_ad = element.is_ad;\n            if (is_ad && is_ad == true) segments.splice(i, 1);\n        }\n    }\n    body = JSON.stringify(obj);\n}\n\nif (url.indexOf(path7) != -1) {\n    let obj = JSON.parse(body);\n    obj.datas = [];\n    body = JSON.stringify(obj);\n}\n\nif (url.indexOf(path8) != -1) {\n    let obj = JSON.parse(body);\n    obj.story_list = [];\n    body = JSON.stringify(obj);\n}\n\nif (url.indexOf(path11) != -1) {\n    let obj = JSON.parse(body);\n    obj.data = [];\n    body = JSON.stringify(obj);\n}\n\nif (\n    url.indexOf(path9) != -1 ||\n    url.indexOf(path12) != -1 ||\n    url.indexOf(path13) != -1 ||\n    url.indexOf(path14) != -1 ||\n    url.indexOf(path16) != -1\n) {\n    let obj = JSON.parse(body);\n    if (obj.cards) obj.cards = filter_timeline_cards(obj.cards);\n    body = JSON.stringify(obj);\n}\n\n$done({ body });\n\nfunction filter_timeline_statuses(statuses) {\n    if (statuses && statuses.length > 0) {\n        let i = statuses.length;\n        while (i--) {\n            let element = statuses[i];\n            if (is_timeline_likerecommend(element.title)) statuses.splice(i, 1);\n            if (is_timeline_ad(element)) statuses.splice(i, 1);\n        }\n    }\n    return statuses;\n}\n\nfunction filter_comments(datas) {\n    if (datas && datas.length > 0) {\n        let i = datas.length;\n        while (i--) {\n            const element = datas[i];\n            let type = element.type;\n            if (type == 5 || type == 1 || type == 6) datas.splice(i, 1);\n        }\n    }\n    return datas;\n}\n\nfunction filter_timeline_cards(cards) {\n    if (cards && cards.length > 0) {\n        let j = cards.length;\n        while (j--) {\n            let item = cards[j];\n            let card_group = item.card_group;\n            if (card_group && card_group.length > 0) {\n                let i = card_group.length;\n                while (i--) {\n                    let card_group_item = card_group[i];\n                    let card_type = card_group_item.card_type;\n                    if (card_type) {\n                        if (card_type == 9) {\n                            if (is_timeline_ad(card_group_item.mblog)) card_group.splice(i, 1);\n                        } else if (card_type == 118 || card_type == 89) {\n                            card_group.splice(i, 1);\n                        } else if (card_type == 42) {\n                            if (card_group_item.desc == '\\u53ef\\u80fd\\u611f\\u5174\\u8da3\\u7684\\u4eba') {\n                                cards.splice(j, 1);\n                                break;\n                            }\n                        }\n                    }\n                }\n            } else {\n                let card_type = item.card_type;\n                if (card_type && card_type == 9) {\n                    if (is_timeline_ad(item.mblog)) cards.splice(j, 1);\n                }\n            }\n        }\n    }\n    return cards;\n}\n\nfunction is_timeline_ad(mblog) {\n    if (!mblog) return false;\n    let promotiontype = mblog.promotion && mblog.promotion.type && mblog.promotion.type == \"ad\";\n    let mblogtype = mblog.mblogtype && mblog.mblogtype == 1;\n    return (promotiontype || mblogtype) ? true : false;\n}\n\nfunction is_timeline_likerecommend(title) {\n    return title && title.type && title.type == \"likerecommend\" ? true : false;\n}\n"
  },
  {
    "path": "wb_launch.js",
    "content": "/*\nREADME：https://github.com/yichahucha/surge/tree/master\n */\n\nconst path1 = \"/interface/sdk/sdkad.php\";\nconst path2 = \"/wbapplua/wbpullad.lua\";\n\nconst url = $request.url;\nvar body = $response.body;\n\nif (url.indexOf(path1) != -1) {\n    let re = /\\{.*\\}/;\n    body = body.match(re);\n    var obj = JSON.parse(body);\n    if (obj.background_delay_display_time) obj.background_delay_display_time = 60*60*24*365;\n    if (obj.show_push_splash_ad) obj.show_push_splash_ad = false;\n    if (obj.ads) obj.ads = [];\n    body = JSON.stringify(obj) + 'OK';\n}\n\nif (url.indexOf(path2) != -1) {\n    var obj = JSON.parse(body);\n    if (obj.cached_ad && obj.cached_ad.ads) obj.cached_ad.ads = [];\n    body = JSON.stringify(obj);\n}\n\n$done({body});\n"
  }
]