├── README.md ├── boxjs ├── Part-timeJob_boxjs.json └── jf_boxjs.json ├── rewrite ├── baidu_user_agent.conf ├── get_10000_cookie.conf ├── get_10010_cookie.conf ├── get_didi_cookie.conf ├── get_elem_cookie.conf ├── get_jd_cookie.conf ├── get_jdjr_cookie.conf ├── get_jingxi_cookie.conf ├── get_meituan_cookie.conf ├── get_sf_cookie.conf ├── get_smzdm_cookie.conf ├── get_tieba_cookie.conf ├── get_wf_cookie.conf ├── jd_login_help2.sgmodule ├── jd_price.conf ├── jd_price_lite.conf ├── jd_reject_logout.sgmodule ├── jf_Convert.conf ├── jf_Convert.sgmodule └── weixin110.conf └── scripts ├── jd_price.js ├── jd_price_lite.js ├── jd_reject_logout.js ├── jf_Convert.js └── weixin110.js /README.md: -------------------------------------------------------------------------------- 1 | # Quantumult-X 自用脚本 2 | -------------------------------------------------------------------------------- /boxjs/Part-timeJob_boxjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "Part-timeJob", 3 | "name": "打工仔", 4 | "author": "@CrawlID", 5 | "icon": "https://raw.githubusercontent.com/Former-Years/icon/master/Part-timeJob.png", 6 | "repo": "", 7 | "apps": [ 8 | { 9 | "id": "CrawlID", 10 | "name": "组队瓜分/会员开卡/关注有礼/收藏有礼", 11 | "keys": [ 12 | "TG_BOT_TOKEN", 13 | "TG_USER_ID", 14 | "QUOTATION" 15 | ], 16 | "settings": [ 17 | { 18 | "id": "TG_BOT_TOKEN", 19 | "name": "TG_BOT_TOKEN", 20 | "val": "", 21 | "type": "text", 22 | "placeholder": "123:ABCD", 23 | "autoGrow": true, 24 | "rows": 2, 25 | "desc": "输入后你将是一个合格的打工人" 26 | }, 27 | { 28 | "id": "TG_USER_ID", 29 | "name": "TG群组ID", 30 | "type": "text", 31 | "val": "-1001589058412", 32 | "placeholder": "TG群组ID", 33 | "autoGrow": true, 34 | "rows": 2, 35 | "desc": "默认为偷撸群ID-1001589058412" 36 | }, 37 | { 38 | "id": "QUOTATION", 39 | "name": "打工语录", 40 | "type": "textarea", 41 | "val": "", 42 | "placeholder": "打工人,打工魂!", 43 | "autoGrow": false, 44 | "rows": 4, 45 | "desc": "使用&分割" 46 | } 47 | ], 48 | "author": "@打工仔", 49 | "repo": "", 50 | "script": "", 51 | "icons": [ 52 | "https://raw.githubusercontent.com/Former-Years/icon/master/Part-timeJob.png", 53 | "https://raw.githubusercontent.com/Former-Years/icon/master/Part-timeJob.png" 54 | ] 55 | } 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /boxjs/jf_boxjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "jfConvert", 3 | "name": "京粉转链", 4 | "author": "@jfConvert", 5 | "icon": "https://is5-ssl.mzstatic.com/image/thumb/Purple125/v4/eb/a8/f6/eba8f63a-b550-4586-b5d3-f22c0718ef81/source/100x100bb.jpg", 6 | "repo": "https://jingfen.jd.com/html/index.html", 7 | "apps": [ 8 | { 9 | "id": "jf", 10 | "name": "京粉转链", 11 | "desc": "在京东比价中增加京粉转链,如显示有转链信息(即使显示无详细返利信息)则可点击跳转跟单,如未显示返利信息则为未参加推广的商品,不会跳转。", 12 | "keys": ["jfCookie", "jfUseConvert", "jfAutoScheme", "jfusejsapp", "jfChooseScheme", "chooseBrowser", "jfDIYScheme"], 13 | "settings": [ 14 | { 15 | "id": "jfUseConvert", 16 | "name": "开启转链", 17 | "val": true, 18 | "type": "boolean", 19 | "desc": "是否开启京粉转链?" 20 | }, 21 | { 22 | "id": "jfAutoScheme", 23 | "name": "自动目标", 24 | "val": true, 25 | "type": "boolean", 26 | "desc": "开启后如转链成功有返利,点击通知跳转正在使用的 app,关闭则跳转自选的 app。" 27 | }, 28 | { 29 | "id": "jfChooseScheme", 30 | "name": "自选目标", 31 | "val": "jd", 32 | "type": "radios", 33 | "desc": "自选跳转的 app,仅在自动目标关闭时有效。", 34 | "items": [ 35 | { "key": "jd", "label": "京东" }, 36 | { "key": "jx", "label": "京喜" }, 37 | { "key": "jk", "label": "京东健康" }, 38 | { "key": "js", "label": "京东极速版" }, 39 | { "key": "browser", "label": "浏览器" } 40 | ] 41 | }, 42 | { 43 | "id": "jfusejsapp", 44 | "name": "京东极速版使用 app", 45 | "val": false, 46 | "type": "boolean", 47 | "desc": "开启时对目标为京东极速版则跳转京东极速版,关闭则跳转浏览器,默认关闭。注意:即使开启,由于极速版 URL Scheme 问题,跳转后只能先加入购物车,返回原购物车界面进行结账,否则无法使用极速版优惠券。" 48 | }, 49 | { 50 | "id": "chooseBrowser", 51 | "name": "浏览器目标", 52 | "val": "Safari", 53 | "type": "radios", 54 | "desc": "自选跳转的浏览器。", 55 | "items": [ 56 | { "key": "Safari", "label": "Safari" }, 57 | { "key": "Alook", "label": "Alook" }, 58 | { "key": "DIY", "label": "自定义" } 59 | ] 60 | }, 61 | { 62 | "id": "jfDIYScheme", 63 | "name": "自定义浏览器", 64 | "val": "", 65 | "type": "textarea", 66 | "placeholder": "Foxok://url?", 67 | "autoGrow": true, 68 | "rows": 2, 69 | "desc": "自定义跳转浏览器 URL Scheme,拼接后会是 diy+convertURL,如 Foxok://url?convertURL" 70 | }, 71 | { 72 | "id": "jfCookie", 73 | "name": "Cookie", 74 | "type": "textarea", 75 | "autoGrow": true, 76 | "rows": 2, 77 | "desc": "使用京粉的京东账号 Cookie,如不填则为京东系脚本中的第一个 Cookie。" 78 | } 79 | ], 80 | "author": "@jfConvert", 81 | "repo": "https://jingfen.jd.com/html/index.html", 82 | "icons": [ 83 | "https://is5-ssl.mzstatic.com/image/thumb/Purple125/v4/eb/a8/f6/eba8f63a-b550-4586-b5d3-f22c0718ef81/source/100x100bb.jpg", 84 | "https://is5-ssl.mzstatic.com/image/thumb/Purple125/v4/eb/a8/f6/eba8f63a-b550-4586-b5d3-f22c0718ef81/source/100x100bb.jpg" 85 | ] 86 | } 87 | ] 88 | } -------------------------------------------------------------------------------- /rewrite/baidu_user_agent.conf: -------------------------------------------------------------------------------- 1 | # 百度防跳转(全站替换为手机百度 Quark 的 User-Agent) 2 | ^https?:\/\/(?!d\.pcs).*(? 红包签到) 3 | 4 | ^https:\/\/i.meituan.com\/evolve\/signin\/signpost\/ url script-request-body https://raw.githubusercontent.com/chavyleung/scripts/master/meituan/meituan.js 5 | 6 | hostname = i.meituan.com 7 | -------------------------------------------------------------------------------- /rewrite/get_sf_cookie.conf: -------------------------------------------------------------------------------- 1 | # 获取顺丰速运 Cookie 2 | ^https:\/\/ccsp-egmas.sf-express.com\/cx-app-member\/member\/app\/user\/universalSign url script-request-body https://raw.githubusercontent.com/chavyleung/scripts/master/sfexpress/sfexpress.cookie.js 3 | 4 | hostname = ccsp-egmas.sf-express.com 5 | -------------------------------------------------------------------------------- /rewrite/get_smzdm_cookie.conf: -------------------------------------------------------------------------------- 1 | # 获取 什么值得买 Cookie 2 | # 1.浏览器访问并登录: https://zhiyou.smzdm.com/user/login 3 | # 2.打开浏览器访问: https://www.smzdm.com 4 | # 3.QuanX提示: Cookie [什么值得买] 写入成功 5 | 6 | #smzdm 7 | ^https:\/\/www\.smzdm\.com\/?.? url script-request-header https://raw.githubusercontent.com/chavyleung/scripts/master/smzdm/quanx/smzdm.cookie.js 8 | 9 | hostname = *.smzdm.com 10 | -------------------------------------------------------------------------------- /rewrite/get_tieba_cookie.conf: -------------------------------------------------------------------------------- 1 | # 获取 百度贴吧 Cookie 2 | # 打开百度贴吧App后(AppStore中国区, 非内部版),点击"我的", 提示成功获取cookie即可; 3 | 4 | https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login url script-request-header https://raw.githubusercontent.com/NobyDa/Script/master/BDTieBa-DailyBonus/TieBa.js 5 | 6 | hostname= c.tieba.baidu.com 7 | -------------------------------------------------------------------------------- /rewrite/get_wf_cookie.conf: -------------------------------------------------------------------------------- 1 | # 获取威锋 Cookie 2 | ^http:\/\/49.234.36.200:9091\/v1\/auth\/signin url script-request-body https://raw.githubusercontent.com/chavyleung/scripts/master/feng/feng.cookie.js 3 | 4 | hostname = 49.234.36.200 5 | -------------------------------------------------------------------------------- /rewrite/jd_login_help2.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=京东登录辅助 2 | #!desc=京东+京喜账号CK辅助登陆(UI2) 2021/08/06 13:50 3 | 4 | [Script] 5 | # > 京东系列 6 | 京东首页 = type=http-response,pattern=^https:\/\/m\.jd\.com,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 7 | 京东登陆 = type=http-response,pattern=^https:\/\/plogin\.m\.jd\.com,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 8 | 京东我的 = type=http-response,pattern=^https:\/\/home\.m\.jd\.com\/(myJd\/newhome\.action|userinfom\/QueryUserInfoM),requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 9 | 京东订单 = type=http-response,pattern=^https:\/\/wqs\.jd\.com\/order\/orderlist_merge\.shtml,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 10 | 京东下单 = type=http-response,pattern=^https:\/\/wq\.jd\.com\/deal\/confirmorder,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 11 | 京东购物 = type=http-response,pattern=^https:\/\/p\.m\.jd\.com\/cart\/cart\.action,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 12 | 京豆明细 = type=http-response,pattern=^https:\/\/bean\.m\.jd\.com\/beanDetail\/index\.action,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 13 | 京东商品 = type=http-response,pattern=^https:\/\/item\.m\.jd\.com\/(product\/\d+\.html|ware\/view.action\?wareId=\d+|item\/jxview\?skuId=\d+),requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 14 | 京东店铺 = type=http-response,pattern=^https:\/\/shop\.m\.jd\.com\/(shopv2\/mzpage|\?shopId),requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 15 | 京东入会 = type=http-response,pattern=^https:\/\/shopmember\.m\.jd\.com\/shopcard\/\?venderId=\d+,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 16 | 京东销卡 = type=http-response,pattern=^https:\/\/cardpackage\.jd\.com,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 17 | 领券中心 = type=http-response,pattern=^https:\/\/coupon\.m\.jd\.com\/center\/getCouponCenter\.action,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 18 | 签到日历 = type=http-response,pattern=^https:\/\/bean\.m\.jd\.com\/bean\/signIndex\.action,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 19 | 切换修复 = type=http-response,pattern=^https:\/\/plogin\.m\.jd\.com\/cgi-bin\/mm\/dom(sms)?login,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/id77/QuantumultX/master/Script/unHttpOnly.js 20 | 京东活动 = type=http-response,pattern=^https:\/\/h5\.m\.jd\.com\/babelDiy\/Zeus\/\w+\/index\.html,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 21 | 京东红包 = type=http-response,pattern=^https:\/\/wqs\.jd\.com\/my\/redpacket\.shtml,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 22 | 京东超市 = type=http-response,pattern=^https:\/\/jdsupermarket\.jd\.com\/game,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 23 | 京东优惠 = type=http-response,pattern=^https:\/\/coupon\.m\.jd\.com\/coupons\/show\.action,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 24 | 我的优惠 = type=http-response,pattern=^https:\/\/wqs\.jd\.com\/my\/coupon\/jd\.shtml,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 25 | 任务中心 = type=http-response,pattern=^https:\/\/prodev\.m\.jd.com\/mall\/active\/\w+\/index\.html,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 26 | 京东试用 = type=http-response,pattern=^https:\/\/pro\.m\.jd\.com\/mall\/active\/\w+\/index\.html,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 27 | 京东问卷 = type=http-response,pattern=^https:\/\/answer\.jd\.com\/answer,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 28 | 手机狂欢 = type=http-response,pattern=^https:\/\/carnivalcity\.m\.jd\.com,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 29 | 30 | # > 京喜系列 31 | 京喜首页 = type=http-response,pattern=^https:\/\/m\.jingxi\.com\/mcoss\/wxmall\/home,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 32 | 京喜商品 = type=http-response,pattern=^https:\/\/(m\.jingxi\.com\/item\/(jxview|view)|wq\.jd.com\/item),requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 33 | 京喜购物 = type=http-response,pattern=^https:\/\/u\.jingxi\.com\/cart\/mycart\?fromnav,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 34 | 京喜我的 = type=http-response,pattern=^https:\/\/st\.jingxi\.com\/pingou\/account\/index\.html,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 35 | 京喜订单 = type=http-response,pattern=^https:\/\/st\.jingxi\.com\/order\/orderlist_merge\.shtml,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 36 | 京喜下单 = type=http-response,pattern=^https:\/\/(wqs\.jd\.com\/order\/s_confirm_app\.shtml|m\.jingxi\.com\/deal\/minfo\/confirmorder|m\.jingxi\.com\/deal\/confirmorder\/main),requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 37 | 京喜农场 = type=http-response,pattern=^https:\/\/(actst\.jingxi\.com|wqsh\.jd\.com)\/sns\/201912\/12\/jxnc\/detail\.html,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 38 | 京喜财富 = type=http-response,pattern=^https:\/\/st\.jingxi\.com\/fortune_island\/index2?\.html,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 39 | 京喜工厂 = type=http-response,pattern=^https:\/\/(actst\.jingxi\.com|wqsd\.jd\.com)\/pingou\/dream_factory,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 40 | 京喜牧场 = type=http-response,pattern=^https:\/\/wqs\.jd\.com\/pingou\/jxmc\/index\.html,requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/dompling/Script/master/jd/jd_login_help2.js 41 | 42 | [MITM] 43 | hostname = %INSERT% m.jd.com, plogin.m.jd.com, home.m.jd.com, wqs.jd.com, wq.jd.com, wqsd.jd.com,wqsh.jd.com, p.m.jd.com, bean.m.jd.com, item.m.jd.com, shop.m.jd.com, shopmember.m.jd.com, cardpackage.jd.com, coupon.m.jd.com, m.jingxi.com, u.jingxi.com, st.jingxi.com, actst.jingxi.com, h5.m.jd.com, jdsupermarket.jd.com, wbbny.m.jd.com, prodev.m.jd.com, try.m.jd.com, answer.jd.com, carnivalcity.m.jd.com 44 | -------------------------------------------------------------------------------- /rewrite/jd_price.conf: -------------------------------------------------------------------------------- 1 | ^https?://api\.m\.jd\.com/client\.action\?functionId=(wareBusiness|serverConfig|basicConfig) url script-response-body https://raw.githubusercontent.com/Fokit/Quantumult-X/main/scripts/jd_price.js 2 | 3 | hostname = api.m.jd.com 4 | 5 | # 如果京东比价不生效,请检查重写是否订阅了神机去广告,然后把该订阅打开资源解析器,在订阅后面加#out=functionId即可; 6 | # 或者在本地重写[rewrite_local]添加一条 ^https?:\/\/api\.m\.jd.com\/client\.action\?functionId=start url reject-200 7 | -------------------------------------------------------------------------------- /rewrite/jd_price_lite.conf: -------------------------------------------------------------------------------- 1 | ^https?://api\.m\.jd\.com/(client\.action|api)\?functionId=(wareBusiness|serverConfig|basicConfig|lite_wareBusiness|pingou_item) url script-response-body https://raw.githubusercontent.com/Fokit/Quantumult-X/main/scripts/jd_price_lite.js 2 | 3 | hostname = api.m.jd.com 4 | 5 | # 如果京东比价不生效,请检查重写是否订阅了神机去广告,然后把该订阅打开资源解析器,在订阅后面加#out=functionId即可; 6 | # 或者在本地重写[rewrite_local]添加一条 ^https?:\/\/api\.m\.jd.com\/client\.action\?functionId=start url reject-200 7 | -------------------------------------------------------------------------------- /rewrite/jd_reject_logout.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=京东登出拦截 2 | 3 | [Script] 4 | 京东登出拦截 = type=http-request,pattern=\/(cgi-bin\/wlogin\/applogin|applogin_v2),requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/Fokit/Quantumult-X/main/scripts/jd_reject_logout.js 5 | 6 | hostname = %INSERT% * -------------------------------------------------------------------------------- /rewrite/jf_Convert.conf: -------------------------------------------------------------------------------- 1 | # 京粉转链 2 | 3 | ^https?://api\.m\.jd\.com/(client\.action|api)\?functionId=(wareBusiness|serverConfig|basicConfig|lite_wareBusiness|pingou_item) url script-response-body https://raw.githubusercontent.com/Fokit/Quantumult-X/main/scripts/jf_Convert.js 4 | 5 | hostname = api.m.jd.com 6 | 7 | # 如果京粉转链不生效,请检查重写是否订阅了神机去广告,然后把该订阅打开资源解析器,在订阅后面加#out=functionId即可; 8 | # 或者在本地重写[rewrite_local]添加一条 ^https?:\/\/api\.m\.jd.com\/client\.action\?functionId=start url reject-200 9 | -------------------------------------------------------------------------------- /rewrite/jf_Convert.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=京粉转链 2 | #!desc=UpDate:2021-6-19 21:38 3 | #!system=ios 4 | 5 | [Script] 6 | 京粉转链 = type=http-response,pattern=^https:\/\/api\.m\.jd\.com/(client\.action|api)\?functionId=(wareBusiness|serverConfig|basicConfig|lite_wareBusiness|pingou_item),requires-body=1,max-size=0,timeout=1000,script-path=https://raw.githubusercontent.com/Fokit/Quantumult-X/main/scripts/jf_Convert.js 7 | 8 | hostname = %INSERT% api.m.jd.com 9 | -------------------------------------------------------------------------------- /rewrite/weixin110.conf: -------------------------------------------------------------------------------- 1 | ^https?:\/\/weixin110\.qq\.com\/cgi-bin\/mmspamsupport-bin\/newredirectconfirmcgi url script-response-body https://raw.githubusercontent.com/Fokit/Quantumult-X/main/scripts/weixin110.js 2 | 3 | hostname = weixin110.qq.com -------------------------------------------------------------------------------- /scripts/jd_price.js: -------------------------------------------------------------------------------- 1 | /* 2 | # 京东比价 修改版 3 | 原作者:@yichahucha 4 | ==============Quantumult-X============== 5 | [rewrite_remote] 6 | https://raw.githubusercontent.com/Fokit/Quantumult-X/main/rewrite/jd_price.conf, tag=京东比价, update-interval=86400, opt-parser=false, enabled=false 7 | */ 8 | 9 | const path1 = "serverConfig"; 10 | const path2 = "wareBusiness"; 11 | const path3 = "basicConfig"; 12 | const consolelog = false; 13 | const url = $request.url; 14 | const body = $response.body; 15 | const $tool = tool(); 16 | 17 | if (url.indexOf(path1) != -1) { 18 | let obj = JSON.parse(body); 19 | delete obj.serverConfig.httpdns; 20 | delete obj.serverConfig.dnsvip; 21 | delete obj.serverConfig.dnsvip_v6; 22 | $done({ body: JSON.stringify(obj) }); 23 | } 24 | 25 | if (url.indexOf(path3) != -1) { 26 | let obj = JSON.parse(body); 27 | let JDHttpToolKit = obj.data.JDHttpToolKit; 28 | if (JDHttpToolKit) { 29 | delete obj.data.JDHttpToolKit.httpdns; 30 | delete obj.data.JDHttpToolKit.dnsvipV6; 31 | } 32 | $done({ body: JSON.stringify(obj) }); 33 | } 34 | 35 | if (url.indexOf(path2) != -1) { 36 | let obj = JSON.parse(body); 37 | const floors = obj.floors; 38 | const commodity_info = floors[floors.length - 1]; 39 | const shareUrl = commodity_info.data.property.shareUrl; 40 | request_history_price(shareUrl, function (data) { 41 | if (data) { 42 | const lowerword = adword_obj(); 43 | lowerword.data.ad.textColor = "#000"; 44 | let bestIndex = 0; 45 | for (let index = 0; index < floors.length; index++) { 46 | const element = floors[index]; 47 | if (element.mId == lowerword.mId) { 48 | bestIndex = index + 1; 49 | break; 50 | } else { 51 | if (element.sortId > lowerword.sortId) { 52 | bestIndex = index; 53 | break; 54 | } 55 | } 56 | } 57 | if (data.ok == 1 && data.single) { 58 | const lower = lowerMsgs(data.single) 59 | const detail = priceSummary(data) 60 | const tip = data.PriceRemark.Tip + " ✦" 61 | lowerword.data.ad.adword = `${lower} ${tip}\n${detail}`; 62 | floors.insert(bestIndex, lowerword); 63 | } 64 | if (data.ok == 0 && data.msg.length > 0) { 65 | lowerword.data.ad.adword = "⚠️ " + data.msg; 66 | floors.insert(bestIndex, lowerword); 67 | } 68 | $done({ body: JSON.stringify(obj) }); 69 | } else { 70 | $done({ body }); 71 | } 72 | }) 73 | } 74 | 75 | function lowerMsgs(data) { 76 | const lower = data.lowerPriceyh 77 | const lowerDate = dateFormat(data.lowerDateyh) 78 | const lowerMsg = "✦ 历史最低价:¥" + String(lower) + ` (${lowerDate}) ` 79 | return lowerMsg 80 | } 81 | 82 | function priceSummary(data) { 83 | let summary = "" 84 | let listPriceDetail = data.PriceRemark.ListPriceDetail 85 | listPriceDetail.pop() 86 | let list = listPriceDetail.concat(historySummary(data.single)) 87 | list.forEach((item, index) => { 88 | if (item.Name == "双11价格") { 89 | item.Name = "双11价格" 90 | } else if (item.Name == "618价格") { 91 | item.Name = "618价格" 92 | } else if (item.Name == "30天最低价") { 93 | item.Name = "30天最低价" 94 | } 95 | summary += `\n${item.Name}${getSpace(8)}${item.Price}${getSpace(8)}${item.Date}${getSpace(8)}${item.Difference}` 96 | }) 97 | return summary 98 | } 99 | 100 | function historySummary(single) { 101 | const rexMatch = /\[.*?\]/g; 102 | const rexExec = /\[(.*),(.*),"(.*)".*\]/; 103 | let currentPrice, lowest60, lowest180, lowest360 104 | let list = single.jiagequshiyh.match(rexMatch); 105 | list = list.reverse().slice(0, 360); 106 | list.forEach((item, index) => { 107 | if (item.length > 0) { 108 | const result = rexExec.exec(item); 109 | const dateUTC = new Date(eval(result[1])); 110 | const date = dateUTC.format("yyyy-MM-dd"); 111 | let price = parseFloat(result[2]); 112 | if (index == 0) { 113 | currentPrice = price 114 | lowest60 = { Name: " 60天最低价", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price } 115 | lowest180 = { Name: "180天最低价", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price } 116 | lowest360 = { Name: "360天最低价", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price } 117 | } 118 | if (index < 60 && price <= lowest60.price) { 119 | lowest60.price = price 120 | lowest60.Price = `¥${String(price)}` 121 | lowest60.Date = date 122 | lowest60.Difference = difference(currentPrice, price) 123 | } 124 | if (index < 180 && price <= lowest180.price) { 125 | lowest180.price = price 126 | lowest180.Price = `¥${String(price)}` 127 | lowest180.Date = date 128 | lowest180.Difference = difference(currentPrice, price) 129 | } 130 | if (index < 360 && price <= lowest360.price) { 131 | lowest360.price = price 132 | lowest360.Price = `¥${String(price)}` 133 | lowest360.Date = date 134 | lowest360.Difference = difference(currentPrice, price) 135 | } 136 | } 137 | }); 138 | return [lowest60, lowest180, lowest360]; 139 | } 140 | 141 | function difference(currentPrice, price) { 142 | let difference = sub(currentPrice, price) 143 | if (difference == 0) { 144 | return "-" 145 | } else { 146 | return `${difference > 0 ? "↑" : "↓"}${String(difference)}` 147 | } 148 | } 149 | 150 | function sub(arg1, arg2) { 151 | return add(arg1, -Number(arg2), arguments[2]); 152 | } 153 | 154 | function add(arg1, arg2) { 155 | arg1 = arg1.toString(), arg2 = arg2.toString(); 156 | var arg1Arr = arg1.split("."), arg2Arr = arg2.split("."), d1 = arg1Arr.length == 2 ? arg1Arr[1] : "", d2 = arg2Arr.length == 2 ? arg2Arr[1] : ""; 157 | var maxLen = Math.max(d1.length, d2.length); 158 | var m = Math.pow(10, maxLen); 159 | var result = Number(((arg1 * m + arg2 * m) / m).toFixed(maxLen)); 160 | var d = arguments[2]; 161 | return typeof d === "number" ? Number((result).toFixed(d)) : result; 162 | } 163 | 164 | function request_history_price(share_url, callback) { 165 | const options = { 166 | url: "https://apapia-history.manmanbuy.com/ChromeWidgetServices/WidgetServices.ashx", 167 | headers: { 168 | "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", 169 | "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" 170 | }, 171 | body: "methodName=getHistoryTrend&p_url=" + encodeURIComponent(share_url) 172 | } 173 | $tool.post(options, function (error, response, data) { 174 | if (!error) { 175 | callback(JSON.parse(data)); 176 | if (consolelog) console.log("Data:\n" + data); 177 | } else { 178 | callback(null, null); 179 | if (consolelog) console.log("Error:\n" + error); 180 | } 181 | }) 182 | } 183 | 184 | function dateFormat(cellval) { 185 | const date = new Date(parseInt(cellval.replace("/Date(", "").replace(")/", ""), 10)); 186 | const month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1; 187 | const currentDate = date.getDate() < 10 ? "0" + date.getDate() : date.getDate(); 188 | return date.getFullYear() + "-" + month + "-" + currentDate; 189 | } 190 | 191 | function getSpace(length) { 192 | let blank = ""; 193 | for (let index = 0; index < length; index++) { 194 | blank += " "; 195 | } 196 | return blank; 197 | } 198 | 199 | function adword_obj() { 200 | return { 201 | "bId": "eCustom_flo_199", 202 | "cf": { 203 | "bgc": "#ffffff", 204 | "spl": "empty" 205 | }, 206 | "data": { 207 | "ad": { 208 | "adword": "", 209 | "textColor": "#8C8C8C", 210 | "color": "#f23030", 211 | "newALContent": true, 212 | "hasFold": true, 213 | "class": "com.jd.app.server.warecoresoa.domain.AdWordInfo.AdWordInfo", 214 | "adLinkContent": "", 215 | "adLink": "" 216 | } 217 | }, 218 | "mId": "bpAdword", 219 | "refId": "eAdword_0000000028", 220 | "sortId": 13 221 | } 222 | } 223 | 224 | function tool() { 225 | const isSurge = typeof $httpClient != "undefined" 226 | const isQuanX = typeof $task != "undefined" 227 | const isResponse = typeof $response != "undefined" 228 | const node = (() => { 229 | if (typeof require == "function") { 230 | const request = require('request') 231 | return ({ request }) 232 | } else { 233 | return (null) 234 | } 235 | })() 236 | const notify = (title, subtitle, message) => { 237 | if (isQuanX) $notify(title, subtitle, message) 238 | if (isSurge) $notification.post(title, subtitle, message) 239 | if (node) console.log(JSON.stringify({ title, subtitle, message })); 240 | } 241 | const write = (value, key) => { 242 | if (isQuanX) return $prefs.setValueForKey(value, key) 243 | if (isSurge) return $persistentStore.write(value, key) 244 | } 245 | const read = (key) => { 246 | if (isQuanX) return $prefs.valueForKey(key) 247 | if (isSurge) return $persistentStore.read(key) 248 | } 249 | const adapterStatus = (response) => { 250 | if (response) { 251 | if (response.status) { 252 | response["statusCode"] = response.status 253 | } else if (response.statusCode) { 254 | response["status"] = response.statusCode 255 | } 256 | } 257 | return response 258 | } 259 | const get = (options, callback) => { 260 | if (isQuanX) { 261 | if (typeof options == "string") options = { url: options } 262 | options["method"] = "GET" 263 | $task.fetch(options).then(response => { 264 | callback(null, adapterStatus(response), response.body) 265 | }, reason => callback(reason.error, null, null)) 266 | } 267 | if (isSurge) $httpClient.get(options, (error, response, body) => { 268 | callback(error, adapterStatus(response), body) 269 | }) 270 | if (node) { 271 | node.request(options, (error, response, body) => { 272 | callback(error, adapterStatus(response), body) 273 | }) 274 | } 275 | } 276 | const post = (options, callback) => { 277 | if (isQuanX) { 278 | if (typeof options == "string") options = { url: options } 279 | options["method"] = "POST" 280 | $task.fetch(options).then(response => { 281 | callback(null, adapterStatus(response), response.body) 282 | }, reason => callback(reason.error, null, null)) 283 | } 284 | if (isSurge) { 285 | $httpClient.post(options, (error, response, body) => { 286 | callback(error, adapterStatus(response), body) 287 | }) 288 | } 289 | if (node) { 290 | node.request.post(options, (error, response, body) => { 291 | callback(error, adapterStatus(response), body) 292 | }) 293 | } 294 | } 295 | return { isQuanX, isSurge, isResponse, notify, write, read, get, post } 296 | } 297 | 298 | Array.prototype.insert = function (index, item) { 299 | this.splice(index, 0, item); 300 | }; 301 | 302 | Date.prototype.format = function (fmt) { 303 | var o = { 304 | "y+": this.getFullYear(), 305 | "M+": this.getMonth() + 1, 306 | "d+": this.getDate(), 307 | "h+": this.getHours(), 308 | "m+": this.getMinutes(), 309 | "s+": this.getSeconds(), 310 | "q+": Math.floor((this.getMonth() + 3) / 3), 311 | "S+": this.getMilliseconds() 312 | }; 313 | for (var k in o) { 314 | if (new RegExp("(" + k + ")").test(fmt)) { 315 | if (k == "y+") { 316 | fmt = fmt.replace(RegExp.$1, ("" + o[k]).substr(4 - RegExp.$1.length)); 317 | } 318 | else if (k == "S+") { 319 | var lens = RegExp.$1.length; 320 | lens = lens == 1 ? 3 : lens; 321 | fmt = fmt.replace(RegExp.$1, ("00" + o[k]).substr(("" + o[k]).length - 1, lens)); 322 | } 323 | else { 324 | fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 325 | } 326 | } 327 | } 328 | return fmt; 329 | } 330 | -------------------------------------------------------------------------------- /scripts/jd_price_lite.js: -------------------------------------------------------------------------------- 1 | /* 2 | README:https://github.com/yichahucha/surge/tree/master 3 | ^https?://api\.m\.jd\.com/(client\.action|api)\?functionId=(wareBusiness|serverConfig|basicConfig|lite_wareBusiness|pingou_item) 4 | */ 5 | 6 | const path1 = "serverConfig"; 7 | const path2 = "wareBusiness"; 8 | const path2h = "wareBusiness.style"; 9 | const path3 = "basicConfig"; 10 | const path4 = "pingou_item"; 11 | const consolelog = false; 12 | const url = $request.url; 13 | const body = $response.body; 14 | const $tool = tool(); 15 | 16 | let cookie = $tool.getCache("jfCookie") || ""; 17 | let cscheme = $tool.getCache("jfChooseScheme") || "jd"; // "jx","js","jk" 京东、京喜、京东极速版、京东健康 18 | let jsapp = [true, "true"].includes($tool.getCache("jfusejsapp")) || false; // 对极速版是否也跳转 app,注意即使跳转 app,也需要先加入购物车返回再结账,否则无法使用极速版优惠券 19 | let browser = $tool.getCache("chooseBrowser") || "Safari"; 20 | let jfAutoScheme = $tool.getCache("jfAutoScheme"); // 本地不使用 BoxJs 可自行更改 let jfAutoScheme = true / false 21 | let jfConvert = $tool.getCache("jfUseConvert"); 22 | 23 | let chooseScheme; 24 | let chooseBrowser; 25 | switch (cscheme) { 26 | case "jd": 27 | chooseScheme = "openjd"; 28 | break; 29 | case "jx": 30 | chooseScheme = "openapp.jdpingou"; 31 | break; 32 | case "jk": 33 | chooseScheme = "openApp.jdHealth"; 34 | break; 35 | case "js": 36 | if (jsapp) { 37 | chooseScheme = "openjdlite"; 38 | break; 39 | } 40 | case "browser": 41 | chooseScheme = "browser"; 42 | break; 43 | } 44 | switch (browser) { 45 | case "Safari": 46 | chooseBrowser = ""; 47 | break; 48 | case "Alook": 49 | chooseBrowser = "Alook://"; 50 | break; 51 | default: 52 | chooseBrowser = $tool.getCache("jfDIYScheme"); 53 | } 54 | const autoChoose = jfAutoScheme == undefined ? true : [true, "true"].includes(jfAutoScheme); 55 | const useConvert = jfAutoScheme == undefined ? true : [true, "true"].includes(jfConvert); 56 | let autoScheme; 57 | let cookiesArr = [ 58 | $tool.getCache("CookieJD"), 59 | $tool.getCache("CookieJD2"), 60 | ...cookieParse($tool.getCache("CookiesJD") || "[]").map((item) => item.cookie), 61 | ].filter((item) => !!item); 62 | 63 | function cookieParse(str) { 64 | if (typeof str == "string") { 65 | try { 66 | return JSON.parse(str); 67 | } catch (e) { 68 | console.log(e); 69 | $.msg($.name, "", "请勿随意在BoxJs输入框修改内容\n建议通过脚本去获取cookie"); 70 | return []; 71 | } 72 | } 73 | } 74 | 75 | cookie = cookie ? cookie : cookiesArr[0]; 76 | 77 | if (url.indexOf(path1) != -1) { 78 | let obj = JSON.parse(body); 79 | delete obj.serverConfig.httpdns; 80 | delete obj.serverConfig.dnsvip; 81 | delete obj.serverConfig.dnsvip_v6; 82 | $done({ body: JSON.stringify(obj) }); 83 | } 84 | 85 | if (url.indexOf(path3) != -1) { 86 | let obj = JSON.parse(body); 87 | let JDHttpToolKit = obj.data.JDHttpToolKit; 88 | let jCommandConfig = obj.data.jCommandConfig; 89 | if (JDHttpToolKit) { 90 | delete obj.data.JDHttpToolKit.httpdns; 91 | delete obj.data.JDHttpToolKit.dnsvipV6; 92 | } 93 | if (jCommandConfig) { 94 | delete obj.data.jCommandConfig.httpdnsConfig; 95 | } 96 | $done({ body: JSON.stringify(obj) }); 97 | } 98 | 99 | if (url.indexOf(path2) != -1 || url.indexOf(path4) != -1) { 100 | if (!$tool.isQuanX) { 101 | $done({ body }); 102 | } 103 | let obj = JSON.parse(body); 104 | const floors = obj.floors; 105 | const commodity_info = floors[floors.length - 1]; 106 | const others = obj.others; 107 | const domain = obj.domain; 108 | const shareUrl = 109 | url.indexOf(path4) != -1 110 | ? domain.h5Url 111 | : url.indexOf(path2h) != -1 112 | ? others.property.shareUrl 113 | : commodity_info.data.property.shareUrl; 114 | autoScheme = url.indexOf(path2h) != -1 ? "openApp.jdHealth" : "openjd"; 115 | //const scheme = !autoChoose ? chooseScheme : url.indexOf(path4) != -1 ? "openapp.jdpingou" : url.indexOf(path2h) != -1 ? "openApp.jdHealth" : url.indexOf("lite_"+path3) != -1 ? "openjdlite" : "openjd"; 116 | let getHistory = request_history_price(shareUrl); 117 | let convertURL = ""; 118 | let jxconvertURL = ""; 119 | if (useConvert) { 120 | convertURL = convert(shareUrl); 121 | jxconvertURL = url.indexOf(path4) != -1 ? convert(shareUrl, true) : undefined; 122 | } 123 | Promise.all([getHistory, convertURL, jxconvertURL]) 124 | .then((detail) => { 125 | let msg = ""; 126 | if (detail[1] == "useJXOrigin") detail[1] = detail[2]; 127 | if (detail[0].lower_tip) { 128 | msg += detail[0].lower_tip; 129 | let convertmsg = detail[1].convertURL ? detail[1].msg : detail[1]; 130 | msg += convertmsg ? "\n" + convertmsg : ""; 131 | msg += "\n" + detail[0].historydetail; 132 | } else { 133 | let convertmsg = detail[1].convertURL ? detail[1].msg : detail[1]; 134 | msg += convertmsg ? convertmsg + "\n" : ""; 135 | msg += detail[0]; 136 | } 137 | let oprnUrl = detail[1].convertURL ? detail[1].convertURL : ""; 138 | $tool.notify("", "", msg, oprnUrl); 139 | }) 140 | .finally(() => { 141 | $done({ body }); 142 | }); 143 | } 144 | 145 | function lowerMsgs(data) { 146 | const lower = data.lowerPriceyh; 147 | const lowerDate = dateFormat(data.lowerDateyh); 148 | const lowerMsg = "🍵 历史最低到手价:¥" + String(lower) + ` (${lowerDate}) `; 149 | return lowerMsg; 150 | } 151 | 152 | function priceSummary(data) { 153 | let summary = ""; 154 | let listPriceDetail = data.PriceRemark.ListPriceDetail.slice(0, 4); 155 | let list = listPriceDetail.concat(historySummary(data.single)); 156 | list.forEach((item, index) => { 157 | if (item.Name == "双11价格") { 158 | item.Name = "双十一价格"; 159 | } else if (item.Name == "618价格") { 160 | item.Name = "六一八价格"; 161 | } 162 | let price = String(parseInt(item.Price.substr(1))); 163 | summary += `\n${item.Name} ${isNaN(price) ? "-" : "¥" + price} ${item.Date} ${ 164 | item.Difference 165 | }`; 166 | }); 167 | return summary; 168 | } 169 | 170 | function historySummary(single) { 171 | const rexMatch = /\[.*?\]/g; 172 | const rexExec = /\[(.*),(.*),"(.*)".*\]/; 173 | let currentPrice, lowest30, lowest90, lowest180, lowest360; 174 | let list = single.jiagequshiyh.match(rexMatch); 175 | list = list.reverse().slice(0, 360); 176 | list.forEach((item, index) => { 177 | if (item.length > 0) { 178 | const result = rexExec.exec(item); 179 | const dateUTC = new Date(eval(result[1])); 180 | const date = dateUTC.format("yyyy-MM-dd"); 181 | let price = parseFloat(result[2]); 182 | if (index == 0) { 183 | currentPrice = price; 184 | lowest30 = { 185 | Name: "三十天最低", 186 | Price: `¥${String(price)}`, 187 | Date: date, 188 | Difference: difference(currentPrice, price), 189 | price, 190 | }; 191 | lowest90 = { 192 | Name: "九十天最低", 193 | Price: `¥${String(price)}`, 194 | Date: date, 195 | Difference: difference(currentPrice, price), 196 | price, 197 | }; 198 | lowest180 = { 199 | Name: "一百八最低", 200 | Price: `¥${String(price)}`, 201 | Date: date, 202 | Difference: difference(currentPrice, price), 203 | price, 204 | }; 205 | lowest360 = { 206 | Name: "三百六最低", 207 | Price: `¥${String(price)}`, 208 | Date: date, 209 | Difference: difference(currentPrice, price), 210 | price, 211 | }; 212 | } 213 | if (index < 30 && price < lowest30.price) { 214 | lowest30.price = price; 215 | lowest30.Price = `¥${String(price)}`; 216 | lowest30.Date = date; 217 | lowest30.Difference = difference(currentPrice, price); 218 | } 219 | if (index < 90 && price < lowest90.price) { 220 | lowest90.price = price; 221 | lowest90.Price = `¥${String(price)}`; 222 | lowest90.Date = date; 223 | lowest90.Difference = difference(currentPrice, price); 224 | } 225 | if (index < 180 && price < lowest180.price) { 226 | lowest180.price = price; 227 | lowest180.Price = `¥${String(price)}`; 228 | lowest180.Date = date; 229 | lowest180.Difference = difference(currentPrice, price); 230 | } 231 | if (index < 360 && price < lowest360.price) { 232 | lowest360.price = price; 233 | lowest360.Price = `¥${String(price)}`; 234 | lowest360.Date = date; 235 | lowest360.Difference = difference(currentPrice, price); 236 | } 237 | } 238 | }); 239 | return [lowest30, lowest90, lowest180]; 240 | } 241 | 242 | function difference(currentPrice, price) { 243 | let difference = sub(currentPrice, price); 244 | if (difference == 0) { 245 | return "-"; 246 | } else { 247 | return `${difference > 0 ? "↑" : "↓"}${String(difference)}`; 248 | } 249 | } 250 | 251 | function sub(arg1, arg2) { 252 | return add(arg1, -Number(arg2), arguments[2]); 253 | } 254 | 255 | function add(arg1, arg2) { 256 | (arg1 = arg1.toString()), (arg2 = arg2.toString()); 257 | var arg1Arr = arg1.split("."), 258 | arg2Arr = arg2.split("."), 259 | d1 = arg1Arr.length == 2 ? arg1Arr[1] : "", 260 | d2 = arg2Arr.length == 2 ? arg2Arr[1] : ""; 261 | var maxLen = Math.max(d1.length, d2.length); 262 | var m = Math.pow(10, maxLen); 263 | var result = Number(((arg1 * m + arg2 * m) / m).toFixed(maxLen)); 264 | var d = arguments[2]; 265 | return typeof d === "number" ? Number(result.toFixed(d)) : result; 266 | } 267 | 268 | function request_history_price(share_url) { 269 | return new Promise((resolve) => { 270 | let options = { 271 | url: "https://apapia-history.manmanbuy.com/ChromeWidgetServices/WidgetServices.ashx", 272 | headers: { 273 | "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", 274 | "User-Agent": 275 | "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", 276 | }, 277 | body: "methodName=getHistoryTrend&p_url=" + encodeURIComponent(share_url), 278 | }; 279 | $tool.post(options, function (error, response, data) { 280 | if (!error) { 281 | data = JSON.parse(data); 282 | if (consolelog) console.log("Data:\n" + data); 283 | if (data.ok == 1 && data.single) { 284 | const lower = lowerMsgs(data.single); 285 | const detail = priceSummary(data); 286 | const tip = data.PriceRemark.Tip; 287 | let r = {}; 288 | r.lower_tip = `${lower} ${tip}`; 289 | r.historydetail = `${detail.substr(1)}`; 290 | resolve(r); 291 | } 292 | if (data.ok == 0 && data.msg.length > 0) { 293 | let e = `⚠️ ${data.msg}`; 294 | resolve(e); 295 | } 296 | } else { 297 | if (consolelog) console.log("JD History Error:\n" + error); 298 | resolve(); 299 | } 300 | }); 301 | }); 302 | } 303 | 304 | function convert(url, isOriginJXURL) { 305 | return new Promise((resolve) => { 306 | if (!cookiesArr[0]) { 307 | $tool.setCache("false", "jfUseConvert"); 308 | resolve(""); 309 | } else { 310 | let id; 311 | if ( 312 | url.includes("item.m.jd") || 313 | url.includes("item.jd") || 314 | (!autoChoose && chooseScheme == "openApp.jdHealth") 315 | ) { 316 | id = url.match(/(\d+)\.html/)[1]; 317 | url = `https:\/\/item.m.jd.com\/product\/${id}.html`; 318 | } else if (url.includes("m.jingxi") || url.includes("wq.jd.com")) { 319 | id = url.match(/sku=(\d+)/)[1]; 320 | url = `https:\/\/wq.jd.com\/item\/view?sku=${id}`; 321 | if (isOriginJXURL || (!autoChoose && chooseScheme == "openjdlite")) 322 | url = `https:\/\/m.jingxi.com\/item\/jxview?sku=${id}`; 323 | autoScheme = "openapp.jdpingou"; 324 | } else if (url.includes("kpl.m.jd")) { 325 | id = url.match(/wareId=(\d+)/)[1]; 326 | url = `https:\/\/kpl.m.jd.com\/product?wareId=${id}`; 327 | autoScheme = jsapp ? "openjdlite" : "browser"; 328 | } else { 329 | url = url; 330 | //url = url.replace(/\//g, "\\/"); 331 | } 332 | let body = { 333 | funName: "getSuperClickUrl", 334 | param: { 335 | materialInfo: url, 336 | ext1: "200|100_3|", 337 | }, 338 | }; 339 | let t = +new Date(); 340 | let options = { 341 | url: `https://api.m.jd.com/api?functionId=ConvertSuperLink&appid=u&_=${t}&body=${encodeURI( 342 | JSON.stringify(body) 343 | )}&loginType=2`, 344 | headers: { 345 | "Accept-Encoding": "gzip,compress,br,deflate", 346 | Connection: "keep-alive", 347 | Cookie: cookie, 348 | Host: "api.m.jd.com", 349 | Referer: "https://servicewechat.com/wxf463e50cd384beda/114/page-frame.html", 350 | "User-Agent": 351 | "Mozilla/5.0 (iPhone; CPU iPhone OS 13_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.4(0x18000429) NetType/WIFI Language/zh_CN", 352 | "content-type": "application/json", 353 | }, 354 | }; 355 | $tool.get(options, function (err, resp, data) { 356 | if (!err) { 357 | data = JSON.parse(data); 358 | console.log("JD Convert Data:\n" + data); 359 | if (data.code === 200) { 360 | let r = {}; 361 | let scheme = autoChoose ? autoScheme : chooseScheme; 362 | if (data.data.promotionUrl) { 363 | r.msg = `💰返点比率:${data.data.wlCommissionShare} % 预计返利:¥ ${data.data.wlCommission}`; 364 | r.convertURL = 365 | scheme == "browser" 366 | ? chooseBrowser + data.data.promotionUrl 367 | : `${scheme}://virtual?params=%7B%22category%22:%22jump%22,%22des%22:%22m%22,%22sourceValue%22:%22babel-act%22,%22sourceType%22:%22babel%22,%22url%22:%22${data.data.promotionUrl}%22%7D`; 368 | } else { 369 | r.msg = `该商品暂无详细返利信息,${data.data.formatContext.trim()}`; 370 | r.convertURL = 371 | scheme == "browser" 372 | ? chooseBrowser + data.data.originalContext 373 | : `${scheme}://virtual?params=%7B%22category%22:%22jump%22,%22des%22:%22m%22,%22sourceValue%22:%22babel-act%22,%22sourceType%22:%22babel%22,%22url%22:%22${data.data.originalContext}%22%7D`; 374 | } 375 | resolve(r); 376 | } else if (data.code === 105) { 377 | if (autoScheme == "openapp.jdpingou") resolve("useJXOrigin"); 378 | else resolve(""); 379 | } else if (data.code === 430) { 380 | $tool.setCache("false", "jfUseConvert"); 381 | resolve(""); 382 | } else { 383 | resolve(JSON.stringify(data)); 384 | } 385 | } else { 386 | console.log("JD Convert Error:\n" + err); 387 | resolve(); 388 | } 389 | }); 390 | } 391 | }); 392 | } 393 | 394 | function dateFormat(cellval) { 395 | const date = new Date(parseInt(cellval.replace("/Date(", "").replace(")/", ""), 10)); 396 | const month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1; 397 | const currentDate = date.getDate() < 10 ? "0" + date.getDate() : date.getDate(); 398 | return date.getFullYear() + "-" + month + "-" + currentDate; 399 | } 400 | 401 | function tool() { 402 | const isSurge = typeof $httpClient != "undefined"; 403 | const isQuanX = typeof $task != "undefined"; 404 | const node = (() => { 405 | if (typeof require == "function") { 406 | const request = require("request"); 407 | return { request }; 408 | } else { 409 | return null; 410 | } 411 | })(); 412 | const notify = (title, subtitle, content, open_url) => { 413 | if (isSurge) { 414 | let opts = {}; 415 | if (open_url) opts["url"] = open_url; 416 | if (JSON.stringify(opts) == "{}") { 417 | $notification.post(title, subtitle, content); 418 | } else { 419 | $notification.post(title, subtitle, content, opts); 420 | } 421 | } 422 | if (isQuanX) { 423 | let opts = {}; 424 | if (open_url) opts["open-url"] = open_url; 425 | if (JSON.stringify(opts) == "{}") { 426 | $notify(title, subtitle, content); 427 | } else { 428 | $notify(title, subtitle, content, opts); 429 | } 430 | } 431 | if (isLoon) { 432 | let opts = {}; 433 | if (open_url) opts["openUrl"] = open_url; 434 | if (JSON.stringify(opts) == "{}") { 435 | $notification.post(title, subtitle, content); 436 | } else { 437 | $notification.post(title, subtitle, content, opts); 438 | } 439 | } 440 | if (node) { 441 | let content_Node = content + (open_url == undefined ? "" : `\n\n跳转链接:${open_url}`); 442 | console.log(`${title}\n${subtitle}\n${content_Node}\n\n`); 443 | } 444 | }; 445 | const setCache = (value, key) => { 446 | if (isQuanX) return $prefs.setValueForKey(value, key); 447 | if (isSurge) return $persistentStore.write(value, key); 448 | }; 449 | const getCache = (key) => { 450 | if (isQuanX) return $prefs.valueForKey(key); 451 | if (isSurge) return $persistentStore.read(key); 452 | }; 453 | const adapterStatus = (response) => { 454 | if (response.status) { 455 | response["statusCode"] = response.status; 456 | } else if (response.statusCode) { 457 | response["status"] = response.statusCode; 458 | } 459 | return response; 460 | }; 461 | const get = (options, callback) => { 462 | if (isQuanX) { 463 | if (typeof options == "string") options = { url: options }; 464 | options["method"] = "GET"; 465 | $task.fetch(options).then( 466 | (response) => { 467 | callback(null, adapterStatus(response), response.body); 468 | }, 469 | (reason) => callback(reason.error, null, null) 470 | ); 471 | } 472 | if (isSurge) 473 | $httpClient.get(options, (error, response, body) => { 474 | callback(error, adapterStatus(response), body); 475 | }); 476 | if (node) { 477 | node.request(options, (error, response, body) => { 478 | callback(error, adapterStatus(response), body); 479 | }); 480 | } 481 | }; 482 | const post = (options, callback) => { 483 | if (isQuanX) { 484 | if (typeof options == "string") options = { url: options }; 485 | options["method"] = "POST"; 486 | $task.fetch(options).then( 487 | (response) => { 488 | callback(null, adapterStatus(response), response.body); 489 | }, 490 | (reason) => callback(reason.error, null, null) 491 | ); 492 | } 493 | if (isSurge) { 494 | $httpClient.post(options, (error, response, body) => { 495 | callback(error, adapterStatus(response), body); 496 | }); 497 | } 498 | if (node) { 499 | node.request.post(options, (error, response, body) => { 500 | callback(error, adapterStatus(response), body); 501 | }); 502 | } 503 | }; 504 | return { isQuanX, isSurge, notify, setCache, getCache, get, post }; 505 | } 506 | 507 | Array.prototype.insert = function (index, item) { 508 | this.splice(index, 0, item); 509 | }; 510 | 511 | Date.prototype.format = function (fmt) { 512 | var o = { 513 | "y+": this.getFullYear(), 514 | "M+": this.getMonth() + 1, 515 | "d+": this.getDate(), 516 | "h+": this.getHours(), 517 | "m+": this.getMinutes(), 518 | "s+": this.getSeconds(), 519 | "q+": Math.floor((this.getMonth() + 3) / 3), 520 | "S+": this.getMilliseconds(), 521 | }; 522 | for (var k in o) { 523 | if (new RegExp("(" + k + ")").test(fmt)) { 524 | if (k == "y+") { 525 | fmt = fmt.replace(RegExp.$1, ("" + o[k]).substr(4 - RegExp.$1.length)); 526 | } else if (k == "S+") { 527 | var lens = RegExp.$1.length; 528 | lens = lens == 1 ? 3 : lens; 529 | fmt = fmt.replace(RegExp.$1, ("00" + o[k]).substr(("" + o[k]).length - 1, lens)); 530 | } else { 531 | fmt = fmt.replace( 532 | RegExp.$1, 533 | RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length) 534 | ); 535 | } 536 | } 537 | } 538 | return fmt; 539 | }; 540 | -------------------------------------------------------------------------------- /scripts/jd_reject_logout.js: -------------------------------------------------------------------------------- 1 | const $ = new API('reject'); 2 | console.log($request); 3 | if ($request) { 4 | const contentLength = `${ 5 | $request.headers['Content-Length'] || $request.headers['content-length'] 6 | }`; 7 | if (contentLength === '1048' || contentLength === '976' || contentLength === "1068") { 8 | console.log('检测到京东登出,重写 body'); 9 | 10 | }else {$.done({});} 11 | }else {$.done({});} 12 | 13 | 14 | function ENV() { 15 | const isQX = typeof $task !== 'undefined'; 16 | const isLoon = typeof $loon !== 'undefined'; 17 | const isSurge = typeof $httpClient !== 'undefined' && !isLoon; 18 | const isJSBox = typeof require == 'function' && typeof $jsbox != 'undefined'; 19 | const isNode = typeof require == 'function' && !isJSBox; 20 | const isRequest = typeof $request !== 'undefined'; 21 | const isScriptable = typeof importModule !== 'undefined'; 22 | return { isQX, isLoon, isSurge, isNode, isJSBox, isRequest, isScriptable }; 23 | } 24 | 25 | function HTTP(defaultOptions = { baseURL: '' }) { 26 | const { isQX, isLoon, isSurge, isScriptable, isNode } = ENV(); 27 | const methods = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS', 'PATCH']; 28 | const URL_REGEX = 29 | /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/; 30 | 31 | function send(method, options) { 32 | options = typeof options === 'string' ? { url: options } : options; 33 | const baseURL = defaultOptions.baseURL; 34 | if (baseURL && !URL_REGEX.test(options.url || '')) { 35 | options.url = baseURL ? baseURL + options.url : options.url; 36 | } 37 | options = { ...defaultOptions, ...options }; 38 | const timeout = options.timeout; 39 | const events = { 40 | ...{ 41 | onRequest: () => {}, 42 | onResponse: (resp) => resp, 43 | onTimeout: () => {}, 44 | }, 45 | ...options.events, 46 | }; 47 | 48 | events.onRequest(method, options); 49 | 50 | let worker; 51 | if (isQX) { 52 | worker = $task.fetch({ method, ...options }); 53 | } else if (isLoon || isSurge || isNode) { 54 | worker = new Promise((resolve, reject) => { 55 | const request = isNode ? require('request') : $httpClient; 56 | request[method.toLowerCase()](options, (err, response, body) => { 57 | if (err) reject(err); 58 | else 59 | resolve({ 60 | statusCode: response.status || response.statusCode, 61 | headers: response.headers, 62 | body, 63 | }); 64 | }); 65 | }); 66 | } else if (isScriptable) { 67 | const request = new Request(options.url); 68 | request.method = method; 69 | request.headers = options.headers; 70 | request.body = options.body; 71 | worker = new Promise((resolve, reject) => { 72 | request 73 | .loadString() 74 | .then((body) => { 75 | resolve({ 76 | statusCode: request.response.statusCode, 77 | headers: request.response.headers, 78 | body, 79 | }); 80 | }) 81 | .catch((err) => reject(err)); 82 | }); 83 | } 84 | 85 | let timeoutid; 86 | const timer = timeout 87 | ? new Promise((_, reject) => { 88 | timeoutid = setTimeout(() => { 89 | events.onTimeout(); 90 | return reject( 91 | `${method} URL: ${options.url} exceeds the timeout ${timeout} ms`, 92 | ); 93 | }, timeout); 94 | }) 95 | : null; 96 | 97 | return ( 98 | timer 99 | ? Promise.race([timer, worker]).then((res) => { 100 | clearTimeout(timeoutid); 101 | return res; 102 | }) 103 | : worker 104 | ).then((resp) => events.onResponse(resp)); 105 | } 106 | 107 | const http = {}; 108 | methods.forEach( 109 | (method) => 110 | (http[method.toLowerCase()] = (options) => send(method, options)), 111 | ); 112 | return http; 113 | } 114 | 115 | function API(name = 'untitled', debug = false) { 116 | const { isQX, isLoon, isSurge, isNode, isJSBox, isScriptable } = ENV(); 117 | return new (class { 118 | constructor(name, debug) { 119 | this.name = name; 120 | this.debug = debug; 121 | 122 | this.http = HTTP(); 123 | this.env = ENV(); 124 | 125 | this.node = (() => { 126 | if (isNode) { 127 | const fs = require('fs'); 128 | 129 | return { 130 | fs, 131 | }; 132 | } else { 133 | return null; 134 | } 135 | })(); 136 | this.initCache(); 137 | 138 | const delay = (t, v) => 139 | new Promise(function (resolve) { 140 | setTimeout(resolve.bind(null, v), t); 141 | }); 142 | 143 | Promise.prototype.delay = function (t) { 144 | return this.then(function (v) { 145 | return delay(t, v); 146 | }); 147 | }; 148 | } 149 | 150 | // persistance 151 | 152 | // initialize cache 153 | initCache() { 154 | if (isQX) this.cache = JSON.parse($prefs.valueForKey(this.name) || '{}'); 155 | if (isLoon || isSurge) 156 | this.cache = JSON.parse($persistentStore.read(this.name) || '{}'); 157 | 158 | if (isNode) { 159 | // create a json for root cache 160 | let fpath = 'root.json'; 161 | if (!this.node.fs.existsSync(fpath)) { 162 | this.node.fs.writeFileSync( 163 | fpath, 164 | JSON.stringify({}), 165 | { flag: 'wx' }, 166 | (err) => console.log(err), 167 | ); 168 | } 169 | this.root = {}; 170 | 171 | // create a json file with the given name if not exists 172 | fpath = `${this.name}.json`; 173 | if (!this.node.fs.existsSync(fpath)) { 174 | this.node.fs.writeFileSync( 175 | fpath, 176 | JSON.stringify({}), 177 | { flag: 'wx' }, 178 | (err) => console.log(err), 179 | ); 180 | this.cache = {}; 181 | } else { 182 | this.cache = JSON.parse( 183 | this.node.fs.readFileSync(`${this.name}.json`), 184 | ); 185 | } 186 | } 187 | } 188 | 189 | // store cache 190 | persistCache() { 191 | const data = JSON.stringify(this.cache); 192 | if (isQX) $prefs.setValueForKey(data, this.name); 193 | if (isLoon || isSurge) $persistentStore.write(data, this.name); 194 | if (isNode) { 195 | this.node.fs.writeFileSync( 196 | `${this.name}.json`, 197 | data, 198 | { flag: 'w' }, 199 | (err) => console.log(err), 200 | ); 201 | this.node.fs.writeFileSync( 202 | 'root.json', 203 | JSON.stringify(this.root), 204 | { flag: 'w' }, 205 | (err) => console.log(err), 206 | ); 207 | } 208 | } 209 | 210 | write(data, key) { 211 | this.log(`SET ${key}`); 212 | if (key.indexOf('#') !== -1) { 213 | key = key.substr(1); 214 | if (isSurge || isLoon) { 215 | return $persistentStore.write(data, key); 216 | } 217 | if (isQX) { 218 | return $prefs.setValueForKey(data, key); 219 | } 220 | if (isNode) { 221 | this.root[key] = data; 222 | } 223 | } else { 224 | this.cache[key] = data; 225 | } 226 | this.persistCache(); 227 | } 228 | 229 | read(key) { 230 | this.log(`READ ${key}`); 231 | if (key.indexOf('#') !== -1) { 232 | key = key.substr(1); 233 | if (isSurge || isLoon) { 234 | return $persistentStore.read(key); 235 | } 236 | if (isQX) { 237 | return $prefs.valueForKey(key); 238 | } 239 | if (isNode) { 240 | return this.root[key]; 241 | } 242 | } else { 243 | return this.cache[key]; 244 | } 245 | } 246 | 247 | delete(key) { 248 | this.log(`DELETE ${key}`); 249 | if (key.indexOf('#') !== -1) { 250 | key = key.substr(1); 251 | if (isSurge || isLoon) { 252 | return $persistentStore.write(null, key); 253 | } 254 | if (isQX) { 255 | return $prefs.removeValueForKey(key); 256 | } 257 | if (isNode) { 258 | delete this.root[key]; 259 | } 260 | } else { 261 | delete this.cache[key]; 262 | } 263 | this.persistCache(); 264 | } 265 | 266 | // notification 267 | notify(title, subtitle = '', content = '', options = {}) { 268 | const openURL = options['open-url']; 269 | const mediaURL = options['media-url']; 270 | 271 | if (isQX) $notify(title, subtitle, content, options); 272 | if (isSurge) { 273 | $notification.post( 274 | title, 275 | subtitle, 276 | content + `${mediaURL ? '\n多媒体:' + mediaURL : ''}`, 277 | { 278 | url: openURL, 279 | }, 280 | ); 281 | } 282 | if (isLoon) { 283 | let opts = {}; 284 | if (openURL) opts['openUrl'] = openURL; 285 | if (mediaURL) opts['mediaUrl'] = mediaURL; 286 | if (JSON.stringify(opts) == '{}') { 287 | $notification.post(title, subtitle, content); 288 | } else { 289 | $notification.post(title, subtitle, content, opts); 290 | } 291 | } 292 | if (isNode || isScriptable) { 293 | const content_ = 294 | content + 295 | (openURL ? `\n点击跳转: ${openURL}` : '') + 296 | (mediaURL ? `\n多媒体: ${mediaURL}` : ''); 297 | if (isJSBox) { 298 | const push = require('push'); 299 | push.schedule({ 300 | title: title, 301 | body: (subtitle ? subtitle + '\n' : '') + content_, 302 | }); 303 | } else { 304 | console.log(`${title}\n${subtitle}\n${content_}\n\n`); 305 | } 306 | } 307 | } 308 | 309 | // other helper functions 310 | log(msg) { 311 | if (this.debug) console.log(msg); 312 | } 313 | 314 | info(msg) { 315 | console.log(msg); 316 | } 317 | 318 | error(msg) { 319 | console.log('ERROR: ' + msg); 320 | } 321 | 322 | wait(millisec) { 323 | return new Promise((resolve) => setTimeout(resolve, millisec)); 324 | } 325 | 326 | done(value = {}) { 327 | if (isQX || isLoon || isSurge) { 328 | $done(value); 329 | } else if (isNode && !isJSBox) { 330 | if (typeof $context !== 'undefined') { 331 | $context.headers = value.headers; 332 | $context.statusCode = value.statusCode; 333 | $context.body = value.body; 334 | } 335 | } 336 | } 337 | })(name, debug); 338 | } 339 | -------------------------------------------------------------------------------- /scripts/jf_Convert.js: -------------------------------------------------------------------------------- 1 | /* 2 | README:https://github.com/yichahucha/surge/tree/master 3 | ^https?://api\.m\.jd\.com/(client\.action|api)\?functionId=(wareBusiness|serverConfig|basicConfig|lite_wareBusiness|pingou_item) 4 | */ 5 | 6 | const path1 = "serverConfig"; 7 | const path2 = "wareBusiness"; 8 | const path2h = "wareBusiness.style"; 9 | const path3 = "basicConfig"; 10 | const path4 = "pingou_item"; 11 | const consolelog = false; 12 | const url = $request.url; 13 | const body = $response.body; 14 | const $tool = tool(); 15 | 16 | let cookie = $tool.getCache("jfCookie") || ""; 17 | let cscheme = $tool.getCache("jfChooseScheme") || "jd"; // "jx","js","jk" 京东、京喜、京东极速版、京东健康 18 | let jsapp = [true, "true"].includes($tool.getCache("jfusejsapp")) || false; // 对极速版是否也跳转 app,注意即使跳转 app,也需要先加入购物车返回再结账,否则无法使用极速版优惠券 19 | let browser = $tool.getCache("chooseBrowser") || "Safari"; 20 | let jfAutoScheme = $tool.getCache("jfAutoScheme"); // 本地不使用 BoxJs 可自行更改 let jfAutoScheme = true / false 21 | let jfConvert = $tool.getCache("jfUseConvert"); 22 | 23 | let chooseScheme; 24 | let chooseBrowser; 25 | switch (cscheme) { 26 | case "jd": 27 | chooseScheme = "openjd"; 28 | break; 29 | case "jx": 30 | chooseScheme = "openapp.jdpingou"; 31 | break; 32 | case "jk": 33 | chooseScheme = "openApp.jdHealth"; 34 | break; 35 | case "js": 36 | if (jsapp) { 37 | chooseScheme = "openjdlite"; 38 | break; 39 | } 40 | case "browser": 41 | chooseScheme = "browser"; 42 | break; 43 | } 44 | switch (browser) { 45 | case "Safari": 46 | chooseBrowser = ""; 47 | break; 48 | case "Alook": 49 | chooseBrowser = "Alook://"; 50 | break; 51 | default: 52 | chooseBrowser = $tool.getCache("jfDIYScheme"); 53 | } 54 | const autoChoose = jfAutoScheme == undefined ? true : [true, "true"].includes(jfAutoScheme); 55 | const useConvert = jfAutoScheme == undefined ? true : [true, "true"].includes(jfConvert); 56 | let autoScheme; 57 | let cookiesArr = [ 58 | $tool.getCache("CookieJD"), 59 | $tool.getCache("CookieJD2"), 60 | ...cookieParse($tool.getCache("CookiesJD") || "[]").map((item) => item.cookie), 61 | ].filter((item) => !!item); 62 | 63 | function cookieParse(str) { 64 | if (typeof str == "string") { 65 | try { 66 | return JSON.parse(str); 67 | } catch (e) { 68 | console.log(e); 69 | $.msg($.name, "", "请勿随意在BoxJs输入框修改内容\n建议通过脚本去获取cookie"); 70 | return []; 71 | } 72 | } 73 | } 74 | 75 | cookie = cookie ? cookie : cookiesArr[0]; 76 | 77 | if (url.indexOf(path1) != -1) { 78 | let obj = JSON.parse(body); 79 | delete obj.serverConfig.httpdns; 80 | delete obj.serverConfig.dnsvip; 81 | delete obj.serverConfig.dnsvip_v6; 82 | $done({ body: JSON.stringify(obj) }); 83 | } 84 | 85 | if (url.indexOf(path3) != -1) { 86 | let obj = JSON.parse(body); 87 | let JDHttpToolKit = obj.data.JDHttpToolKit; 88 | let jCommandConfig = obj.data.jCommandConfig; 89 | if (JDHttpToolKit) { 90 | delete obj.data.JDHttpToolKit.httpdns; 91 | delete obj.data.JDHttpToolKit.dnsvipV6; 92 | } 93 | if (jCommandConfig) { 94 | delete obj.data.jCommandConfig.httpdnsConfig; 95 | } 96 | $done({ body: JSON.stringify(obj) }); 97 | } 98 | 99 | if (url.indexOf(path2) != -1 || url.indexOf(path4) != -1) { 100 | if (!$tool.isQuanX) { 101 | $done({ body }); 102 | } 103 | let obj = JSON.parse(body); 104 | const floors = obj.floors; 105 | const commodity_info = floors[floors.length - 1]; 106 | const others = obj.others; 107 | const domain = obj.domain; 108 | const shareUrl = 109 | url.indexOf(path4) != -1 110 | ? domain.h5Url 111 | : url.indexOf(path2h) != -1 112 | ? others.property.shareUrl 113 | : commodity_info.data.property.shareUrl; 114 | autoScheme = url.indexOf(path2h) != -1 ? "openApp.jdHealth" : "openjd"; 115 | //const scheme = !autoChoose ? chooseScheme : url.indexOf(path4) != -1 ? "openapp.jdpingou" : url.indexOf(path2h) != -1 ? "openApp.jdHealth" : url.indexOf("lite_"+path3) != -1 ? "openjdlite" : "openjd"; 116 | let getHistory = ""; 117 | let convertURL = ""; 118 | let jxconvertURL = ""; 119 | if (useConvert) { 120 | convertURL = convert(shareUrl); 121 | jxconvertURL = url.indexOf(path4) != -1 ? convert(shareUrl, true) : undefined; 122 | } 123 | Promise.all([getHistory, convertURL, jxconvertURL]) 124 | .then((detail) => { 125 | let msg = ""; 126 | if (detail[1] == "useJXOrigin") detail[1] = detail[2]; 127 | let convertmsg = detail[1].convertURL ? detail[1].msg : detail[1]; 128 | msg += convertmsg ? convertmsg : "该商品暂无详细返利信息"; 129 | let oprnUrl = detail[1].convertURL ? detail[1].convertURL : ""; 130 | $tool.notify("京粉转链", "", msg, oprnUrl); 131 | }) 132 | .finally(() => { 133 | $done({ body }); 134 | }); 135 | } 136 | 137 | function convert(url, isOriginJXURL) { 138 | return new Promise((resolve) => { 139 | if (!cookiesArr[0]) { 140 | $tool.setCache("false", "jfUseConvert"); 141 | resolve(""); 142 | } else { 143 | let id; 144 | if ( 145 | url.includes("item.m.jd") || 146 | url.includes("item.jd") || 147 | (!autoChoose && chooseScheme == "openApp.jdHealth") 148 | ) { 149 | id = url.match(/(\d+)\.html/)[1]; 150 | url = `https:\/\/item.m.jd.com\/product\/${id}.html`; 151 | } else if (url.includes("m.jingxi") || url.includes("wq.jd.com")) { 152 | id = url.match(/sku=(\d+)/)[1]; 153 | url = `https:\/\/wq.jd.com\/item\/view?sku=${id}`; 154 | if (isOriginJXURL || (!autoChoose && chooseScheme == "openjdlite")) 155 | url = `https:\/\/m.jingxi.com\/item\/jxview?sku=${id}`; 156 | autoScheme = "openapp.jdpingou"; 157 | } else if (url.includes("kpl.m.jd")) { 158 | id = url.match(/wareId=(\d+)/)[1]; 159 | url = `https:\/\/kpl.m.jd.com\/product?wareId=${id}`; 160 | autoScheme = jsapp ? "openjdlite" : "browser"; 161 | } else { 162 | url = url; 163 | //url = url.replace(/\//g, "\\/"); 164 | } 165 | let body = { 166 | funName: "getSuperClickUrl", 167 | param: { 168 | materialInfo: url, 169 | ext1: "200|100_3|", 170 | }, 171 | }; 172 | let t = +new Date(); 173 | let options = { 174 | url: `https://api.m.jd.com/api?functionId=ConvertSuperLink&appid=u&_=${t}&body=${encodeURI( 175 | JSON.stringify(body) 176 | )}&loginType=2`, 177 | headers: { 178 | "Accept-Encoding": "gzip,compress,br,deflate", 179 | Connection: "keep-alive", 180 | Cookie: cookie, 181 | Host: "api.m.jd.com", 182 | Referer: "https://servicewechat.com/wxf463e50cd384beda/114/page-frame.html", 183 | "User-Agent": 184 | "Mozilla/5.0 (iPhone; CPU iPhone OS 13_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.4(0x18000429) NetType/WIFI Language/zh_CN", 185 | "content-type": "application/json", 186 | }, 187 | }; 188 | $tool.get(options, function (err, resp, data) { 189 | if (!err) { 190 | data = JSON.parse(data); 191 | console.log("JD Convert Data:\n" + data); 192 | if (data.code === 200) { 193 | let r = {}; 194 | let scheme = autoChoose ? autoScheme : chooseScheme; 195 | if (data.data.promotionUrl) { 196 | r.msg = `💰返点比率:${data.data.wlCommissionShare} % 预计返利:¥ ${data.data.wlCommission}`; 197 | r.convertURL = 198 | scheme == "browser" 199 | ? chooseBrowser + data.data.promotionUrl 200 | : `${scheme}://virtual?params=%7B%22category%22:%22jump%22,%22des%22:%22m%22,%22sourceValue%22:%22babel-act%22,%22sourceType%22:%22babel%22,%22url%22:%22${data.data.promotionUrl}%22%7D`; 201 | } else { 202 | r.msg = `该商品暂无详细返利信息,${data.data.formatContext.trim()}`; 203 | r.convertURL = 204 | scheme == "browser" 205 | ? chooseBrowser + data.data.originalContext 206 | : `${scheme}://virtual?params=%7B%22category%22:%22jump%22,%22des%22:%22m%22,%22sourceValue%22:%22babel-act%22,%22sourceType%22:%22babel%22,%22url%22:%22${data.data.originalContext}%22%7D`; 207 | } 208 | resolve(r); 209 | } else if (data.code === 105) { 210 | if (autoScheme == "openapp.jdpingou") resolve("useJXOrigin"); 211 | else resolve(""); 212 | } else if (data.code === 430) { 213 | $tool.setCache("false", "jfUseConvert"); 214 | resolve(""); 215 | } else { 216 | resolve(JSON.stringify(data)); 217 | } 218 | } else { 219 | console.log("JD Convert Error:\n" + err); 220 | resolve(); 221 | } 222 | }); 223 | } 224 | }); 225 | } 226 | 227 | function dateFormat(cellval) { 228 | const date = new Date(parseInt(cellval.replace("/Date(", "").replace(")/", ""), 10)); 229 | const month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1; 230 | const currentDate = date.getDate() < 10 ? "0" + date.getDate() : date.getDate(); 231 | return date.getFullYear() + "-" + month + "-" + currentDate; 232 | } 233 | 234 | function tool() { 235 | const isSurge = typeof $httpClient != "undefined"; 236 | const isQuanX = typeof $task != "undefined"; 237 | const node = (() => { 238 | if (typeof require == "function") { 239 | const request = require("request"); 240 | return { request }; 241 | } else { 242 | return null; 243 | } 244 | })(); 245 | const notify = (title, subtitle, content, open_url) => { 246 | if (isSurge) { 247 | let opts = {}; 248 | if (open_url) opts["url"] = open_url; 249 | if (JSON.stringify(opts) == "{}") { 250 | $notification.post(title, subtitle, content); 251 | } else { 252 | $notification.post(title, subtitle, content, opts); 253 | } 254 | } 255 | if (isQuanX) { 256 | let opts = {}; 257 | if (open_url) opts["open-url"] = open_url; 258 | if (JSON.stringify(opts) == "{}") { 259 | $notify(title, subtitle, content); 260 | } else { 261 | $notify(title, subtitle, content, opts); 262 | } 263 | } 264 | if (isLoon) { 265 | let opts = {}; 266 | if (open_url) opts["openUrl"] = open_url; 267 | if (JSON.stringify(opts) == "{}") { 268 | $notification.post(title, subtitle, content); 269 | } else { 270 | $notification.post(title, subtitle, content, opts); 271 | } 272 | } 273 | if (node) { 274 | let content_Node = content + (open_url == undefined ? "" : `\n\n跳转链接:${open_url}`); 275 | console.log(`${title}\n${subtitle}\n${content_Node}\n\n`); 276 | } 277 | }; 278 | const setCache = (value, key) => { 279 | if (isQuanX) return $prefs.setValueForKey(value, key); 280 | if (isSurge) return $persistentStore.write(value, key); 281 | }; 282 | const getCache = (key) => { 283 | if (isQuanX) return $prefs.valueForKey(key); 284 | if (isSurge) return $persistentStore.read(key); 285 | }; 286 | const adapterStatus = (response) => { 287 | if (response.status) { 288 | response["statusCode"] = response.status; 289 | } else if (response.statusCode) { 290 | response["status"] = response.statusCode; 291 | } 292 | return response; 293 | }; 294 | const get = (options, callback) => { 295 | if (isQuanX) { 296 | if (typeof options == "string") options = { url: options }; 297 | options["method"] = "GET"; 298 | $task.fetch(options).then( 299 | (response) => { 300 | callback(null, adapterStatus(response), response.body); 301 | }, 302 | (reason) => callback(reason.error, null, null) 303 | ); 304 | } 305 | if (isSurge) 306 | $httpClient.get(options, (error, response, body) => { 307 | callback(error, adapterStatus(response), body); 308 | }); 309 | if (node) { 310 | node.request(options, (error, response, body) => { 311 | callback(error, adapterStatus(response), body); 312 | }); 313 | } 314 | }; 315 | const post = (options, callback) => { 316 | if (isQuanX) { 317 | if (typeof options == "string") options = { url: options }; 318 | options["method"] = "POST"; 319 | $task.fetch(options).then( 320 | (response) => { 321 | callback(null, adapterStatus(response), response.body); 322 | }, 323 | (reason) => callback(reason.error, null, null) 324 | ); 325 | } 326 | if (isSurge) { 327 | $httpClient.post(options, (error, response, body) => { 328 | callback(error, adapterStatus(response), body); 329 | }); 330 | } 331 | if (node) { 332 | node.request.post(options, (error, response, body) => { 333 | callback(error, adapterStatus(response), body); 334 | }); 335 | } 336 | }; 337 | return { isQuanX, isSurge, notify, setCache, getCache, get, post }; 338 | } 339 | 340 | Array.prototype.insert = function (index, item) { 341 | this.splice(index, 0, item); 342 | }; 343 | 344 | Date.prototype.format = function (fmt) { 345 | var o = { 346 | "y+": this.getFullYear(), 347 | "M+": this.getMonth() + 1, 348 | "d+": this.getDate(), 349 | "h+": this.getHours(), 350 | "m+": this.getMinutes(), 351 | "s+": this.getSeconds(), 352 | "q+": Math.floor((this.getMonth() + 3) / 3), 353 | "S+": this.getMilliseconds(), 354 | }; 355 | for (var k in o) { 356 | if (new RegExp("(" + k + ")").test(fmt)) { 357 | if (k == "y+") { 358 | fmt = fmt.replace(RegExp.$1, ("" + o[k]).substr(4 - RegExp.$1.length)); 359 | } else if (k == "S+") { 360 | var lens = RegExp.$1.length; 361 | lens = lens == 1 ? 3 : lens; 362 | fmt = fmt.replace(RegExp.$1, ("00" + o[k]).substr(("" + o[k]).length - 1, lens)); 363 | } else { 364 | fmt = fmt.replace( 365 | RegExp.$1, 366 | RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length) 367 | ); 368 | } 369 | } 370 | } 371 | return fmt; 372 | }; 373 | -------------------------------------------------------------------------------- /scripts/weixin110.js: -------------------------------------------------------------------------------- 1 | /* 2 | 在微信中打开淘宝等被屏蔽链接,点击 Surge/QuantumultX 通知跳转到 Safari 或淘宝 App 3 | by @HotKids & @XIAO_KOP,修改自 @江湖中人 4 | 5 | /********************* 6 | QuantumultX 远程脚本配置: 7 | ********************** 8 | [rewrite_local] 9 | ^https?:\/\/weixin110\.qq\.com\/cgi-bin\/mmspamsupport-bin\/newredirectconfirmcgi url script-response-body https://raw.githubusercontent.com/Fokit/Quantumult-X/main/scripts/weixin110.js 10 | [mitm] 11 | hostname= weixin110.qq.com 12 | ********************** 13 | Surge 4.2.0+ 脚本配置: 14 | ********************** 15 | [Script] 16 | tbopener.js = type=http-response,pattern=^https?:\/\/weixin110\.qq\.com\/cgi-bin\/mmspamsupport-bin\/newredirectconfirmcgi,script-path=https://raw.githubusercontent.com/Fokit/Quantumult-X/main/scripts/weixin110.js 17 | [MITM] 18 | hostname= weixin110.qq.com 19 | */ 20 | 21 | var str = ($response.body); 22 | 23 | str = str.match(/://(\S*)”}/)[1].replace(///g, ’/‘).replace(/&/g, ’&‘).split(“\”“)[0] 24 | let opener = str.indexOf(”m.tb.cn“) != -1 ? ”taobao://“ + str: ($response.body) 25 | //console.log(str); 26 | 27 | const $ = new cmp() 28 | 29 | if (str.indexOf(”m.tb.cn“) != -1) { 30 | $.notify(``, ”“, ”🛍️点击打开淘宝“, opener) 31 | } else if (str.indexOf(”如需浏览“)) { 32 | $.notify(``,”“, ”🔗点击打开链接“, ”https://“+str) 33 | } 34 | 35 | $done({body: $response.body}); 36 | 37 | function cmp() { 38 | _isQuanX = typeof $task != ”undefined“ 39 | _isLoon = typeof $loon != ”undefined“ 40 | _isSurge = typeof $httpClient != ”undefined“ && !_isLoon 41 | this.notify = (title, subtitle, message, url) => { 42 | if (_isLoon) $notification.post(title, subtitle, message, url) 43 | if (_isQuanX) $notify(title, subtitle, message, { ”open-url“: url }) 44 | if (_isSurge) $notification.post(title, subtitle, message, { url: url }) 45 | } 46 | } 47 | --------------------------------------------------------------------------------