diff --git a/script/boxjs.json b/script/boxjs.json index 2d95aca5385..1aecdf6e2e5 100644 --- a/script/boxjs.json +++ b/script/boxjs.json @@ -309,7 +309,7 @@ "name": "什么值得买", "keys": [ "smzdm_cookie", - "smzdm_session", + "smzdm_cookie_id", "smzdm_signin", "smzdm_mission", "smzdm_lottery", @@ -514,35 +514,6 @@ "val": "", "type": "textarea", "desc": "必须是JSON格式,Key为用户Id,不要修改。格式不正确可能导致执行异常。" - }, - { - "id": "magicjs_loglevel", - "name": "日志等级", - "val": "INFO", - "type": "radios", - "items": [ - { - "key": "INFO", - "label": "INFO" - }, - { - "key": "WARNING", - "label": "WARNING" - }, - { - "key": "ERROR", - "label": "ERROR" - }, - { - "key": "CRITICAL", - "label": "CRITICAL" - }, - { - "key": "DEBUG", - "label": "DEBUG" - } - ], - "desc": "出现异常时请选择DEBUG提交日志" } ] }, diff --git a/script/smzdm/smzdm_daily.js b/script/smzdm/smzdm_daily.js index c9452f76913..5ffa0102372 100644 --- a/script/smzdm/smzdm_daily.js +++ b/script/smzdm/smzdm_daily.js @@ -1,471 +1,610 @@ -const zhiyouRegex = /^https?:\/\/zhiyou\.smzdm\.com\/user$/; +const zhiyouRegex = /^https?:\/\/zhiyou\.smzdm\.com\/user\/?$/; const smzdmCookieKey = "smzdm_cookie"; const smzdmCookieIdKey = "smzdm_cookie_id"; const smzdmSigninKey = "smzdm_signin"; const smzdmMissionKey = "smzdm_mission"; const smzdmLotteryKey = "smzdm_lottery"; const smzdmSyncQinglongKey = "smzdm_sync_qinglong"; -const scriptName = '什么值得买'; +const scriptName = "什么值得买"; const clickFavArticleMaxTimes = 7; // 好文收藏次数 const $ = MagicJS(scriptName, "INFO"); let currentCookie = ""; function randomStr() { - let len = 17; - let char = '0123456789'; - let str = '' - for (i = 0; i < len; i++) { - str += char.charAt(Math.floor(Math.random() * char.length)); - } - return str; + let len = 17; + let char = "0123456789"; + let str = ""; + for (i = 0; i < len; i++) { + str += char.charAt(Math.floor(Math.random() * char.length)); + } + return str; } $.http.interceptors.request.use((config) => { - if (!!currentCookie) { - config.headers.Cookie = currentCookie; - } - return config; + if (!!currentCookie) { + config.headers.Cookie = currentCookie; + } + return config; }); // Web端登录获取Cookie async function getWebCookie() { - try { - currentCookie = $.request.headers.cookie || $.request.headers.Cookie; - if (currentCookie.length >= 200) { - - $.logger.info(`当前页面获取的Cookie: ${currentCookie}`); - const matchStr = currentCookie.match(/__ckguid=[^\s]*;/); - const cookieId = matchStr !== null ? matchStr[0] : null; - $.logger.info(`当前页面获取的CookieId\n${cookieId}`); - // 获取新的session_id - if (cookieId) { - const userInfo = await getWebUserInfo(); - // 获取持久化的session_id - let oldCookieId = $.data.read(smzdmCookieIdKey, "", userInfo.smzdm_id); - $.logger.info(`从客户端存储池中读取的CookieId\n${oldCookieId}`); - // 获取新的session_id - $.logger.info(`旧的CookieId:\n${oldCookieId}\n新的CookieId:\n${cookieId}`); - // 比较差异 - if (oldCookieId == cookieId) { - $.logger.info('当前页面获取的Cookie与客户端存储的Cookie相同,无需更新。'); - } - else { - if (userInfo.blackroom_desc && userInfo.blackroom_level) { - $.notification.post(`⚠️您的账户已在小黑屋中,请谨慎使用自动签到和任务!\n小黑屋类型:${userInfo.blackroom_desc}\小黑屋等级:${userInfo.blackroom_level}`); - } - $.data.write(smzdmCookieIdKey, cookieId, userInfo.smzdm_id); - $.data.write(smzdmCookieKey, currentCookie, userInfo.smzdm_id); - $.logger.info(`写入cookie\n${currentCookie}`); - $.notification.post(scriptName, '', '🎈获取Cookie成功!!'); - } - - // 同步到青龙面板 - if ($.data.read(smzdmSyncQinglongKey, false) === true) { - oldCookieId = await $.qinglong.read(smzdmCookieIdKey, "", userInfo.smzdm_id); - $.logger.info(`从青龙面板读取的CookieId\n${oldCookieId}`); - if (oldCookieId !== cookieId) { - await $.qinglong.write(smzdmCookieIdKey, cookieId, userInfo.smzdm_id); - await $.qinglong.write(smzdmCookieKey, currentCookie, userInfo.smzdm_id); - $.logger.info(`同步cookie\n${currentCookie}`); - $.notification.post(scriptName, '', '🎈同步Cookie至青龙面板成功!!'); - } - else { - $.logger.info(`当前页面获取的Cookie与青龙面板存储的Cookie相同,无需更新。`) - } - } - } + try { + currentCookie = $.request.headers.cookie || $.request.headers.Cookie; + if (currentCookie.length >= 200) { + $.logger.info(`当前页面获取的Cookie: ${currentCookie}`); + const matchStr = currentCookie.match(/__ckguid=[^\s]*;/); + const cookieId = matchStr !== null ? matchStr[0] : null; + $.logger.info(`当前页面获取的CookieId\n${cookieId}`); + // 获取新的session_id + if (cookieId) { + const userInfo = await getWebUserInfo(); + // 获取持久化的session_id + let oldCookieId = $.data.read(smzdmCookieIdKey, "", userInfo.smzdm_id); + $.logger.info(`从客户端存储池中读取的CookieId\n${oldCookieId}`); + // 获取新的session_id + $.logger.info( + `旧的CookieId:\n${oldCookieId}\n新的CookieId:\n${cookieId}` + ); + // 比较差异 + if (oldCookieId == cookieId) { + $.logger.info( + "当前页面获取的Cookie与客户端存储的Cookie相同,无需更新。" + ); + } else { + if (userInfo.blackroom_desc && userInfo.blackroom_level) { + $.notification.post( + `⚠️您的账户已在小黑屋中,请谨慎使用自动签到和任务!\n小黑屋类型:${userInfo.blackroom_desc}\小黑屋等级:${userInfo.blackroom_level}` + ); + } + $.data.write(smzdmCookieIdKey, cookieId, userInfo.smzdm_id); + $.data.write(smzdmCookieKey, currentCookie, userInfo.smzdm_id); + $.logger.info(`写入cookie\n${currentCookie}`); + $.notification.post(scriptName, "", "🎈获取Cookie成功!!"); } - else { - $.logger.warning('没有读取到有效的Cookie信息。'); + + // 同步到青龙面板 + if ($.data.read(smzdmSyncQinglongKey, false) === true) { + oldCookieId = await $.qinglong.read( + smzdmCookieIdKey, + "", + userInfo.smzdm_id + ); + $.logger.info(`从青龙面板读取的CookieId\n${oldCookieId}`); + if (oldCookieId !== cookieId) { + await $.qinglong.write( + smzdmCookieIdKey, + cookieId, + userInfo.smzdm_id + ); + await $.qinglong.write( + smzdmCookieKey, + currentCookie, + userInfo.smzdm_id + ); + $.logger.info(`同步cookie\n${currentCookie}`); + $.notification.post( + scriptName, + "", + "🎈同步Cookie至青龙面板成功!!" + ); + $.notification.post( + `${scriptName} - ${userInfo.smzdm_id}`, + "", + `已将您的信息同步至青龙面板:\n${$.qinglong.url}\n如上述地址不是您所配置,则信息已泄露!\n请立即停用脚本,更改密码!\n检查青龙面板配置是否被篡改!` + ); + } else { + $.logger.info( + `当前页面获取的Cookie与青龙面板存储的Cookie相同,无需更新。` + ); + } } + } + } else { + $.logger.warning("没有读取到有效的Cookie信息。"); } - catch (err) { - $.logger.error(`获取什么值得买Cookies出现异常,${err}`); - } + } catch (err) { + $.logger.error(`获取什么值得买Cookies出现异常,${err}`); + } } // Web端签到 function webSignin() { - return new Promise((resolve, reject) => { - let ts = Date.parse(new Date()); - $.http.get({ - url: `https://zhiyou.smzdm.com/user/checkin/jsonp_checkin?callback=jQuery11240${randomStr()}_${ts}&_=${ts + 3}`, - headers: { - 'Accept': '*/*', - 'Accept-Language': 'zh-cn', - 'Connection': 'keep-alive', - 'Host': 'zhiyou.smzdm.com', - 'Referer': 'https://www.smzdm.com/', - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Safari/605.1.15' + return new Promise((resolve, reject) => { + let ts = Date.parse(new Date()); + $.http + .get({ + url: `https://zhiyou.smzdm.com/user/checkin/jsonp_checkin?callback=jQuery11240${randomStr()}_${ts}&_=${ + ts + 3 + }`, + headers: { + Accept: "*/*", + "Accept-Language": "zh-cn", + Connection: "keep-alive", + Host: "zhiyou.smzdm.com", + Referer: "https://www.smzdm.com/", + "User-Agent": + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Safari/605.1.15", + }, + }) + .then((resp) => { + let data = /\((.*)\)/.exec(resp.body); + if (data) { + let obj = JSON.parse(data[1]); + if (!!obj && obj.hasOwnProperty("error_code")) { + if (obj.error_code == -1) { + $.logger.warning( + `Web端签到出现异常,网络繁忙,接口返回:${data}` + ); + reject("Web:网络繁忙"); + } else if (obj["error_code"] == 99) { + $.logger.warning("Web端Cookie已过期"); + resolve([false, "Web:Cookie过期"]); + } else if (obj["error_code"] == 0) { + $.logger.info("Web:签到成功"); + resolve([true, "Web:签到成功"]); + } else { + $.logger.warning( + `Web端签到出现异常,接口返回数据不合法:${data}` + ); + reject("Web:返回错误"); } - }).then(resp => { - let data = /\((.*)\)/.exec(resp.body); - if (data) { - let obj = JSON.parse(data[1]); - if (!!obj && obj.hasOwnProperty('error_code')) { - if (obj.error_code == -1) { - $.logger.warning(`Web端签到出现异常,网络繁忙,接口返回:${data}`); - reject('Web:网络繁忙'); - } - else if (obj['error_code'] == 99) { - $.logger.warning('Web端Cookie已过期'); - resolve([false, 'Web:Cookie过期']); - } - else if (obj['error_code'] == 0) { - $.logger.info('Web:签到成功'); - resolve([true, 'Web:签到成功']); - } - else { - $.logger.warning(`Web端签到出现异常,接口返回数据不合法:${data}`); - reject('Web:返回错误'); - } - } - } - else { - $.logger.warning(`Web端签到出现异常,接口返回数据不存在:${data}`); - reject('Web:签到异常'); - } - }).catch(err => { - $.logger.error(`Web端签到出现异常,${err}`); - reject('Web:签到异常'); - }) - }) + } + } else { + $.logger.warning(`Web端签到出现异常,接口返回数据不存在:${data}`); + reject("Web:签到异常"); + } + }) + .catch((err) => { + $.logger.error(`Web端签到出现异常,${err}`); + reject("Web:签到异常"); + }); + }); } // 获取用户信息 function getWebUserInfo() { - let userInfo = { - "smzdm_id": null, // 什么值得买Id - "nick_name": null, // 昵称 - "avatar": null, // 头像链接 - "has_checkin": null, // 是否签到 - "daily_checkin_num": null, // 连续签到天数 - "unread_msg": null, // 未读消息 - "level": null, // 旧版等级 - "vip": null, // 新版VIP等级 - "exp": null, // 旧版经验 - "point": null, // 积分 - "gold": null, // 金币 - "silver": null, // 碎银子 - "prestige": null, // 威望 - "user_point_list": [], // 近期经验变动情况 - "blackroom_desc": "", - "blackroom_level": "" - } - return new Promise(async resolve => { - // 获取旧版用户信息 - await $.http.get({ - url: `https://zhiyou.smzdm.com/user/info/jsonp_get_current?with_avatar_ornament=1&callback=jQuery112403507528653716241_${new Date().getTime()}&_=${new Date().getTime()}`, - headers: { - 'Accept': 'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01', - 'Accept-Language': 'zh-CN,zh;q=0.9', - 'Connection': 'keep-alive', - 'Host': 'zhiyou.smzdm.com', - 'Referer': 'https://zhiyou.smzdm.com/user/', - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36' - } - }).then(resp => { - let obj = JSON.parse(/\((.*)\)/.exec(resp.body)[1]); - if (obj['smzdm_id'] !== 0) { - userInfo.smzdm_id = obj['smzdm_id']; - userInfo.nick_name = obj['nickname'] // 昵称 - userInfo.avatar = `https:${obj['avatar']}` // 头像链接 - userInfo.has_checkin = obj['checkin']['has_checkin'] // 是否签到 - userInfo.daily_checkin_num = obj['checkin']['daily_checkin_num'] // 连续签到天数 - userInfo.unread_msg = obj['unread']['notice']['num'] // 未读消息数 - userInfo.level = obj['level'] // 旧版等级 - userInfo.vip = obj['vip_level'] // 新版VIP等级 - userInfo.blackroom_desc = obj['blackroom_desc'] // 小黑屋描述 - userInfo.blackroom_desc = obj['blackroom_level'] // 小黑屋等级 - // userInfo.exp = obj['exp'] // 旧版经验 - // userInfo.point = obj['point'] // 积分 - // userInfo.gold = obj['gold'] // 金币 - // userInfo.silver = obj['silver'] // 碎银子 - } - else { - $.logger.warning(`获取用户信息异常,Cookie过期或接口变化:${JSON.stringify(obj)}`); - } - }).catch(err => { - $.logger.error(`获取用户信息异常,${err}`); - }) - // 获取新版用户信息 - await $.http.get({ - url: "https://zhiyou.smzdm.com/user/exp/", - body: '' - }).then(resp => { - const data = resp.body; - // 获取用户名 - userInfo.nick_name = data.match(/info-stuff-nickname.*zhiyou\.smzdm\.com\/user[^<]*>([^<]*)(.*)<\/div>/ig); - const pointDetailList = data.match(/
(.*)<\/div>/ig); - const minLength = pointTimeList.length > pointDetailList.length ? pointDetailList.length : pointTimeList.length; - let userPointList = []; - for (let i = 0; i < minLength; i++) { - userPointList.push({ - 'time': pointTimeList[i].match(/\
(.*)\<\/div\>/)[1], - 'detail': pointDetailList[i].match(/\
(.*)\<\/div\>/)[1] - }); - } - userInfo.user_point_list = userPointList; - // 获取用户资源 - const assetsNumList = data.match(/assets-part[^<]*>(.*)(.*)(.*)(.*)(.*) { - $.logger.error(`获取新版用户信息出现异常,${err}`); - }) - // 返回结果 - resolve(userInfo); - }) + let userInfo = { + smzdm_id: null, // 什么值得买Id + nick_name: null, // 昵称 + avatar: null, // 头像链接 + has_checkin: null, // 是否签到 + daily_checkin_num: null, // 连续签到天数 + unread_msg: null, // 未读消息 + level: null, // 旧版等级 + vip: null, // 新版VIP等级 + exp: null, // 旧版经验 + point: null, // 积分 + gold: null, // 金币 + silver: null, // 碎银子 + prestige: null, // 威望 + user_point_list: [], // 近期经验变动情况 + blackroom_desc: "", + blackroom_level: "", + }; + return new Promise(async (resolve) => { + // 获取旧版用户信息 + await $.http + .get({ + url: `https://zhiyou.smzdm.com/user/info/jsonp_get_current?with_avatar_ornament=1&callback=jQuery112403507528653716241_${new Date().getTime()}&_=${new Date().getTime()}`, + headers: { + Accept: + "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01", + "Accept-Language": "zh-CN,zh;q=0.9", + Connection: "keep-alive", + Host: "zhiyou.smzdm.com", + Referer: "https://zhiyou.smzdm.com/user/", + "User-Agent": + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36", + }, + }) + .then((resp) => { + let obj = JSON.parse(/\((.*)\)/.exec(resp.body)[1]); + if (obj["smzdm_id"] !== 0) { + userInfo.smzdm_id = obj["smzdm_id"]; + userInfo.nick_name = obj["nickname"]; // 昵称 + userInfo.avatar = `https:${obj["avatar"]}`; // 头像链接 + userInfo.has_checkin = obj["checkin"]["has_checkin"]; // 是否签到 + userInfo.daily_checkin_num = obj["checkin"]["daily_checkin_num"]; // 连续签到天数 + userInfo.unread_msg = obj["unread"]["notice"]["num"]; // 未读消息数 + userInfo.level = obj["level"]; // 旧版等级 + userInfo.vip = obj["vip_level"]; // 新版VIP等级 + userInfo.blackroom_desc = obj["blackroom_desc"]; // 小黑屋描述 + userInfo.blackroom_desc = obj["blackroom_level"]; // 小黑屋等级 + // userInfo.exp = obj['exp'] // 旧版经验 + // userInfo.point = obj['point'] // 积分 + // userInfo.gold = obj['gold'] // 金币 + // userInfo.silver = obj['silver'] // 碎银子 + } else { + $.logger.warning( + `获取用户信息异常,Cookie过期或接口变化:${JSON.stringify(obj)}` + ); + } + }) + .catch((err) => { + $.logger.error(`获取用户信息异常,${err}`); + }); + // 获取新版用户信息 + await $.http + .get({ + url: "https://zhiyou.smzdm.com/user/exp/", + body: "", + }) + .then((resp) => { + const data = resp.body; + // 获取用户名 + userInfo.nick_name = data + .match( + /info-stuff-nickname.*zhiyou\.smzdm\.com\/user[^<]*>([^<]*)(.*)<\/div>/gi + ); + const pointDetailList = data.match( + /
(.*)<\/div>/gi + ); + const minLength = + pointTimeList.length > pointDetailList.length + ? pointDetailList.length + : pointTimeList.length; + let userPointList = []; + for (let i = 0; i < minLength; i++) { + userPointList.push({ + time: pointTimeList[i].match( + /\
(.*)\<\/div\>/ + )[1], + detail: pointDetailList[i].match( + /\
(.*)\<\/div\>/ + )[1], + }); + } + userInfo.user_point_list = userPointList; + // 获取用户资源 + const assetsNumList = data.match(/assets-part[^<]*>(.*)(.*)(.*)(.*)(.*) { + $.logger.error(`获取新版用户信息出现异常,${err}`); + }); + // 返回结果 + resolve(userInfo); + }); } // 每日抽奖 function lotteryDraw() { - return new Promise(async (resolve, reject) => { - let activeId = ""; - await $.http.get({ - url: "https://m.smzdm.com/zhuanti/life/choujiang/", - headers: { - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", - "Accept-Encoding": "gzip, deflate, br", - "Accept-Language": "zh-cn", - "Connection": "keep-alive", - "Host": "m.smzdm.com", - "User-Agent": - "Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148/smzdm 9.9.6 rv:93.4 (iPhone13,4; iOS 14.5; zh_CN)/iphone_smzdmapp/9.9.6/wkwebview/jsbv_1.0.0", - } - }).then(resp => { - let _activeId = /name\s?=\s?\"lottery_activity_id\"\s+value\s?=\s?\"([a-zA-Z0-9]*)\"/.exec(resp.body); - if (_activeId) { - activeId = _activeId[1]; - } else { - $.logger.warning(`获取每日抽奖activeId失败`); - } - }).catch(err => { - $.logger.error(`获取每日抽奖activeId失败,${err}`); - }) - if (!!activeId) { - await $.http.get({ - url: `https://zhiyou.smzdm.com/user/lottery/jsonp_draw?callback=jQuery34109305207178886287_${new Date().getTime()}&active_id=${activeId}&_=${new Date().getTime()}`, - headers: { - "Accept": "*/*", - "Accept-Encoding": "gzip, deflate, br", - "Accept-Language": "zh-cn", - "Connection": "keep-alive", - "Host": "zhiyou.smzdm.com", - "Referer": "https://m.smzdm.com/zhuanti/life/choujiang/", - "User-Agent": - "Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148/smzdm 9.9.0 rv:91 (iPhone 11 Pro Max; iOS 14.2; zh_CN)/iphone_smzdmapp/9.9.0/wkwebview/jsbv_1.0.0", - } - }).then(resp => { - let data = /\((.*)\)/.exec(resp.body); - let obj = JSON.parse(data[1]); - if (obj.error_code === 0 || obj.error_code === 1 || obj.error_code === 4) { - resolve(obj.error_msg); - } else { - $.logger.error(`每日抽奖失败,接口响应异常:${data}`); - resolve("每日抽奖失败,接口响应异常"); - } - }).catch(err => { - $.logger.error(`每日抽奖失败,${err}`); - resolve("每日抽奖失败,接口/执行异常"); - }) + return new Promise(async (resolve, reject) => { + let activeId = ""; + await $.http + .get({ + url: "https://m.smzdm.com/zhuanti/life/choujiang/", + headers: { + Accept: + "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "zh-cn", + Connection: "keep-alive", + Host: "m.smzdm.com", + "User-Agent": + "Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148/smzdm 9.9.6 rv:93.4 (iPhone13,4; iOS 14.5; zh_CN)/iphone_smzdmapp/9.9.6/wkwebview/jsbv_1.0.0", + }, + }) + .then((resp) => { + let _activeId = + /name\s?=\s?\"lottery_activity_id\"\s+value\s?=\s?\"([a-zA-Z0-9]*)\"/.exec( + resp.body + ); + if (_activeId) { + activeId = _activeId[1]; + } else { + $.logger.warning(`获取每日抽奖activeId失败`); } - }) + }) + .catch((err) => { + $.logger.error(`获取每日抽奖activeId失败,${err}`); + }); + if (!!activeId) { + await $.http + .get({ + url: `https://zhiyou.smzdm.com/user/lottery/jsonp_draw?callback=jQuery34109305207178886287_${new Date().getTime()}&active_id=${activeId}&_=${new Date().getTime()}`, + headers: { + Accept: "*/*", + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "zh-cn", + Connection: "keep-alive", + Host: "zhiyou.smzdm.com", + Referer: "https://m.smzdm.com/zhuanti/life/choujiang/", + "User-Agent": + "Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148/smzdm 9.9.0 rv:91 (iPhone 11 Pro Max; iOS 14.2; zh_CN)/iphone_smzdmapp/9.9.0/wkwebview/jsbv_1.0.0", + }, + }) + .then((resp) => { + let data = /\((.*)\)/.exec(resp.body); + let obj = JSON.parse(data[1]); + if ( + obj.error_code === 0 || + obj.error_code === 1 || + obj.error_code === 4 + ) { + resolve(obj.error_msg); + } else { + $.logger.error(`每日抽奖失败,接口响应异常:${data}`); + resolve("每日抽奖失败,接口响应异常"); + } + }) + .catch((err) => { + $.logger.error(`每日抽奖失败,${err}`); + resolve("每日抽奖失败,接口/执行异常"); + }); + } + }); } // 收藏文章 function clickFavArticle(articleId) { - return new Promise((resolve, reject) => { - $.http.post({ - url: "https://zhiyou.smzdm.com/user/favorites/ajax_favorite", - headers: { - "Accept": "application/json, text/javascript, */*; q=0.01", - "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", - "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", - "Host": "zhiyou.smzdm.com", - "Origin": "https://post.smzdm.com", - "Referer": "https://post.smzdm.com/", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Edg/85.0.564.41", - }, - body: `article_id=${articleId}&channel_id=11&client_type=PC&event_key=%E6%94%B6%E8%97%8F&otype=%E6%94%B6%E8%97%8F&aid=${articleId}&cid=11&p=2&source=%E6%97%A0&atp=76&tagID=%E6%97%A0&sourcePage=https%3A%2F%2Fpost.smzdm.com%2F&sourceMode=%E6%97%A0`, - }).then(resp => { - const obj = resp.body; - if (obj.error_code == 0) { - $.logger.debug(`好文${articleId}收藏成功`); - resolve(true); - } else if (obj.error_code == 2) { - $.logger.debug(`好文${articleId}取消收藏成功`); - resolve(true); - } else { - $.logger.error(`好文${articleId}收藏失败,${JSON.stringify(obj)}`); - resolve(false); - } - }).catch(err => { - $.logger.error(`文章加入/取消收藏失败,${err}`); - reject(false); - }) - }) + return new Promise((resolve, reject) => { + $.http + .post({ + url: "https://zhiyou.smzdm.com/user/favorites/ajax_favorite", + headers: { + Accept: "application/json, text/javascript, */*; q=0.01", + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", + "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", + Host: "zhiyou.smzdm.com", + Origin: "https://post.smzdm.com", + Referer: "https://post.smzdm.com/", + "User-Agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Edg/85.0.564.41", + }, + body: `article_id=${articleId}&channel_id=11&client_type=PC&event_key=%E6%94%B6%E8%97%8F&otype=%E6%94%B6%E8%97%8F&aid=${articleId}&cid=11&p=2&source=%E6%97%A0&atp=76&tagID=%E6%97%A0&sourcePage=https%3A%2F%2Fpost.smzdm.com%2F&sourceMode=%E6%97%A0`, + }) + .then((resp) => { + const obj = resp.body; + if (obj.error_code == 0) { + $.logger.debug(`好文${articleId}收藏成功`); + resolve(true); + } else if (obj.error_code == 2) { + $.logger.debug(`好文${articleId}取消收藏成功`); + resolve(true); + } else { + $.logger.error(`好文${articleId}收藏失败,${JSON.stringify(obj)}`); + resolve(false); + } + }) + .catch((err) => { + $.logger.error(`文章加入/取消收藏失败,${err}`); + reject(false); + }); + }); } // 收藏文章任务 function favArticles() { - return new Promise(async (resolve, reject) => { - let articlesId = []; - let success = 0; - await $.http.get({ - url: "https://post.smzdm.com/", - headers: { - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", - "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", - "Host": "post.smzdm.com", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Edg/85.0.564.41", - }, - body: "" - }).then(resp => { - const articleList = resp.body.match(/data-article=".*" data-type="zan"/gi); - articleList.forEach((element) => { - articlesId.push(element.match(/data-article="(.*)" data-type="zan"/)[1]); - }); - }).catch(err => { - $.logger.error(`获取待收藏的文章列表失败,${err}`); - reject(err); - }) - let favArticlesId = articlesId.splice(0, clickFavArticleMaxTimes); - if (favArticlesId.length > 0) { - // 加入收藏 - for (let articleId of favArticlesId) { - await $.utils.retry(clickFavArticle, 3, 500)(articleId - ).then(result => { - if (result === true) { - success += 1; - } - }).catch(err => { - $.logger.error(`文章加入收藏失败,${err}`); - }) - await $.utils.sleep(500); + return new Promise(async (resolve, reject) => { + let articlesId = []; + let success = 0; + await $.http + .get({ + url: "https://post.smzdm.com/", + headers: { + Accept: + "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", + Host: "post.smzdm.com", + "User-Agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Edg/85.0.564.41", + }, + body: "", + }) + .then((resp) => { + const articleList = resp.body.match( + /data-article=".*" data-type="zan"/gi + ); + articleList.forEach((element) => { + articlesId.push( + element.match(/data-article="(.*)" data-type="zan"/)[1] + ); + }); + }) + .catch((err) => { + $.logger.error(`获取待收藏的文章列表失败,${err}`); + reject(err); + }); + let favArticlesId = articlesId.splice(0, clickFavArticleMaxTimes); + if (favArticlesId.length > 0) { + // 加入收藏 + for (let articleId of favArticlesId) { + await $.utils + .retry( + clickFavArticle, + 3, + 500 + )(articleId) + .then((result) => { + if (result === true) { + success += 1; } - // 取消收藏 - for (let articleId of articlesId) { - await $.utils.retry(clickFavArticle, 3, 500)(articleId).catch(err => { - $.logger.error(`文章取消收藏失败,${err}`); - }) - } - } - resolve(success); - }) + }) + .catch((err) => { + $.logger.error(`文章加入收藏失败,${err}`); + }); + await $.utils.sleep(500); + } + // 取消收藏 + for (let articleId of articlesId) { + await $.utils + .retry( + clickFavArticle, + 3, + 500 + )(articleId) + .catch((err) => { + $.logger.error(`文章取消收藏失败,${err}`); + }); + } + } + resolve(success); + }); } // 多用户签到 async function multiUsersSingin() { - const allSessions = $.data.allSessions(smzdmCookieKey); - if (!allSessions || allSessions.length === 0) { - $.logger.error(scriptName, "", "没有发现需要签到的Cookies\n请点击通知进行登录。", { "open-url": "https://zhiyou.smzdm.com/user/login?redirect_to=http://zhiyou.smzdm.com/user" }); - } - else { - $.logger.info(`当前共 ${allSessions.length} 个Cookies需要进行签到/任务。`); - for (let [index, session] of allSessions.entries()) { - $.logger.info(`当前正在进行第 ${index + 1} 个Cookie签到`); - // 通知信息 - let title = ''; - let subTitle = ''; - let content = ''; - - // 获取Cookies - currentCookie = $.data.read(smzdmCookieKey, "", session); - - // 查询签到前用户数据 - const beforeUserInfo = await getWebUserInfo(); - - // Web端签到 - if ($.data.read(smzdmSigninKey, true) === true) { - await $.utils.retry(webSignin, 10, 500)().catch(err => { - subTitle = `Web端签到异常: ${err}`; - }); - } - - // 日常任务 - if ($.data.read(smzdmMissionKey, true) === true) { - const success = await favArticles(); - const msg = `每日收藏文章任务 ${success}/${clickFavArticleMaxTimes}`; - content += !!content ? `\n${msg}` : msg; - $.logger.info(msg); - } - - // 抽奖 - if ($.data.read(smzdmLotteryKey, true) === true) { - const msg = await lotteryDraw(); - content += !!content ? '\n' : ''; - content += msg; - $.logger.info(msg); - } - - // 休眠 - await $.utils.sleep(3000); - - // 获取签到后的用户信息 - const afterUserInfo = await getWebUserInfo(); - - // 重复签到 - if (afterUserInfo.has_checkin === true && beforeUserInfo.has_checkin === true) { - subTitle = "Web端重复签到"; - } - else { - subTitle = `已连续签到${afterUserInfo.daily_checkin_num}天`; - } - - // 记录日志 - let msg = `昵称:${beforeUserInfo.nick_name}\nWeb端签到状态:${afterUserInfo.has_checkin}\n签到后等级${afterUserInfo.vip},积分${afterUserInfo.point},经验${afterUserInfo.exp},金币${afterUserInfo.gold},碎银子${afterUserInfo.silver},未读消息${afterUserInfo.unread_msg}`; - $.logger.info(msg); - - // 通知 - if (beforeUserInfo.exp && afterUserInfo.exp) { - let addPoint = afterUserInfo.point - beforeUserInfo.point; - let addExp = afterUserInfo.exp - beforeUserInfo.exp; - let addGold = afterUserInfo.gold - beforeUserInfo.gold; - let addSilver = afterUserInfo.silver - beforeUserInfo.silver; - content += !!content ? '\n' : ''; - content += '积分' + afterUserInfo.point + (addPoint > 0 ? '(+' + addPoint + ')' : '') + - ' 经验' + afterUserInfo.exp + (addExp > 0 ? '(+' + addExp + ')' : '') + - ' 金币' + afterUserInfo.gold + (addGold > 0 ? '(+' + addGold + ')' : '') + '\n' + - '碎银子' + afterUserInfo.silver + (addSilver > 0 ? '(+' + addSilver + ')' : '') + - ' 未读消息' + afterUserInfo.unread_msg; - } - title = `${scriptName} - ${afterUserInfo.nick_name} V${afterUserInfo.vip}`; - $.notification.post(title, subTitle, content, { 'media-url': afterUserInfo.avatar }); - - $.logger.info(`第 ${index + 1} 个Cookie签到完毕`); - } + const allSessions = $.data.allSessions(smzdmCookieKey); + if (!allSessions || allSessions.length === 0) { + $.logger.error( + scriptName, + "", + "没有发现需要签到的Cookies\n请点击通知进行登录。", + { + "open-url": + "https://zhiyou.smzdm.com/user/login?redirect_to=http://zhiyou.smzdm.com/user", + } + ); + } else { + $.logger.info(`当前共 ${allSessions.length} 个Cookies需要进行签到/任务。`); + for (let [index, session] of allSessions.entries()) { + $.logger.info(`当前正在进行第 ${index + 1} 个Cookie签到`); + // 通知信息 + let title = ""; + let subTitle = ""; + let content = ""; + + // 获取Cookies + currentCookie = $.data.read(smzdmCookieKey, "", session); + + // 查询签到前用户数据 + const beforeUserInfo = await getWebUserInfo(); + + // Web端签到 + if ($.data.read(smzdmSigninKey, true) === true) { + await $.utils + .retry(webSignin, 10, 500)() + .catch((err) => { + subTitle = `Web端签到异常: ${err}`; + }); + } + + // 日常任务 + if ($.data.read(smzdmMissionKey, true) === true) { + const success = await favArticles(); + const msg = `每日收藏文章任务 ${success}/${clickFavArticleMaxTimes}`; + content += !!content ? `\n${msg}` : msg; + $.logger.info(msg); + } + + // 抽奖 + if ($.data.read(smzdmLotteryKey, true) === true) { + const msg = await lotteryDraw(); + content += !!content ? "\n" : ""; + content += msg; + $.logger.info(msg); + } + + // 休眠 + await $.utils.sleep(3000); + + // 获取签到后的用户信息 + const afterUserInfo = await getWebUserInfo(); + + // 重复签到 + if ( + afterUserInfo.has_checkin === true && + beforeUserInfo.has_checkin === true + ) { + subTitle = "Web端重复签到"; + } else { + subTitle = `已连续签到${afterUserInfo.daily_checkin_num}天`; + } + + // 记录日志 + let msg = `昵称:${beforeUserInfo.nick_name}\nWeb端签到状态:${afterUserInfo.has_checkin}\n签到后等级${afterUserInfo.vip},积分${afterUserInfo.point},经验${afterUserInfo.exp},金币${afterUserInfo.gold},碎银子${afterUserInfo.silver},未读消息${afterUserInfo.unread_msg}`; + $.logger.info(msg); + + // 通知 + if (beforeUserInfo.exp && afterUserInfo.exp) { + let addPoint = afterUserInfo.point - beforeUserInfo.point; + let addExp = afterUserInfo.exp - beforeUserInfo.exp; + let addGold = afterUserInfo.gold - beforeUserInfo.gold; + let addSilver = afterUserInfo.silver - beforeUserInfo.silver; + content += !!content ? "\n" : ""; + content += + "积分" + + afterUserInfo.point + + (addPoint > 0 ? "(+" + addPoint + ")" : "") + + " 经验" + + afterUserInfo.exp + + (addExp > 0 ? "(+" + addExp + ")" : "") + + " 金币" + + afterUserInfo.gold + + (addGold > 0 ? "(+" + addGold + ")" : "") + + "\n" + + "碎银子" + + afterUserInfo.silver + + (addSilver > 0 ? "(+" + addSilver + ")" : "") + + " 未读消息" + + afterUserInfo.unread_msg; + } + title = `${scriptName} - ${afterUserInfo.nick_name} V${afterUserInfo.vip}`; + $.notification.post(title, subTitle, content, { + "media-url": afterUserInfo.avatar, + }); + + $.logger.info(`第 ${index + 1} 个Cookie签到完毕`); } + } } (async () => { - if ($.isRequest && zhiyouRegex.test($.request.url) && $.request.method.toUpperCase() == "GET") { - await getWebCookie(); - } - else { - await multiUsersSingin(); - } - $.done(); -})() + if ( + $.isRequest && + zhiyouRegex.test($.request.url) && + $.request.method.toUpperCase() == "GET" + ) { + await getWebCookie(); + } else { + await multiUsersSingin(); + } + $.done(); +})(); /** - * - * $$\ $$\ $$\ $$$$$\ $$$$$$\ $$$$$$\ - * $$$\ $$$ | \__| \__$$ |$$ __$$\ $$ ___$$\ + * + * $$\ $$\ $$\ $$$$$\ $$$$$$\ $$$$$$\ + * $$$\ $$$ | \__| \__$$ |$$ __$$\ $$ ___$$\ * $$$$\ $$$$ | $$$$$$\ $$$$$$\ $$\ $$$$$$$\ $$ |$$ / \__| \_/ $$ | - * $$\$$\$$ $$ | \____$$\ $$ __$$\ $$ |$$ _____| $$ |\$$$$$$\ $$$$$ / - * $$ \$$$ $$ | $$$$$$$ |$$ / $$ |$$ |$$ / $$\ $$ | \____$$\ \___$$\ + * $$\$$\$$ $$ | \____$$\ $$ __$$\ $$ |$$ _____| $$ |\$$$$$$\ $$$$$ / + * $$ \$$$ $$ | $$$$$$$ |$$ / $$ |$$ |$$ / $$\ $$ | \____$$\ \___$$\ * $$ |\$ /$$ |$$ __$$ |$$ | $$ |$$ |$$ | $$ | $$ |$$\ $$ | $$\ $$ | * $$ | \_/ $$ |\$$$$$$$ |\$$$$$$$ |$$ |\$$$$$$$\\$$$$$$ |\$$$$$$ | \$$$$$$ | - * \__| \__| \_______| \____$$ |\__| \_______|\______/ \______/ \______/ - * $$\ $$ | - * \$$$$$$ | - * \______/ - * -*/ -function MagicJS(e="MagicJS",t="INFO"){const r=()=>{const e=typeof $loon!=="undefined";const t=typeof $task!=="undefined";const n=typeof module!=="undefined";const r=typeof $httpClient!=="undefined"&&!e;const i=typeof $storm!=="undefined";const o=typeof $environment!=="undefined"&&typeof $environment["stash-build"]!=="undefined";const s=r||e||i||o;const a=typeof importModule!=="undefined";return{isLoon:e,isQuanX:t,isNode:n,isSurge:r,isStorm:i,isStash:o,isSurgeLike:s,isScriptable:a,get name(){if(e){return"Loon"}else if(t){return"QuantumultX"}else if(n){return"NodeJS"}else if(r){return"Surge"}else if(a){return"Scriptable"}else{return"unknown"}},get build(){if(r){return $environment["surge-build"]}else if(o){return $environment["stash-build"]}else if(i){return $storm.buildVersion}},get language(){if(r||o){return $environment["language"]}},get version(){if(r){return $environment["surge-version"]}else if(o){return $environment["stash-version"]}else if(i){return $storm.appVersion}else if(n){return process.version}},get system(){if(r){return $environment["system"]}else if(n){return process.platform}},get systemVersion(){if(i){return $storm.systemVersion}},get deviceName(){if(i){return $storm.deviceName}}}};const i=(n,e="INFO")=>{let r=e;const i={SNIFFER:6,DEBUG:5,INFO:4,NOTIFY:3,WARNING:2,ERROR:1,CRITICAL:0,NONE:-1};const o={SNIFFER:"",DEBUG:"",INFO:"",NOTIFY:"",WARNING:"❗ ",ERROR:"❌ ",CRITICAL:"❌ ",NONE:""};const t=(e,t="INFO")=>{if(!(i[r]{r=e};return{setLevel:s,sniffer:e=>{t(e,"SNIFFER")},debug:e=>{t(e,"DEBUG")},info:e=>{t(e,"INFO")},notify:e=>{t(e,"NOTIFY")},warning:e=>{t(e,"WARNING")},error:e=>{t(e,"ERROR")},retry:e=>{t(e,"RETRY")}}};return new class{constructor(e,t){this._startTime=Date.now();this.version="3.0.0";this.scriptName=e;this.env=r();this.logger=i(e,t);this.http=typeof MagicHttp==="function"?MagicHttp(this.env,this.logger):undefined;this.data=typeof MagicData==="function"?MagicData(this.env,this.logger):undefined;this.notification=typeof MagicNotification==="function"?MagicNotification(this.scriptName,this.env,this.logger,this.http):undefined;this.utils=typeof MagicUtils==="function"?MagicUtils(this.env,this.logger):undefined;this.qinglong=typeof MagicQingLong==="function"?MagicQingLong(this.env,this.data,this.logger):undefined;if(typeof this.data!=="undefined"){let e=this.data.read("magic_loglevel");const n=this.data.read("magic_bark_url");if(e){this.logger.setLevel(e.toUpperCase())}if(n){this.notification.setBark(n)}}}get isRequest(){return typeof $request!=="undefined"&&typeof $response==="undefined"}get isResponse(){return typeof $response!=="undefined"}get isDebug(){return this.logger.level==="DEBUG"}get request(){return typeof $request!=="undefined"?$request:undefined}get response(){if(typeof $response!=="undefined"){if($response.hasOwnProperty("status"))$response["statusCode"]=$response["status"];if($response.hasOwnProperty("statusCode"))$response["status"]=$response["statusCode"];return $response}else{return undefined}}done=(e={})=>{this._endTime=Date.now();let t=(this._endTime-this._startTime)/1e3;this.logger.info(`SCRIPT COMPLETED: ${t} S.`);if(typeof $done!=="undefined"){$done(e)}}}(e,t)}function MagicHttp(u,c){const t="Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Mobile/15E148 Safari/604.1";const n="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36 Edg/84.0.522.59";let f;if(u.isNode){const a=require("axios");f=a.create()}class e{constructor(e=true){this.handlers=[];this.isRequest=e}use(e,t,n){this.handlers.push({fulfilled:e,rejected:t,synchronous:n?n.synchronous:false,runWhen:n?n.runWhen:null});return this.handlers.length-1}eject(e){if(this.handlers[e]){this.handlers[e]=null}}forEach(t){this.handlers.forEach(e=>{if(e!==null){t(e)}})}}function r(e){let n={...e};if(!!n.params){if(!u.isNode){let e=Object.keys(n.params).map(e=>{const t=encodeURIComponent(e);n.url=n.url.replace(new RegExp(`${e}=[^&]*`,"ig"),"");n.url=n.url.replace(new RegExp(`${t}=[^&]*`,"ig"),"");return`${t}=${encodeURIComponent(n.params[e])}`}).join("&");if(n.url.indexOf("?")<0)n.url+="?";if(!/(&|\?)$/g.test(n.url)){n.url+="&"}n.url+=e;delete n.params;c.debug(`Params to QueryString: ${n.url}`)}}return n}const d=(e,t)=>{let n=typeof t==="object"?{headers:{},...t}:{url:t,headers:{}};if(!n.method){n["method"]=e}n=r(n);if(n["rewrite"]===true){if(u.isSurge){n.headers["X-Surge-Skip-Scripting"]=false;delete n["rewrite"]}else if(u.isQuanX){n["hints"]=false;delete n["rewrite"]}}if(u.isSurge){if(n["method"]!=="GET"&&n.headers["Content-Type"].indexOf("application/json")>=0&&n.body instanceof Array){n.body=JSON.stringify(n.body);c.debug(`Convert Array object to String: ${n.body}`)}}else if(u.isQuanX){if(n.hasOwnProperty("body")&&typeof n["body"]!=="string")n["body"]=JSON.stringify(n["body"]);n["method"]=e}else if(u.isNode){if(e==="POST"||e==="PUT"||e==="PATCH"||e==="DELETE"){n.data=n.data||n.body}else if(e==="GET"){n.params=n.params||n.body}delete n.body}return n};const p=(t,n=null)=>{if(t){let e={...t,config:t.config||n,status:t.statusCode||t.status,body:t.body||t.data,headers:t.headers||t.header};if(typeof e.body==="string"){try{e.body=JSON.parse(e.body)}catch{}}delete t.data;return e}else{return t}};const i=r=>{if(!!r){delete r["Content-Length"];let e=new Set(["Accept","Accept-CH","Accept-Charset","Accept-Features","Accept-Encoding","Accept-Language","Accept-Ranges","Access-Control-Allow-Credentials","Access-Control-Allow-Origin","Access-Control-Allow-Methods","Access-Control-Allow-Headers","Access-Control-Max-Age","Access-Control-Expose-Headers","Access-Control-Request-Method","Access-Control-Request-Headers","Age","Allow","Alternates","Authorization","Cache-Control","Connection","Content-Encoding","Content-Language","ontent-Length","Content-Location","Content-Range","Content-Security-Policy","Content-Type","Cookie","DNT","Date","ETag","Expect","Expires","From","Host","If-Match","If-Modified-Since","If-None-Match","If-Range","If-Unmodified-Since","Last-Event-ID","Last-Modified","Link","Location","Max-Forwards","Negotiate","Origin","Pragma","Proxy-Authenticate","Proxy-Authorization","Range","Referer","Retry-After","Sec-Websocket-Extensions","Sec-Websocket-Key","Sec-Websocket-Origin","Sec-Websocket-Protocol","Sec-Websocket-Version","Server","Set-Cookie","Set-Cookie2","Strict-Transport-Security","TCN","TE","Trailer","Transfer-Encoding","Upgrade","User-Agent","Variant-Vary","Vary","Via","Warning","WWW-Authenticate","X-Content-Duration","X-Content-Security-Policy","X-DNSPrefetch-Control","X-Frame-Options","X-Requested-With"]);for(let n of Object.keys(r)){if(!e.has(n)){for(let t of e){let e=n.replace(new RegExp(t,"ig"),t);if(n!==e){r[e]=r[n];delete r[n];break}}}}if(!r["User-Agent"]){if(u.isNode){r["User-Agent"]=n}else{r["User-Agent"]=t}}return r}return r};const g=(t,n=null)=>{if(!!t&&t.status>=400){c.debug(`Raise exception when status code is ${t.status}`);let e={name:"RequestException",message:`Request failed with status code ${t.status}`,config:n||t.config,response:t};return e}};const o={request:new e,response:new e(false)};let y=[];let h=[];let m=true;function $(e){if(typeof e==="object"&&e["modify"]!==false){e["headers"]=i(e["headers"])}e=r(e);return e}function b(e){try{e=!!e?p(e):e;c.sniffer(`HTTP ${e.config["method"].toUpperCase()}:\n${JSON.stringify(e.config)}\nSTATUS CODE:\n${e.status}\nRESPONSE:\n${typeof e.body==="object"?JSON.stringify(e.body):e.body}`);const t=g(e);if(!!t){return Promise.reject(t)}return e}catch(t){c.error(t);return e}}const S=t=>{try{y=[];h=[];o.request.forEach(e=>{if(typeof e.runWhen==="function"&&e.runWhen(t)===false){return}m=m&&e.synchronous;y.unshift(e.fulfilled,e.rejected)});o.response.forEach(e=>{h.push(e.fulfilled,e.rejected)})}catch(e){c.error(`failed to register interceptors: ${e}`)}};const s=(e,r)=>{let i;const t=e.toUpperCase();r=d(t,r);if(u.isNode){i=f}else{if(u.isSurgeLike){i=o=>{return new Promise((r,i)=>{$httpClient[e.toLowerCase()](o,(t,n,e)=>{if(t){let e={name:t.name||t,message:t.message||t,stack:t.stack||t,config:o,response:p(n)};i(e)}else{n.config=o;n.body=e;r(n)}})})}}else{i=i=>{return new Promise((n,r)=>{$task.fetch(i).then(e=>{e=p(e,i);const t=g(e,i);if(t){return Promise.reject(t)}n(e)}).catch(e=>{let t={name:e.message||e.error,message:e.message||e.error,stack:e.error,config:i,response:!!e.response?p(e.response):null};r(t)})})}}}let o;S(r);const s=[$,undefined];const a=[b,undefined];if(!m){c.debug("Interceptors are executed in asynchronous mode");let n=[i,undefined];Array.prototype.unshift.apply(n,s);Array.prototype.unshift.apply(n,y);Array.prototype.unshift.apply(n,s);n=n.concat(a);n=n.concat(h);o=Promise.resolve(r);while(n.length){try{let e=n.shift();let t=n.shift();if(!u.isNode&&r["timeout"]&&e===i){o=l(r)}else{o=o.then(e,t)}}catch(e){c.error(`request exception: ${e}`)}}return o}else{c.debug("Interceptors are executed in synchronous mode");Array.prototype.unshift.apply(y,s);y=y.concat([$,undefined]);while(y.length){let e=y.shift();let t=y.shift();try{r=e(r)}catch(e){t(e);break}}try{if(!u.isNode&&r["timeout"]){o=l(r)}else{o=i(r)}}catch(e){return Promise.reject(e)}Array.prototype.unshift.apply(h,a);while(h.length){o=o.then(h.shift(),h.shift())}return o}function l(n){try{const e=new Promise((e,t)=>{setTimeout(()=>{let e={message:`timeout of ${n["timeout"]}ms exceeded`,config:n};t(e)},n["timeout"])});return Promise.race([i(n),e])}catch(e){c.error(`Request Timeout exception: ${e}`)}}};return{request:s,interceptors:o,modifyHeaders:i,modifyResponse:p,get:e=>{return s("GET",e)},post:e=>{return s("POST",e)},put:e=>{return s("PUT",e)},patch:e=>{return s("PATCH",e)},delete:e=>{return s("DELETE",e)},head:e=>{return s("HEAD",e)},options:e=>{return s("OPTIONS",e)}}}function MagicNotification(o,s,a,l){let u=null;let c=null;const e=t=>{try{let e=t.replace(/\/+$/g,"");u=`${/^https?:\/\/([^/]*)/.exec(e)[0]}/push`;c=/\/([^\/]+)\/?$/.exec(e)[1]}catch(e){a.error(`Bark url error: ${e}.`)}};function t(e=o,t="",n="",r=""){const i=n=>{try{let t={};if(typeof n==="string"){if(s.isLoon)t={openUrl:n};else if(s.isQuanX)t={"open-url":n};else if(s.isSurge)t={url:n}}else if(typeof n==="object"){if(s.isLoon){t["openUrl"]=!!n["open-url"]?n["open-url"]:"";t["mediaUrl"]=!!n["media-url"]?n["media-url"]:""}else if(s.isQuanX){t=!!n["open-url"]||!!n["media-url"]?n:{}}else if(s.isSurge){let e=n["open-url"]||n["openUrl"];t=e?{url:e}:{}}}return t}catch(e){a.error(`Failed to convert notification option, ${e}`)}return n};r=i(r);if(arguments.length==1){e=o;t="",n=arguments[0]}a.notify(`title:${e}\nsubTitle:${t}\nbody:${n}\noptions:${typeof r==="object"?JSON.stringify(r):r}`);if(s.isSurge){$notification.post(e,t,n,r)}else if(s.isLoon){if(!!r)$notification.post(e,t,n,r);else $notification.post(e,t,n)}else if(s.isQuanX){$notify(e,t,n,r)}if(u&&c){f(e,t,n)}}function n(e=o,t="",n="",r=""){if(a.level==="DEBUG"){if(arguments.length==1){e=o;t="",n=arguments[0]}this.notify(e,t,n,r)}}function f(e=o,t="",n="",r=""){if(typeof l==="undefined"||typeof l.post==="undefined"){throw"Bark notification needs to import MagicHttp module."}let i={url:u,headers:{"Content-Type":"application/json; charset=utf-8"},body:{title:e,body:t?`${t}\n${n}`:n,device_key:c}};l.post(i).catch(e=>{a.error(`Bark notify error: ${e}`)})}return{post:t,debug:n,bark:f,setBark:e}}function MagicData(s,a){let l={fs:undefined,data:{}};if(s.isNode){l.fs=require("fs");try{l.fs.accessSync("./magic.json",l.fs.constants.R_OK|l.fs.constants.W_OK)}catch(e){l.fs.writeFileSync("./magic.json","{}",{encoding:"utf8"})}l.data=require("./magic.json")}const u=(e,t)=>{if(typeof t==="object"){return false}else{return e===t}};const c=e=>{if(e==="true"){return true}else if(e==="false"){return false}else if(typeof e==="undefined"){return null}else{return e}};const f=(e,t,n,r)=>{if(n){try{if(typeof e==="string")e=JSON.parse(e);if(e["magic_session"]===true){e=e[n]}else{e=null}}catch{e=null}}if(typeof e==="string"&&e!=="null"){try{e=JSON.parse(e)}catch{}}if(r===false&&!!e&&e["magic_session"]===true){e=null}if((e===null||typeof e==="undefined")&&t!==null&&typeof t!=="undefined"){e=t}e=c(e);return e};const o=t=>{if(typeof t==="string"){let e={};try{e=JSON.parse(t);const n=typeof e;if(n!=="object"||e instanceof Array||n==="bool"||e===null){e={}}}catch{}return e}else if(t instanceof Array||t===null||typeof t==="undefined"||t!==t||typeof t==="boolean"){return{}}else{return t}};const d=(e,t=null,n="",r=false,i=null)=>{let o=i||l.data;if(!!o&&typeof o[e]!=="undefined"&&o[e]!==null){val=o[e]}else{val=!!n?{}:null}val=f(val,t,n,r);return val};const p=(e,t=null,n="",r=false,i=null)=>{let o="";if(i||s.isNode){o=d(e,t,n,r,i)}else{if(s.isSurgeLike){o=$persistentStore.read(e)}else if(s.isQuanX){o=$prefs.valueForKey(e)}o=f(o,t,n,r)}a.debug(`READ DATA [${e}]${!!n?`[${n}]`:""} <${typeof o}>\n${JSON.stringify(o)}`);return o};const g=(t,n,r="",e=null)=>{let i=e||l.data;i=o(i);if(!!r){let e=o(i[t]);e["magic_session"]=true;e[r]=n;i[t]=e}else{i[t]=n}if(e!==null){e=i}return i};const y=(e,t,n="",r=null)=>{if(typeof t==="undefined"||t!==t){return false}if(!s.isNode&&(typeof t==="boolean"||typeof t==="number")){t=String(t)}let i="";if(r||s.isNode){i=g(e,t,n,r)}else{if(!n){i=t}else{if(s.isSurgeLike){i=!!$persistentStore.read(e)?$persistentStore.read(e):i}else if(s.isQuanX){i=!!$prefs.valueForKey(e)?$prefs.valueForKey(e):i}i=o(i);i["magic_session"]=true;i[n]=t}}if(!!i&&typeof i==="object"){i=JSON.stringify(i,"","\t")}a.debug(`WRITE DATA [${e}]${n?`[${n}]`:""} <${typeof t}>\n${JSON.stringify(t)}`);if(!r){if(s.isSurgeLike){return $persistentStore.write(i,e)}else if(s.isQuanX){return $prefs.setValueForKey(i,e)}else if(s.isNode){try{l.fs.writeFileSync("./magic.json",i);return true}catch(e){a.error(e);return false}}}return true};const e=(t,n,r,i=u,o=null)=>{n=c(n);const e=p(t,null,r,false,o);if(i(e,n)===true){return false}else{const s=y(t,n,r,o);let e=p(t,null,r,false,o);if(i===u&&typeof e==="object"){return s}return i(n,e)}};const h=(e,t,n)=>{let r=n||l.data;r=o(r);if(!!t){obj=o(r[e]);delete obj[t];r[e]=obj}else{delete r[e]}if(!!n){n=r}return r};const t=(e,t="",n=null)=>{let r={};if(n||s.isNode){r=h(e,t,n);if(!n){l.fs.writeFileSync("./magic.json",JSON.stringify(r))}else{n=r}}else{if(!t){if(s.isStorm){return $persistentStore.remove(e)}else if(s.isSurgeLike){return $persistentStore.write(null,e)}else if(s.isQuanX){return $prefs.removeValueForKey(e)}}else{if(s.isSurgeLike){r=$persistentStore.read(e)}else if(s.isQuanX){r=$prefs.valueForKey(e)}r=o(r);delete r[t];const i=JSON.stringify(r);y(e,i)}}a.debug(`DELETE KEY [${e}]${!!t?`[${t}]`:""}`)};const n=(e,t=null)=>{let n=[];let r=p(e,null,null,true,t);r=o(r);if(r["magic_session"]!==true){n=[]}else{n=Object.keys(r).filter(e=>e!=="magic_session")}a.debug(`READ ALL SESSIONS [${e}] <${typeof n}>\n${JSON.stringify(n)}`);return n};return{read:p,write:y,del:t,update:e,allSessions:n,defaultValueComparator:u,convertToObject:o}}function MagicUtils(r,u){const e=(o,s=5,a=0,l=null)=>{return(...e)=>{return new Promise((n,r)=>{function i(...t){Promise.resolve().then(()=>o.apply(this,t)).then(e=>{if(typeof l==="function"){Promise.resolve().then(()=>l(e)).then(()=>{n(e)}).catch(e=>{if(s>=1){if(a>0)setTimeout(()=>i.apply(this,t),a);else i.apply(this,t)}else{r(e)}s--})}else{n(e)}}).catch(e=>{u.error(e);if(s>=1&&a>0){setTimeout(()=>i.apply(this,t),a)}else if(s>=1){i.apply(this,t)}else{r(e)}s--})}i.apply(this,e)})}};const t=(e,t="yyyy-MM-dd hh:mm:ss")=>{let n={"M+":e.getMonth()+1,"d+":e.getDate(),"h+":e.getHours(),"m+":e.getMinutes(),"s+":e.getSeconds(),"q+":Math.floor((e.getMonth()+3)/3),S:e.getMilliseconds()};if(/(y+)/.test(t))t=t.replace(RegExp.$1,(e.getFullYear()+"").substr(4-RegExp.$1.length));for(let e in n)if(new RegExp("("+e+")").test(t))t=t.replace(RegExp.$1,RegExp.$1.length==1?n[e]:("00"+n[e]).substr((""+n[e]).length));return t};const n=()=>{return t(new Date,"yyyy-MM-dd hh:mm:ss")};const i=()=>{return t(new Date,"yyyy-MM-dd")};const o=t=>{return new Promise(e=>setTimeout(e,t))};const s=(e,t=null)=>{if(r.isNode){const n=require("assert");if(t)n(e,t);else n(e)}else{if(e!==true){let e=`AssertionError: ${t||"The expression evaluated to a falsy value"}`;u.error(e)}}};return{retry:e,formatTime:t,now:n,today:i,sleep:o,assert:s}}function MagicQingLong(e,l,i){let o="";let s="";let a="";let u="";let c="";let t="";const f="magic.json";const n=3e3;const d=MagicHttp(e,i);const r=(e,t,n,r,i)=>{o=e;a=t;u=n;s=r;c=i};function p(e){o=o||l.read("magic_qlurl");t=t||l.read("magic_qltoken");return e}function g(e){if(!o){o=l.read("magic_qlurl")}if(e.url.indexOf(o)<0){e.url=`${o}${e.url}`}return{...e,timeout:n}}function y(e){e.params={...e.params,t:Date.now()};return e}function h(e){t=t||l.read("magic_qltoken");if(t){e.headers["Authorization"]=`Bearer ${t}`}return e}function m(e){a=a||l.read("magic_qlclient");if(!!a){e.url=e.url.replace("/api/","/open/")}return e}async function $(e){try{const t=e.message||e.error||JSON.stringify(e);if((t.indexOf("NSURLErrorDomain")>=0&&t.indexOf("-1012")>=0||!!e.response&&e.response.status===401)&&(!!e.config&&e.config.refreshToken!==true)){i.warning(`Qinglong panel token has expired`);await b();e.config["refreshToken"]=true;return await d.request(e.config.method,e.config)}else{return Promise.reject(e)}}catch(e){return Promise.reject(e)}}d.interceptors.request.use(p,undefined);d.interceptors.request.use(g,undefined);d.interceptors.request.use(m,undefined,{runWhen:e=>{return e.url.indexOf("api/user/login")<0&&e.url.indexOf("open/auth/token")<0}});d.interceptors.request.use(h,undefined,{runWhen:e=>{return e.url.indexOf("api/user/login")<0&&e.url.indexOf("open/auth/token")<0}});d.interceptors.request.use(y,undefined,{runWhen:e=>{return e.url.indexOf("open/auth/token")<0&&e.url.indexOf("t=")<0}});d.interceptors.response.use(undefined,$);async function b(){a=a||l.read("magic_qlclient");u=u||l.read("magic_qlsecrt");s=s||l.read("magic_qlname");c=c||l.read("magic_qlpwd");if(o&&a&&u){await d.get({url:`/open/auth/token`,headers:{"Content-Type":"application/json"},params:{client_id:a,client_secret:u}}).then(e=>{i.info("Log in to Qinglong panel successfully");t=e.body.data.token;l.update("magic_qltoken",t);return t}).catch(e=>{i.error(`Failed to log in to Qinglong panel.\n${e.message}`)})}else if(o&&s&&c){await d.post({url:`/api/user/login`,headers:{"Content-Type":"application/json"},body:{username:s,password:c}}).then(e=>{i.info("Log in to Qinglong panel successfully");t=e.body.data.token;l.update("magic_qltoken",t);return t}).catch(e=>{i.error(`Failed to log in to Qinglong panel.\n${e.message}`)})}}async function S(t,n,r=null){o=o||l.read("magic_qlurl");if(r===null){let e=await N([{name:t,value:n}]);if(!!e&&e.length===1){return e[0]}}else{d.put({url:`/api/envs`,headers:{"Content-Type":"application/json"},body:{name:t,value:n,id:r}}).then(e=>{if(e.body.code===200){i.debug(`QINGLONG UPDATE ENV ${t} <${typeof n}> (${r})\n${JSON.stringify(n)}`);return true}else{i.error(`Failed to update Qinglong panel environment variable.\n${JSON.stringify(e)}`)}}).catch(e=>{i.error(`Failed to update Qinglong panel environment variable.\n${e.message}`);return false})}}async function N(e){let t=[];await d.post({url:`/api/envs`,headers:{"Content-Type":"application/json"},body:e}).then(e=>{if(e.body.code===200){e.body.data.forEach(e=>{i.debug(`QINGLONG ADD ENV ${e.name} <${typeof e.value}> (${e.id})\n${JSON.stringify(e)}`);t.push(e.id)})}else{i.error(`Failed to add Qinglong panel environment variable.\n${JSON.stringify(e)}`)}}).catch(e=>{i.error(`Failed to add Qinglong panel environment variable.\n${e.message}`)});return t}async function v(t){return await d.delete({url:`/api/envs`,headers:{Accept:"application/json","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",Connection:"keep-alive","Content-Type":"application/json;charset=UTF-8","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30"},body:t}).then(e=>{if(e.body.code===200){i.debug(`QINGLONG DELETE ENV IDS: ${t}`);return true}else{i.error(`Failed to delete QingLong envs.\n${JSON.stringify(e)}`);return false}}).catch(e=>{i.error(`Failed to delete QingLong envs.\n${e.message}`)})}async function O(n=null,e=""){let r=[];await d.get({url:`/api/envs`,headers:{"Content-Type":"application/json"},params:{searchValue:e}}).then(e=>{if(e.body.code===200){const t=e.body.data;if(!!n){let e=[];for(const e of t){if(e.name===n){r.push(e)}}r=e}r=t}else{i.error(`Failed to get environment variables from Qinglong panel.\n${JSON.stringify(e)}`)}}).catch(e=>{i.error(`Failed to get environment variables from Qinglong panel.\n${JSON.stringify(e)}`)});return r}async function E(e){let t=null;const n=await O();for(const r of n){if(r.id===e){t=r;break}}return t}async function T(t){let n=false;await d.put({url:`/api/envs/disable`,headers:{Accept:"application/json","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",Connection:"keep-alive","Content-Type":"application/json;charset=UTF-8","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30"},body:t}).then(e=>{if(e.body.code===200){i.debug(`QINGLONG DISABLED ENV IDS: ${t}`);n=true}else{i.error(`Failed to disable QingLong envs.\n${JSON.stringify(e)}`)}}).catch(e=>{i.error(`Failed to disable QingLong envs.\n${e.message}`)});return n}async function w(t){let n=false;await d.put({url:`/api/envs/enable`,headers:{Accept:"application/json","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",Connection:"keep-alive","Content-Type":"application/json;charset=UTF-8","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30"},body:t}).then(e=>{if(e.body.code===200){i.debug(`QINGLONG ENABLED ENV IDS: ${t}`);n=true}else{i.error(`Failed to enable QingLong envs.\n${JSON.stringify(e)}`)}}).catch(e=>{i.error(`Failed to enable QingLong envs.\n${e.message}`)});return n}async function C(e,t="",n=""){let r=false;await d.post({url:`/api/scripts`,headers:{"Content-Type":"application/json"},body:{filename:e,path:t,content:n}}).then(e=>{if(e.body.code===200){r=true}else{i.error(`Failed to add script content from Qinglong panel.\n${JSON.stringify(e)}`)}}).catch(e=>{i.error(`Failed to add script content from Qinglong panel.\n${e.message}`)});return r}async function A(e,t=""){let n="";await d.get({url:`/api/scripts/${e}`,params:{path:t}}).then(e=>{if(e.body.code===200){n=e.body.data}else{i.error(`Failed to read script content from Qinglong panel.\n${JSON.stringify(e)}`)}}).catch(e=>{i.error(`Failed to read script content from Qinglong panel.\n${e.message}`)});return n}async function k(e,t="",n=""){let r=false;await d.put({url:`/api/scripts`,headers:{"Content-Type":"application/json"},body:{filename:e,path:t,content:n}}).then(e=>{if(e.body.code===200){r=true}else{i.error(`Failed to read script content from Qinglong panel.\n${JSON.stringify(e)}`)}}).catch(e=>{i.error(`Failed to read script content from Qinglong panel.\n${e.message}`)});return r}async function L(e,t=""){let n=false;await d.delete({url:`/api/scripts`,headers:{"Content-Type":"application/json"},body:{filename:e,path:t}}).then(e=>{if(e.body.code===200){n=true}else{i.error(`Failed to read script content from Qinglong panel.\n${JSON.stringify(e)}`)}}).catch(e=>{i.error(`Failed to read script content from Qinglong panel.\n${e.message}`)});return n}async function F(e,t,n=""){let r=await A(f,"");let i=l.convertToObject(r);let o=l.write(e,t,n,i);r=JSON.stringify(i,"","\t");let s=await k(f,"",r);return s&&o}async function j(e,t,n,r=l.defaultValueComparator){let i=await A(f,"");let o=l.convertToObject(i);const s=l.update(e,t,n,r,o);let a=false;if(s===true){i=JSON.stringify(o,"","\t");a=await k(f,"",i)}return s&&a}async function M(e,t,n=""){let r=await A(f,"");let i=l.convertToObject(r);const o=l.read(e,t,n,false,i);return o}async function R(e,t=""){let n=await A(f,"");let r=l.convertToObject(n);const i=l.del(e,t,r);n=JSON.stringify(r,"","\t");const o=await k(f,"",n);return i&&o}async function q(e){let t=await A(f,"");let n=l.convertToObject(t);const r=l.allSessions(e,n);return r}return{init:r,getToken:b,setEnv:S,setEnvs:N,getEnv:E,getEnvs:O,delEnvs:v,disableEnvs:T,enbleEnvs:w,addScript:C,getScript:A,editScript:k,delScript:L,write:F,read:M,del:R,update:j,allSessions:q}} \ No newline at end of file + * \__| \__| \_______| \____$$ |\__| \_______|\______/ \______/ \______/ + * $$\ $$ | + * \$$$$$$ | + * \______/ + * + */ +// prettier-ignore +function MagicJS(e="MagicJS",t="INFO"){const i=()=>{const e=typeof $loon!=="undefined";const t=typeof $task!=="undefined";const n=typeof module!=="undefined";const i=typeof $httpClient!=="undefined"&&!e;const s=typeof $storm!=="undefined";const r=typeof $environment!=="undefined"&&typeof $environment["stash-build"]!=="undefined";const o=i||e||s||r;const u=typeof importModule!=="undefined";return{isLoon:e,isQuanX:t,isNode:n,isSurge:i,isStorm:s,isStash:r,isSurgeLike:o,isScriptable:u,get name(){if(e){return"Loon"}else if(t){return"QuantumultX"}else if(n){return"NodeJS"}else if(i){return"Surge"}else if(u){return"Scriptable"}else{return"unknown"}},get build(){if(i){return $environment["surge-build"]}else if(r){return $environment["stash-build"]}else if(s){return $storm.buildVersion}},get language(){if(i||r){return $environment["language"]}},get version(){if(i){return $environment["surge-version"]}else if(r){return $environment["stash-version"]}else if(s){return $storm.appVersion}else if(n){return process.version}},get system(){if(i){return $environment["system"]}else if(n){return process.platform}},get systemVersion(){if(s){return $storm.systemVersion}},get deviceName(){if(s){return $storm.deviceName}}}};const s=(n,e="INFO")=>{let i=e;const s={SNIFFER:6,DEBUG:5,INFO:4,NOTIFY:3,WARNING:2,ERROR:1,CRITICAL:0,NONE:-1};const r={SNIFFER:"",DEBUG:"",INFO:"",NOTIFY:"",WARNING:"❗ ",ERROR:"❌ ",CRITICAL:"❌ ",NONE:""};const t=(e,t="INFO")=>{if(!(s[i]{i=e};return{setLevel:o,sniffer:e=>{t(e,"SNIFFER")},debug:e=>{t(e,"DEBUG")},info:e=>{t(e,"INFO")},notify:e=>{t(e,"NOTIFY")},warning:e=>{t(e,"WARNING")},error:e=>{t(e,"ERROR")},retry:e=>{t(e,"RETRY")}}};return new class{constructor(e,t){this._startTime=Date.now();this.version="3.0.0";this.scriptName=e;this.env=i();this.logger=s(e,t);this.http=typeof MagicHttp==="function"?MagicHttp(this.env,this.logger):undefined;this.data=typeof MagicData==="function"?MagicData(this.env,this.logger):undefined;this.notification=typeof MagicNotification==="function"?MagicNotification(this.scriptName,this.env,this.logger):undefined;this.utils=typeof MagicUtils==="function"?MagicUtils(this.env,this.logger):undefined;this.qinglong=typeof MagicQingLong==="function"?MagicQingLong(this.env,this.data,this.logger):undefined;if(typeof this.data!=="undefined"){let e=this.data.read("magic_loglevel");const n=this.data.read("magic_bark_url");if(e){this.logger.setLevel(e.toUpperCase())}if(n){this.notification.setBark(n)}}}get isRequest(){return typeof $request!=="undefined"&&typeof $response==="undefined"}get isResponse(){return typeof $response!=="undefined"}get isDebug(){return this.logger.level==="DEBUG"}get request(){if(typeof $request!=="undefined"){this.logger.sniffer(`RESPONSE:\n${JSON.stringify($request)}`);return $request}}get response(){if(typeof $response!=="undefined"){if($response.hasOwnProperty("status"))$response["statusCode"]=$response["status"];if($response.hasOwnProperty("statusCode"))$response["status"]=$response["statusCode"];this.logger.sniffer(`RESPONSE:\n${JSON.stringify($response)}`);return $response}else{return undefined}}done=(e={})=>{this._endTime=Date.now();let t=(this._endTime-this._startTime)/1e3;this.logger.info(`SCRIPT COMPLETED: ${t} S.`);if(typeof $done!=="undefined"){$done(e)}}}(e,t)} +// prettier-ignore +function MagicData(l,f){let u={fs:undefined,data:{}};if(l.isNode){u.fs=require("fs");try{u.fs.accessSync("./magic.json",u.fs.constants.R_OK|u.fs.constants.W_OK)}catch(e){u.fs.writeFileSync("./magic.json","{}",{encoding:"utf8"})}u.data=require("./magic.json")}const o=(e,t)=>{if(typeof t==="object"){return false}else{return e===t}};const a=e=>{if(e==="true"){return true}else if(e==="false"){return false}else if(typeof e==="undefined"){return null}else{return e}};const c=(e,t,r,s)=>{if(r){try{if(typeof e==="string")e=JSON.parse(e);if(e["magic_session"]===true){e=e[r]}else{e=null}}catch{e=null}}if(typeof e==="string"&&e!=="null"){try{e=JSON.parse(e)}catch{}}if(s===false&&!!e&&e["magic_session"]===true){e=null}if((e===null||typeof e==="undefined")&&t!==null&&typeof t!=="undefined"){e=t}e=a(e);return e};const i=t=>{if(typeof t==="string"){let e={};try{e=JSON.parse(t);const r=typeof e;if(r!=="object"||e instanceof Array||r==="bool"||e===null){e={}}}catch{}return e}else if(t instanceof Array||t===null||typeof t==="undefined"||t!==t||typeof t==="boolean"){return{}}else{return t}};const y=(e,t=null,r="",s=false,n=null)=>{let i=n||u.data;if(!!i&&typeof i[e]!=="undefined"&&i[e]!==null){val=i[e]}else{val=!!r?{}:null}val=c(val,t,r,s);return val};const d=(e,t=null,r="",s=false,n=null)=>{let i="";if(n||l.isNode){i=y(e,t,r,s,n)}else{if(l.isSurgeLike){i=$persistentStore.read(e)}else if(l.isQuanX){i=$prefs.valueForKey(e)}i=c(i,t,r,s)}f.debug(`READ DATA [${e}]${!!r?`[${r}]`:""} <${typeof i}>\n${JSON.stringify(i)}`);return i};const p=(t,r,s="",e=null)=>{let n=e||u.data;n=i(n);if(!!s){let e=i(n[t]);e["magic_session"]=true;e[s]=r;n[t]=e}else{n[t]=r}if(e!==null){e=n}return n};const g=(e,t,r="",s=null)=>{if(typeof t==="undefined"||t!==t){return false}if(!l.isNode&&(typeof t==="boolean"||typeof t==="number")){t=String(t)}let n="";if(s||l.isNode){n=p(e,t,r,s)}else{if(!r){n=t}else{if(l.isSurgeLike){n=!!$persistentStore.read(e)?$persistentStore.read(e):n}else if(l.isQuanX){n=!!$prefs.valueForKey(e)?$prefs.valueForKey(e):n}n=i(n);n["magic_session"]=true;n[r]=t}}if(!!n&&typeof n==="object"){n=JSON.stringify(n,"","\t")}f.debug(`WRITE DATA [${e}]${r?`[${r}]`:""} <${typeof t}>\n${JSON.stringify(t)}`);if(!s){if(l.isSurgeLike){return $persistentStore.write(n,e)}else if(l.isQuanX){return $prefs.setValueForKey(n,e)}else if(l.isNode){try{u.fs.writeFileSync("./magic.json",n);return true}catch(e){f.error(e);return false}}}return true};const e=(t,r,s,n=o,i=null)=>{r=a(r);const e=d(t,null,s,false,i);if(n(e,r)===true){return false}else{const l=g(t,r,s,i);let e=d(t,null,s,false,i);if(n===o&&typeof e==="object"){return l}return n(r,e)}};const S=(e,t,r)=>{let s=r||u.data;s=i(s);if(!!t){obj=i(s[e]);delete obj[t];s[e]=obj}else{delete s[e]}if(!!r){r=s}return s};const t=(e,t="",r=null)=>{let s={};if(r||l.isNode){s=S(e,t,r);if(!r){u.fs.writeFileSync("./magic.json",JSON.stringify(s))}else{r=s}}else{if(!t){if(l.isStorm){return $persistentStore.remove(e)}else if(l.isSurgeLike){return $persistentStore.write(null,e)}else if(l.isQuanX){return $prefs.removeValueForKey(e)}}else{if(l.isSurgeLike){s=$persistentStore.read(e)}else if(l.isQuanX){s=$prefs.valueForKey(e)}s=i(s);delete s[t];const n=JSON.stringify(s);g(e,n)}}f.debug(`DELETE KEY [${e}]${!!t?`[${t}]`:""}`)};const r=(e,t=null)=>{let r=[];let s=d(e,null,null,true,t);s=i(s);if(s["magic_session"]!==true){r=[]}else{r=Object.keys(s).filter(e=>e!=="magic_session")}f.debug(`READ ALL SESSIONS [${e}] <${typeof r}>\n${JSON.stringify(r)}`);return r};return{read:d,write:g,del:t,update:e,allSessions:r,defaultValueComparator:o,convertToObject:i}} +// prettier-ignore +function MagicHttp(l,u){const t="Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Mobile/15E148 Safari/604.1";const r="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36 Edg/84.0.522.59";let f;if(l.isNode){const a=require("axios");f=a.create()}class e{constructor(e=true){this.handlers=[];this.isRequest=e}use(e,t,r){this.handlers.push({fulfilled:e,rejected:t,synchronous:r?r.synchronous:false,runWhen:r?r.runWhen:null});return this.handlers.length-1}eject(e){if(this.handlers[e]){this.handlers[e]=null}}forEach(t){this.handlers.forEach(e=>{if(e!==null){t(e)}})}}function n(e){let r={...e};if(!!r.params){if(!l.isNode){let e=Object.keys(r.params).map(e=>{const t=encodeURIComponent(e);r.url=r.url.replace(new RegExp(`${e}=[^&]*`,"ig"),"");r.url=r.url.replace(new RegExp(`${t}=[^&]*`,"ig"),"");return`${t}=${encodeURIComponent(r.params[e])}`}).join("&");if(r.url.indexOf("?")<0)r.url+="?";if(!/(&|\?)$/g.test(r.url)){r.url+="&"}r.url+=e;delete r.params;u.debug(`Params to QueryString: ${r.url}`)}}return r}const d=(e,t)=>{let r=typeof t==="object"?{headers:{},...t}:{url:t,headers:{}};if(!r.method){r["method"]=e}r=n(r);if(r["rewrite"]===true){if(l.isSurge){r.headers["X-Surge-Skip-Scripting"]=false;delete r["rewrite"]}else if(l.isQuanX){r["hints"]=false;delete r["rewrite"]}}if(l.isSurge){if(r["method"]!=="GET"&&typeof r.headers["Content-Type"]==="string"&&r.headers["Content-Type"].indexOf("application/json")>=0&&r.body instanceof Array){r.body=JSON.stringify(r.body);u.debug(`Convert Array object to String: ${r.body}`)}}else if(l.isQuanX){if(r.hasOwnProperty("body")&&typeof r["body"]!=="string")r["body"]=JSON.stringify(r["body"]);r["method"]=e}else if(l.isNode){if(e==="POST"||e==="PUT"||e==="PATCH"||e==="DELETE"){r.data=r.data||r.body}else if(e==="GET"){r.params=r.params||r.body}delete r.body}return r};const h=(t,r=null)=>{if(t){let e={...t,config:t.config||r,status:t.statusCode||t.status,body:t.body||t.data||"",headers:t.headers||t.header};if(typeof e.body==="string"){try{e.body=JSON.parse(e.body)}catch{}}delete t.data;return e}else{let e={config:r,status:null,body:"",headers:{}};return e}};const o=n=>{if(!!n){delete n["Content-Length"];let e=new Set(["Accept","Accept-CH","Accept-Charset","Accept-Features","Accept-Encoding","Accept-Language","Accept-Ranges","Access-Control-Allow-Credentials","Access-Control-Allow-Origin","Access-Control-Allow-Methods","Access-Control-Allow-Headers","Access-Control-Max-Age","Access-Control-Expose-Headers","Access-Control-Request-Method","Access-Control-Request-Headers","Age","Allow","Alternates","Authorization","Cache-Control","Connection","Content-Encoding","Content-Language","ontent-Length","Content-Location","Content-Range","Content-Security-Policy","Content-Type","Cookie","DNT","Date","ETag","Expect","Expires","From","Host","If-Match","If-Modified-Since","If-None-Match","If-Range","If-Unmodified-Since","Last-Event-ID","Last-Modified","Link","Location","Max-Forwards","Negotiate","Origin","Pragma","Proxy-Authenticate","Proxy-Authorization","Range","Referer","Retry-After","Sec-Websocket-Extensions","Sec-Websocket-Key","Sec-Websocket-Origin","Sec-Websocket-Protocol","Sec-Websocket-Version","Server","Set-Cookie","Set-Cookie2","Strict-Transport-Security","TCN","TE","Trailer","Transfer-Encoding","Upgrade","User-Agent","Variant-Vary","Vary","Via","Warning","WWW-Authenticate","X-Content-Duration","X-Content-Security-Policy","X-DNSPrefetch-Control","X-Frame-Options","X-Requested-With"]);for(let r of Object.keys(n)){if(!e.has(r)){for(let t of e){let e=r.replace(new RegExp(t,"ig"),t);if(r!==e){n[e]=n[r];delete n[r];break}}}}if(!n["User-Agent"]){if(l.isNode){n["User-Agent"]=r}else{n["User-Agent"]=t}}return n}return n};const p=(t,r=null)=>{if(!!t&&t.status>=400){u.debug(`Raise exception when status code is ${t.status}`);let e={name:"RequestException",message:`Request failed with status code ${t.status}`,config:r||t.config,response:t};return e}};const s={request:new e,response:new e(false)};let y=[];let g=[];let m=true;function A(e){if(typeof e==="object"&&e["modify"]!==false){e["headers"]=o(e["headers"])}e=n(e);return e}function C(e){try{e=!!e?h(e):e;u.sniffer(`HTTP ${e.config["method"].toUpperCase()}:\n${JSON.stringify(e.config)}\nSTATUS CODE:\n${e.status}\nRESPONSE:\n${typeof e.body==="object"?JSON.stringify(e.body):e.body}`);const t=p(e);if(!!t){return Promise.reject(t)}return e}catch(t){u.error(t);return e}}const b=t=>{try{y=[];g=[];s.request.forEach(e=>{if(typeof e.runWhen==="function"&&e.runWhen(t)===false){return}m=m&&e.synchronous;y.unshift(e.fulfilled,e.rejected)});s.response.forEach(e=>{g.push(e.fulfilled,e.rejected)})}catch(e){u.error(`failed to register interceptors: ${e}`)}};const i=(e,n)=>{let o;const t=e.toUpperCase();n=d(t,n);if(l.isNode){o=f}else{if(l.isSurgeLike){o=s=>{return new Promise((n,o)=>{$httpClient[e.toLowerCase()](s,(t,r,e)=>{if(t){let e={name:t.name||t,message:t.message||t,stack:t.stack||t,config:s,response:h(r)};o(e)}else{r.config=s;r.body=e;n(r)}})})}}else{o=o=>{return new Promise((r,n)=>{$task.fetch(o).then(e=>{e=h(e,o);const t=p(e,o);if(t){return Promise.reject(t)}r(e)}).catch(e=>{let t={name:e.message||e.error,message:e.message||e.error,stack:e.error,config:o,response:!!e.response?h(e.response):null};n(t)})})}}}let s;b(n);const i=[A,undefined];const a=[C,undefined];if(!m){u.debug("Interceptors are executed in asynchronous mode");let r=[o,undefined];Array.prototype.unshift.apply(r,i);Array.prototype.unshift.apply(r,y);Array.prototype.unshift.apply(r,i);r=r.concat(a);r=r.concat(g);s=Promise.resolve(n);while(r.length){try{let e=r.shift();let t=r.shift();if(!l.isNode&&n["timeout"]&&e===o){s=c(n)}else{s=s.then(e,t)}}catch(e){u.error(`request exception: ${e}`)}}return s}else{u.debug("Interceptors are executed in synchronous mode");Array.prototype.unshift.apply(y,i);y=y.concat([A,undefined]);while(y.length){let e=y.shift();let t=y.shift();try{n=e(n)}catch(e){t(e);break}}try{if(!l.isNode&&n["timeout"]){s=c(n)}else{s=o(n)}}catch(e){return Promise.reject(e)}Array.prototype.unshift.apply(g,a);while(g.length){s=s.then(g.shift(),g.shift())}return s}function c(r){try{const e=new Promise((e,t)=>{setTimeout(()=>{let e={message:`timeout of ${r["timeout"]}ms exceeded`,config:r};t(e)},r["timeout"])});return Promise.race([o(r),e])}catch(e){u.error(`Request Timeout exception: ${e}`)}}};return{request:i,interceptors:s,modifyHeaders:o,modifyResponse:h,get:e=>{return i("GET",e)},post:e=>{return i("POST",e)},put:e=>{return i("PUT",e)},patch:e=>{return i("PATCH",e)},delete:e=>{return i("DELETE",e)},head:e=>{return i("HEAD",e)},options:e=>{return i("OPTIONS",e)}}} +// prettier-ignore +function MagicNotification(r,f,l){let s=null;let u=null;const c=typeof MagicHttp==="function"?MagicHttp(f,l):undefined;const e=t=>{try{let e=t.replace(/\/+$/g,"");s=`${/^https?:\/\/([^/]*)/.exec(e)[0]}/push`;u=/\/([^\/]+)\/?$/.exec(e)[1]}catch(e){l.error(`Bark url error: ${e}.`)}};function t(e=r,t="",i="",o=""){const n=i=>{try{let t={};if(typeof i==="string"){if(f.isLoon)t={openUrl:i};else if(f.isQuanX)t={"open-url":i};else if(f.isSurge)t={url:i}}else if(typeof i==="object"){if(f.isLoon){t["openUrl"]=!!i["open-url"]?i["open-url"]:"";t["mediaUrl"]=!!i["media-url"]?i["media-url"]:""}else if(f.isQuanX){t=!!i["open-url"]||!!i["media-url"]?i:{}}else if(f.isSurge){let e=i["open-url"]||i["openUrl"];t=e?{url:e}:{}}}return t}catch(e){l.error(`Failed to convert notification option, ${e}`)}return i};o=n(o);if(arguments.length==1){e=r;t="",i=arguments[0]}l.notify(`title:${e}\nsubTitle:${t}\nbody:${i}\noptions:${typeof o==="object"?JSON.stringify(o):o}`);if(f.isSurge){$notification.post(e,t,i,o)}else if(f.isLoon){if(!!o)$notification.post(e,t,i,o);else $notification.post(e,t,i)}else if(f.isQuanX){$notify(e,t,i,o)}if(s&&u&&typeof c!=="undefined"){p(e,t,i)}}function i(e=r,t="",i="",o=""){if(l.level==="DEBUG"){if(arguments.length==1){e=r;t="",i=arguments[0]}this.notify(e,t,i,o)}}function p(e=r,t="",i="",o=""){if(typeof c==="undefined"||typeof c.post==="undefined"){throw"Bark notification needs to import MagicHttp module."}let n={url:s,headers:{"Content-Type":"application/json; charset=utf-8"},body:{title:e,body:t?`${t}\n${i}`:i,device_key:u}};c.post(n).catch(e=>{l.error(`Bark notify error: ${e}`)})}return{post:t,debug:i,bark:p,setBark:e}} +// prettier-ignore +function MagicUtils(r,h){const e=(o,i=5,l=0,a=null)=>{return(...e)=>{return new Promise((s,r)=>{function n(...t){Promise.resolve().then(()=>o.apply(this,t)).then(e=>{if(typeof a==="function"){Promise.resolve().then(()=>a(e)).then(()=>{s(e)}).catch(e=>{if(i>=1){if(l>0)setTimeout(()=>n.apply(this,t),l);else n.apply(this,t)}else{r(e)}i--})}else{s(e)}}).catch(e=>{h.error(e);if(i>=1&&l>0){setTimeout(()=>n.apply(this,t),l)}else if(i>=1){n.apply(this,t)}else{r(e)}i--})}n.apply(this,e)})}};const t=(e,t="yyyy-MM-dd hh:mm:ss")=>{let s={"M+":e.getMonth()+1,"d+":e.getDate(),"h+":e.getHours(),"m+":e.getMinutes(),"s+":e.getSeconds(),"q+":Math.floor((e.getMonth()+3)/3),S:e.getMilliseconds()};if(/(y+)/.test(t))t=t.replace(RegExp.$1,(e.getFullYear()+"").substr(4-RegExp.$1.length));for(let e in s)if(new RegExp("("+e+")").test(t))t=t.replace(RegExp.$1,RegExp.$1.length==1?s[e]:("00"+s[e]).substr((""+s[e]).length));return t};const s=()=>{return t(new Date,"yyyy-MM-dd hh:mm:ss")};const n=()=>{return t(new Date,"yyyy-MM-dd")};const o=t=>{return new Promise(e=>setTimeout(e,t))};const i=(e,t=null)=>{if(r.isNode){const s=require("assert");if(t)s(e,t);else s(e)}else{if(e!==true){let e=`AssertionError: ${t||"The expression evaluated to a falsy value"}`;h.error(e)}}};return{retry:e,formatTime:t,now:s,today:n,sleep:o,assert:i}} +// prettier-ignore +function MagicQingLong(e,s,r){let i="";let o="";let l="";let c="";let d="";let n="";const u="magic.json";const t=3e3;const p=MagicHttp(e,r);const a=(e,n,t,a,r)=>{i=e;l=n;c=t;o=a;d=r};function g(e){i=i||s.read("magic_qlurl");n=n||s.read("magic_qltoken");return e}function f(e){if(!i){i=s.read("magic_qlurl")}if(e.url.indexOf(i)<0){e.url=`${i}${e.url}`}return{...e,timeout:t}}function y(e){e.params={...e.params,t:Date.now()};return e}function h(e){n=n||s.read("magic_qltoken");if(n){e.headers["Authorization"]=`Bearer ${n}`}return e}function m(e){l=l||s.read("magic_qlclient");if(!!l){e.url=e.url.replace("/api/","/open/")}return e}async function b(e){try{const n=e.message||e.error||JSON.stringify(e);if((n.indexOf("NSURLErrorDomain")>=0&&n.indexOf("-1012")>=0||!!e.response&&e.response.status===401)&&!!e.config&&e.config.refreshToken!==true){r.warning(`Qinglong panel token has expired`);await v();e.config["refreshToken"]=true;return await p.request(e.config.method,e.config)}else{return Promise.reject(e)}}catch(e){return Promise.reject(e)}}p.interceptors.request.use(g,undefined);p.interceptors.request.use(f,undefined);p.interceptors.request.use(m,undefined,{runWhen:e=>{return e.url.indexOf("api/user/login")<0&&e.url.indexOf("open/auth/token")<0}});p.interceptors.request.use(h,undefined,{runWhen:e=>{return e.url.indexOf("api/user/login")<0&&e.url.indexOf("open/auth/token")<0}});p.interceptors.request.use(y,undefined,{runWhen:e=>{return e.url.indexOf("open/auth/token")<0&&e.url.indexOf("t=")<0}});p.interceptors.response.use(undefined,b);async function v(){l=l||s.read("magic_qlclient");c=c||s.read("magic_qlsecrt");o=o||s.read("magic_qlname");d=d||s.read("magic_qlpwd");if(i&&l&&c){await p.get({url:`/open/auth/token`,headers:{"Content-Type":"application/json"},params:{client_id:l,client_secret:c}}).then(e=>{r.info("Log in to Qinglong panel successfully");n=e.body.data.token;s.update("magic_qltoken",n);return n}).catch(e=>{r.error(`Failed to log in to Qinglong panel.\n${e.message}`)})}else if(i&&o&&d){await p.post({url:`/api/user/login`,headers:{"Content-Type":"application/json"},body:{username:o,password:d}}).then(e=>{r.info("Log in to Qinglong panel successfully");n=e.body.data.token;s.update("magic_qltoken",n);return n}).catch(e=>{r.error(`Failed to log in to Qinglong panel.\n${e.message}`)})}}async function N(n,t,a=null){i=i||s.read("magic_qlurl");if(a===null){let e=await $([{name:n,value:t}]);if(!!e&&e.length===1){return e[0]}}else{p.put({url:`/api/envs`,headers:{"Content-Type":"application/json"},body:{name:n,value:t,id:a}}).then(e=>{if(e.body.code===200){r.debug(`QINGLONG UPDATE ENV ${n} <${typeof t}> (${a})\n${JSON.stringify(t)}`);return true}else{r.error(`Failed to update Qinglong panel environment variable.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to update Qinglong panel environment variable.\n${e.message}`);return false})}}async function $(e){let n=[];await p.post({url:`/api/envs`,headers:{"Content-Type":"application/json"},body:e}).then(e=>{if(e.body.code===200){e.body.data.forEach(e=>{r.debug(`QINGLONG ADD ENV ${e.name} <${typeof e.value}> (${e.id})\n${JSON.stringify(e)}`);n.push(e.id)})}else{r.error(`Failed to add Qinglong panel environment variable.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to add Qinglong panel environment variable.\n${e.message}`)});return n}async function O(n){return await p.delete({url:`/api/envs`,headers:{Accept:"application/json","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",Connection:"keep-alive","Content-Type":"application/json;charset=UTF-8","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30"},body:n}).then(e=>{if(e.body.code===200){r.debug(`QINGLONG DELETE ENV IDS: ${n}`);return true}else{r.error(`Failed to delete QingLong envs.\n${JSON.stringify(e)}`);return false}}).catch(e=>{r.error(`Failed to delete QingLong envs.\n${e.message}`)})}async function S(t=null,e=""){let a=[];await p.get({url:`/api/envs`,headers:{"Content-Type":"application/json"},params:{searchValue:e}}).then(e=>{if(e.body.code===200){const n=e.body.data;if(!!t){let e=[];for(const e of n){if(e.name===t){a.push(e)}}a=e}a=n}else{r.error(`Failed to get environment variables from Qinglong panel.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to get environment variables from Qinglong panel.\n${JSON.stringify(e)}`)});return a}async function q(e){let n=null;const t=await S();for(const a of t){if(a.id===e){n=a;break}}return n}async function w(n){let t=false;await p.put({url:`/api/envs/disable`,headers:{Accept:"application/json","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",Connection:"keep-alive","Content-Type":"application/json;charset=UTF-8","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30"},body:n}).then(e=>{if(e.body.code===200){r.debug(`QINGLONG DISABLED ENV IDS: ${n}`);t=true}else{r.error(`Failed to disable QingLong envs.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to disable QingLong envs.\n${e.message}`)});return t}async function Q(n){let t=false;await p.put({url:`/api/envs/enable`,headers:{Accept:"application/json","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",Connection:"keep-alive","Content-Type":"application/json;charset=UTF-8","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30"},body:n}).then(e=>{if(e.body.code===200){r.debug(`QINGLONG ENABLED ENV IDS: ${n}`);t=true}else{r.error(`Failed to enable QingLong envs.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to enable QingLong envs.\n${e.message}`)});return t}async function T(e,n="",t=""){let a=false;await p.post({url:`/api/scripts`,headers:{"Content-Type":"application/json"},body:{filename:e,path:n,content:t}}).then(e=>{if(e.body.code===200){a=true}else{r.error(`Failed to add script content from Qinglong panel.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to add script content from Qinglong panel.\n${e.message}`)});return a}async function F(e,n=""){let t="";await p.get({url:`/api/scripts/${e}`,params:{path:n}}).then(e=>{if(e.body.code===200){t=e.body.data}else{r.error(`Failed to read script content from Qinglong panel.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to read script content from Qinglong panel.\n${e.message}`)});return t}async function k(e,n="",t=""){let a=false;await p.put({url:`/api/scripts`,headers:{"Content-Type":"application/json"},body:{filename:e,path:n,content:t}}).then(e=>{if(e.body.code===200){a=true}else{r.error(`Failed to read script content from Qinglong panel.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to read script content from Qinglong panel.\n${e.message}`)});return a}async function E(e,n=""){let t=false;await p.delete({url:`/api/scripts`,headers:{"Content-Type":"application/json"},body:{filename:e,path:n}}).then(e=>{if(e.body.code===200){t=true}else{r.error(`Failed to read script content from Qinglong panel.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to read script content from Qinglong panel.\n${e.message}`)});return t}async function L(e,n,t=""){let a=await F(u,"");let r=s.convertToObject(a);let i=s.write(e,n,t,r);a=JSON.stringify(r,"","\t");let o=await k(u,"",a);return o&&i}async function j(e,n,t,a=s.defaultValueComparator){let r=await F(u,"");let i=s.convertToObject(r);const o=s.update(e,n,t,a,i);let l=false;if(o===true){r=JSON.stringify(i,"","\t");l=await k(u,"",r)}return o&&l}async function C(e,n,t=""){let a=await F(u,"");let r=s.convertToObject(a);const i=s.read(e,n,t,false,r);return i}async function _(e,n=""){let t=await F(u,"");let a=s.convertToObject(t);const r=s.del(e,n,a);t=JSON.stringify(a,"","\t");const i=await k(u,"",t);return r&&i}async function A(e){let n=await F(u,"");let t=s.convertToObject(n);const a=s.allSessions(e,t);return a}return{init:a,getToken:v,setEnv:N,setEnvs:$,getEnv:q,getEnvs:S,delEnvs:O,disableEnvs:w,enbleEnvs:Q,addScript:T,getScript:F,editScript:k,delScript:E,write:L,read:C,del:_,update:j,allSessions:A,url:i||s.read("magic_qlurl"),clientId:l||s.read("magic_qlclient"),userName:o||s.read("magic_magic_qlname")}} diff --git a/script/smzdm/smzdm_daily.lnplugin b/script/smzdm/smzdm_daily.lnplugin index a74af2eec22..40d9b1b2c9b 100644 --- a/script/smzdm/smzdm_daily.lnplugin +++ b/script/smzdm/smzdm_daily.lnplugin @@ -6,7 +6,7 @@ #!icon= https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/smzdm/smzdm.png [Script] -http-request ^https?:\/\/zhiyou\.smzdm\.com\/user$ script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/smzdm/smzdm_daily.js,tag=什么值得买_获取Cookie +http-request ^https?:\/\/zhiyou\.smzdm\.com\/user\/?$ script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/smzdm/smzdm_daily.js,tag=什么值得买_获取Cookie cron "30 9 * * *" script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/smzdm/smzdm_daily.js,timeout=60,tag=什么值得买_每日签到 [MITM] diff --git a/script/smzdm/smzdm_daily.qxrewrite b/script/smzdm/smzdm_daily.qxrewrite index 7a5cec23a2b..7ca3d4003de 100644 --- a/script/smzdm/smzdm_daily.qxrewrite +++ b/script/smzdm/smzdm_daily.qxrewrite @@ -1,6 +1,6 @@ # 什么值得买每日自动签到 -^https?:\/\/zhiyou\.smzdm\.com\/user$ url script-request-header https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/smzdm/smzdm_daily.js +^https?:\/\/zhiyou\.smzdm\.com\/user\/?$ url script-request-header https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/smzdm/smzdm_daily.js # ^https?:\/\/user-api\.smzdm\.com\/user_login\/normal$ url script-request-body https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/smzdm/smzdm_daily.js hostname = zhiyou.smzdm.com \ No newline at end of file diff --git a/script/smzdm/smzdm_daily.sgmodule b/script/smzdm/smzdm_daily.sgmodule index d1de039b632..20b9c4202bb 100644 --- a/script/smzdm/smzdm_daily.sgmodule +++ b/script/smzdm/smzdm_daily.sgmodule @@ -4,7 +4,7 @@ [Script] 什么值得买_每日签到 = script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/smzdm/smzdm_daily.js,timeout=120,type=cron,cronexp=5 0 * * * -什么值得买_获取cookie = script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/smzdm/smzdm_daily.js,type=http-request,requires-body=false,pattern=^https?:\/\/zhiyou\.smzdm\.com\/user$ +什么值得买_获取cookie = script-path=https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/smzdm/smzdm_daily.js,type=http-request,requires-body=false,pattern=^https?:\/\/zhiyou\.smzdm\.com\/user\/?$ [MITM] hostname = %APPEND% zhiyou.smzdm.com \ No newline at end of file diff --git a/script/tieba/tieba_signin.js b/script/tieba/tieba_signin.js index c8b93819472..346f1b72369 100644 --- a/script/tieba/tieba_signin.js +++ b/script/tieba/tieba_signin.js @@ -2,17 +2,19 @@ 百度贴吧签到,增加重试机制,减少签到失败的情况。 脚本为串行执行,通过设定batchSize的值,实现每批多少个贴吧并行签到一次。 */ -const scirptName = "百度贴吧"; +const scriptName = "百度贴吧"; const batchSize = 20; const retries = 10; // 签到失败重试次数 const interval = 5000; // 每次重试间隔 const tiebaCookieKey = "tieba_signin_cookie"; -const tiebeGetCookieRegex1 = /https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login/; -const tiebeGetCookieRegex2 = /^https?:\/\/c\.tieba\.baidu\.com\/c\/s\/channelIconConfig/; -const tiebeGetCookieRegex3 = /https?:\/\/tiebac\.baidu\.com\/c\/u\/follow\/getFoldedMessageUserInfo/; +const tiebeGetCookieRegex1 = + /https?:\/\/(c\.tieba\.baidu\.com|180\.97\.\d+\.\d+)\/c\/s\/login/; +const tiebeGetCookieRegex2 = + /^https?:\/\/c\.tieba\.baidu\.com\/c\/s\/channelIconConfig/; +const tiebeGetCookieRegex3 = + /https?:\/\/tiebac\.baidu\.com\/c\/u\/follow\/getFoldedMessageUserInfo/; - -const $ = MagicJS(scirptName, "INFO"); +const $ = MagicJS(scriptName, "INFO"); let currentCookie = ""; function addCookie(config) { @@ -21,31 +23,35 @@ function addCookie(config) { } $.http.interceptors.request.use(addCookie); - function getTieBaList() { return new Promise((resolve, reject) => { - $.http.get({ - url: "https://tieba.baidu.com/mo/q/newmoindex", - headers: { - "Content-Type": "application/octet-stream", - "Referer": "https://tieba.baidu.com/index/tbwise/forum", - "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16A366", - }, - body: "" - }).then(resp => { - const obj = resp.body; - if (obj.error === "success") { - $.logger.info(`获取贴吧列表成功,共关注${obj.data.like_forum.length}个贴吧`); - resolve([obj.data.tbs, obj.data.like_forum]) - } - - }).catch(err => { - const errMsg = `获取贴吧列表失败,${err}`; - $.logger.error(); - $.notification.post("获取贴吧列表失败,请查阅日志"); - reject(errMsg); - }) - }) + $.http + .get({ + url: "https://tieba.baidu.com/mo/q/newmoindex", + headers: { + "Content-Type": "application/octet-stream", + Referer: "https://tieba.baidu.com/index/tbwise/forum", + "User-Agent": + "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16A366", + }, + body: "", + }) + .then((resp) => { + const obj = resp.body; + if (obj.error === "success") { + $.logger.info( + `获取贴吧列表成功,共关注${obj.data.like_forum.length}个贴吧` + ); + resolve([obj.data.tbs, obj.data.like_forum]); + } + }) + .catch((err) => { + const errMsg = `获取贴吧列表失败,${err}`; + $.logger.error(); + $.notification.post("获取贴吧列表失败,请查阅日志"); + reject(errMsg); + }); + }); } function tiebaSignIn(tbs, tieba) { @@ -53,80 +59,87 @@ function tiebaSignIn(tbs, tieba) { return new Promise((resolve, reject) => { if (tieba["is_sign"] === 1) { resolve(`[${kw}] 重复签到`); - } - else { + } else { let msg = ""; const body = `tbs=${tbs}&kw=${kw}&ie=utf-8`; - $.http.post({ - url: "https://tieba.baidu.com/sign/add", - headers: { - "Accept": "application/json, text/javascript, */*; q=0.01", - "Accept-Encoding": "gzip,deflate,br", - "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", - "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", - "Connection": "keep-alive", - "Host": "tieba.baidu.com", - "Referer": "https://tieba.baidu.com/", - "x-requested-with": "XMLHttpRequest", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36 Edg/84.0.522.63", - }, - body: body - }).then(resp => { - const obj = resp.body; - if (obj.data.errmsg === "success" && obj.data.errno === 0 && obj.data.uinfo.is_sign_in === 1) { - msg = `[${kw}] 签到成功 排名 ${obj.data.uinfo.user_sign_rank} 积分 ${obj.data.uinfo.cont_sign_num}`; - $.logger.info(msg); - resolve(msg); - } else { - if (obj.no === 2150040) { - msg = `[${kw}] 签到失败,need vcode`; - } else if (obj.no === 1011) { - msg = `[${kw}] 未加入此吧或等级不够`; + $.http + .post({ + url: "https://tieba.baidu.com/sign/add", + headers: { + Accept: "application/json, text/javascript, */*; q=0.01", + "Accept-Encoding": "gzip,deflate,br", + "Accept-Language": + "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", + "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", + Connection: "keep-alive", + Host: "tieba.baidu.com", + Referer: "https://tieba.baidu.com/", + "x-requested-with": "XMLHttpRequest", + "User-Agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36 Edg/84.0.522.63", + }, + body: body, + }) + .then((resp) => { + const obj = resp.body; + if ( + obj.data.errmsg === "success" && + obj.data.errno === 0 && + obj.data.uinfo.is_sign_in === 1 + ) { + msg = `[${kw}] 签到成功 排名 ${obj.data.uinfo.user_sign_rank} 积分 ${obj.data.uinfo.cont_sign_num}`; + $.logger.info(msg); + resolve(msg); + } else { + if (obj.no === 2150040) { + msg = `[${kw}] 签到失败,need vcode`; + } else if (obj.no === 1011) { + msg = `[${kw}] 未加入此吧或等级不够`; + } else if (obj.no === 1102) { + msg = `[${kw}] 签到过快`; + } else if (obj.no === 1101) { + msg = `[${kw}] 重复签到`; + } else if (obj.no === 1010) { + msg = `[${kw}] 目录出错`; + } else { + msg = `[${kw}] 签到失败`; + } + $.logger.warning(`${msg}\n${JSON.stringify(obj)}`); + reject(msg); } - else if (obj.no === 1102) { - msg = `[${kw}] 签到过快`; - } - else if (obj.no === 1101) { - msg = `[${kw}] 重复签到`; - } - else if (obj.no === 1010) { - msg = `[${kw}] 目录出错`; - } - else { - msg = `[${kw}] 签到失败`; - } - $.logger.warning(`${msg}\n${JSON.stringify(obj)}`); + }) + .catch((err) => { + msg = `[${kw}] 签到异常`; + $.logger.warning(`${kw} 签到异常\n${err}`); reject(msg); - } - }).catch(err => { - msg = `[${kw}] 签到异常`; - $.logger.warning(`${kw} 签到异常\n${err}`); - reject(msg); - }) + }); } - }) + }); } function getUserInfo() { return new Promise((resolve, reject) => { - $.http.get({ - url: "https://tieba.baidu.com/mo/q/sync", - headers: { - "Accept": "application/json, text/javascript, */*; q=0.01", - "Accept-Encoding": "gzip, deflate, br", - "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", - "Connection": "keep-alive", - "Host": "tieba.baidu.com", - "Referer": "https://tieba.baidu.com/home/main" - } - }).then(resp => { - if (resp.body.no === 0 && resp.body.error === "success") { - resolve(resp.body.data.user_id); - } - }).catch(err => { - $.logger.error(`获取用户信息出现出现异常,${err}`); - reject(err); - }) + $.http + .get({ + url: "https://tieba.baidu.com/mo/q/sync", + headers: { + Accept: "application/json, text/javascript, */*; q=0.01", + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", + Connection: "keep-alive", + Host: "tieba.baidu.com", + Referer: "https://tieba.baidu.com/home/main", + }, + }) + .then((resp) => { + if (resp.body.no === 0 && resp.body.error === "success") { + resolve(resp.body.data.user_id); + } + }) + .catch((err) => { + $.logger.error(`获取用户信息出现出现异常,${err}`); + reject(err); + }); }); } @@ -142,24 +155,32 @@ async function multiUsersSignIn() { currentCookie = $.data.read(tiebaCookieKey, null, sessionKey); if (!currentCookie) { continue; - } - else { + } else { $.logger.info(`当前正在进行第 ${index + 1} 个Cookie签到`); let content = "🥺很遗憾,以下贴吧签到失败:"; let success = 0; let failure = 0; - const [tbs, tiebaList] = await $.utils.retry(getTieBaList, retries, interval)(); + const [tbs, tiebaList] = await $.utils.retry( + getTieBaList, + retries, + interval + )(); const tiebaCount = tiebaList.length; const cycleNumber = Math.ceil(tiebaList.length / batchSize); for (let i = 0; i < cycleNumber; i++) { let batchTiebaPromise = []; const batchTiebaList = tiebaList.splice(0, batchSize); for (let tieba of batchTiebaList) { - batchTiebaPromise.push($.utils.retry(tiebaSignIn, retries, interval)(tbs, tieba)); + batchTiebaPromise.push( + $.utils.retry(tiebaSignIn, retries, interval)(tbs, tieba) + ); } await Promise.all(batchTiebaPromise).then((result) => { result.forEach((element) => { - if (element.indexOf("签到成功") < 0 && element.indexOf("重复签到") < 0) { + if ( + element.indexOf("签到成功") < 0 && + element.indexOf("重复签到") < 0 + ) { failure += 1; content += `\n${element}`; } else { @@ -168,47 +189,67 @@ async function multiUsersSignIn() { }); }); } - $.notification.post(scirptName, `签到${tiebaCount}个,成功${success}个,失败${failure}个!`, !!failure > 0 ? content : "🎉恭喜,所有贴吧签到成功!!"); + $.notification.post( + scriptName, + `签到${tiebaCount}个,成功${success}个,失败${failure}个!`, + !!failure > 0 ? content : "🎉恭喜,所有贴吧签到成功!!" + ); $.logger.info(`第 ${index + 1} 个Cookie签到完毕`); } } } (async () => { + try{ // 获取百度贴吧Cookie - if ($.isRequest && ( - tiebeGetCookieRegex1.test($.request.url) || - tiebeGetCookieRegex2.test($.request.url) || - tiebeGetCookieRegex3.test($.request.url)) + if ( + $.isRequest && + (tiebeGetCookieRegex1.test($.request.url) || + tiebeGetCookieRegex2.test($.request.url) || + tiebeGetCookieRegex3.test($.request.url)) ) { - const cookie = $.request.headers.Cookie; - currentCookie = cookie; - $.logger.info(`获取百度贴吧Cookies(请勿泄露):\n${cookie}`); - if (!!cookie) { - const userId = await getUserInfo(); - if (!userId) { - userId = "default"; - } - $.logger.info(`获取用户Id:${userId}`); - const result = $.data.update(tiebaCookieKey, cookie, userId); - if (result) { - const msg = "🎈获取百度贴吧Cookie成功"; - $.notification.post(msg); - $.logger.info(msg); - } - else { - $.logger.info("Cookie没有变化,无需更新") - } - const syncQinglong = $.data.read("tieba_sync_qinglong", false); - $.logger.info(`${syncQinglong === true ? "" : "不"}同步Cookie到青龙面板`); - if (syncQinglong === true) { - const msg = "🎈百度贴吧Cookie同步到青龙面板成功"; - const syncQinglong = await $.qinglong.update(tiebaCookieKey, cookie, userId); - if (syncQinglong) { + try { + const cookie = $.request.headers.Cookie; + currentCookie = cookie; + $.logger.info(`获取百度贴吧Cookies(请勿泄露):\n${cookie}`); + if (!!cookie) { + const userId = await getUserInfo(); + if (!userId) { + userId = "default"; + } + $.logger.info(`获取用户Id:${userId}`); + const result = $.data.update(tiebaCookieKey, cookie, userId); + if (result) { + const msg = "🎈获取百度贴吧Cookie成功"; $.notification.post(msg); $.logger.info(msg); + } else { + $.logger.info("Cookie没有变化,无需更新"); + } + const syncQinglong = $.data.read("tieba_sync_qinglong", false); + $.logger.info( + `${syncQinglong === true ? "" : "不"}同步Cookie到青龙面板` + ); + if (syncQinglong === true) { + const msg = "🎈百度贴吧Cookie同步到青龙面板成功"; + const result = await $.qinglong.update( + tiebaCookieKey, + cookie, + userId + ); + if (result) { + $.notification.post(msg); + $.notification.post( + `${scriptName} - ${userId}`, + "", + `已将您的信息同步至青龙面板:\n${$.qinglong.url}\n如上述地址不是您所配置,则信息已泄露!\n请立即停用脚本,更改密码!\n检查青龙面板配置是否被篡改!` + ); + $.logger.info(msg); + } } } + } catch (err) { + $.logger.error(err); } } // 签到 @@ -216,21 +257,35 @@ async function multiUsersSignIn() { await multiUsersSignIn(); } $.done(); -})(); +} +catch(err){ + console.log("出错了" + err); +}finally{$.done()}})(); /** - * - * $$\ $$\ $$\ $$$$$\ $$$$$$\ $$$$$$\ - * $$$\ $$$ | \__| \__$$ |$$ __$$\ $$ ___$$\ + * + * $$\ $$\ $$\ $$$$$\ $$$$$$\ $$$$$$\ + * $$$\ $$$ | \__| \__$$ |$$ __$$\ $$ ___$$\ * $$$$\ $$$$ | $$$$$$\ $$$$$$\ $$\ $$$$$$$\ $$ |$$ / \__| \_/ $$ | - * $$\$$\$$ $$ | \____$$\ $$ __$$\ $$ |$$ _____| $$ |\$$$$$$\ $$$$$ / - * $$ \$$$ $$ | $$$$$$$ |$$ / $$ |$$ |$$ / $$\ $$ | \____$$\ \___$$\ + * $$\$$\$$ $$ | \____$$\ $$ __$$\ $$ |$$ _____| $$ |\$$$$$$\ $$$$$ / + * $$ \$$$ $$ | $$$$$$$ |$$ / $$ |$$ |$$ / $$\ $$ | \____$$\ \___$$\ * $$ |\$ /$$ |$$ __$$ |$$ | $$ |$$ |$$ | $$ | $$ |$$\ $$ | $$\ $$ | * $$ | \_/ $$ |\$$$$$$$ |\$$$$$$$ |$$ |\$$$$$$$\\$$$$$$ |\$$$$$$ | \$$$$$$ | - * \__| \__| \_______| \____$$ |\__| \_______|\______/ \______/ \______/ - * $$\ $$ | - * \$$$$$$ | - * \______/ - * -*/ -function MagicJS(e = "MagicJS", t = "INFO") { const r = () => { const e = typeof $loon !== "undefined"; const t = typeof $task !== "undefined"; const n = typeof module !== "undefined"; const r = typeof $httpClient !== "undefined" && !e; const i = typeof $storm !== "undefined"; const o = typeof $environment !== "undefined" && typeof $environment["stash-build"] !== "undefined"; const s = r || e || i || o; const a = typeof importModule !== "undefined"; return { isLoon: e, isQuanX: t, isNode: n, isSurge: r, isStorm: i, isStash: o, isSurgeLike: s, isScriptable: a, get name() { if (e) { return "Loon" } else if (t) { return "QuantumultX" } else if (n) { return "NodeJS" } else if (r) { return "Surge" } else if (a) { return "Scriptable" } else { return "unknown" } }, get build() { if (r) { return $environment["surge-build"] } else if (o) { return $environment["stash-build"] } else if (i) { return $storm.buildVersion } }, get language() { if (r || o) { return $environment["language"] } }, get version() { if (r) { return $environment["surge-version"] } else if (o) { return $environment["stash-version"] } else if (i) { return $storm.appVersion } else if (n) { return process.version } }, get system() { if (r) { return $environment["system"] } else if (n) { return process.platform } }, get systemVersion() { if (i) { return $storm.systemVersion } }, get deviceName() { if (i) { return $storm.deviceName } } } }; const i = (n, e = "INFO") => { let r = e; const i = { SNIFFER: 6, DEBUG: 5, INFO: 4, NOTIFY: 3, WARNING: 2, ERROR: 1, CRITICAL: 0, NONE: -1 }; const o = { SNIFFER: "", DEBUG: "", INFO: "", NOTIFY: "", WARNING: "❗ ", ERROR: "❌ ", CRITICAL: "❌ ", NONE: "" }; const t = (e, t = "INFO") => { if (!(i[r] < i[t.toUpperCase()])) console.log(`[${t}] [${n}]\n${o[t.toUpperCase()]}${e}\n`) }; const s = e => { r = e }; return { setLevel: s, sniffer: e => { t(e, "SNIFFER") }, debug: e => { t(e, "DEBUG") }, info: e => { t(e, "INFO") }, notify: e => { t(e, "NOTIFY") }, warning: e => { t(e, "WARNING") }, error: e => { t(e, "ERROR") }, retry: e => { t(e, "RETRY") } } }; return new class { constructor(e, t) { this._startTime = Date.now(); this.version = "3.0.0"; this.scriptName = e; this.env = r(); this.logger = i(e, t); this.http = typeof MagicHttp === "function" ? MagicHttp(this.env, this.logger) : undefined; this.data = typeof MagicData === "function" ? MagicData(this.env, this.logger) : undefined; this.notification = typeof MagicNotification === "function" ? MagicNotification(this.scriptName, this.env, this.logger, this.http) : undefined; this.utils = typeof MagicUtils === "function" ? MagicUtils(this.env, this.logger) : undefined; this.qinglong = typeof MagicQingLong === "function" ? MagicQingLong(this.env, this.data, this.logger) : undefined; if (typeof this.data !== "undefined") { let e = this.data.read("magic_loglevel"); const n = this.data.read("magic_bark_url"); if (e) { this.logger.setLevel(e.toUpperCase()) } if (n) { this.notification.setBark(n) } } } get isRequest() { return typeof $request !== "undefined" && typeof $response === "undefined" } get isResponse() { return typeof $response !== "undefined" } get isDebug() { return this.logger.level === "DEBUG" } get request() { return typeof $request !== "undefined" ? $request : undefined } get response() { if (typeof $response !== "undefined") { if ($response.hasOwnProperty("status")) $response["statusCode"] = $response["status"]; if ($response.hasOwnProperty("statusCode")) $response["status"] = $response["statusCode"]; return $response } else { return undefined } } done = (e = {}) => { this._endTime = Date.now(); let t = (this._endTime - this._startTime) / 1e3; this.logger.info(`SCRIPT COMPLETED: ${t} S.`); if (typeof $done !== "undefined") { $done(e) } } }(e, t) } function MagicHttp(u, c) { const t = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Mobile/15E148 Safari/604.1"; const n = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36 Edg/84.0.522.59"; let f; if (u.isNode) { const a = require("axios"); f = a.create() } class e { constructor(e = true) { this.handlers = []; this.isRequest = e } use(e, t, n) { this.handlers.push({ fulfilled: e, rejected: t, synchronous: n ? n.synchronous : false, runWhen: n ? n.runWhen : null }); return this.handlers.length - 1 } eject(e) { if (this.handlers[e]) { this.handlers[e] = null } } forEach(t) { this.handlers.forEach(e => { if (e !== null) { t(e) } }) } } function r(e) { let n = { ...e }; if (!!n.params) { if (!u.isNode) { let e = Object.keys(n.params).map(e => { const t = encodeURIComponent(e); n.url = n.url.replace(new RegExp(`${e}=[^&]*`, "ig"), ""); n.url = n.url.replace(new RegExp(`${t}=[^&]*`, "ig"), ""); return `${t}=${encodeURIComponent(n.params[e])}` }).join("&"); if (n.url.indexOf("?") < 0) n.url += "?"; if (!/(&|\?)$/g.test(n.url)) { n.url += "&" } n.url += e; delete n.params; c.debug(`Params to QueryString: ${n.url}`) } } return n } const d = (e, t) => { let n = typeof t === "object" ? { headers: {}, ...t } : { url: t, headers: {} }; if (!n.method) { n["method"] = e } n = r(n); if (n["rewrite"] === true) { if (u.isSurge) { n.headers["X-Surge-Skip-Scripting"] = false; delete n["rewrite"] } else if (u.isQuanX) { n["hints"] = false; delete n["rewrite"] } } if (u.isSurge) { if (n["method"] !== "GET" && n.headers["Content-Type"].indexOf("application/json") >= 0 && n.body instanceof Array) { n.body = JSON.stringify(n.body); c.debug(`Convert Array object to String: ${n.body}`) } } else if (u.isQuanX) { if (n.hasOwnProperty("body") && typeof n["body"] !== "string") n["body"] = JSON.stringify(n["body"]); n["method"] = e } else if (u.isNode) { if (e === "POST" || e === "PUT" || e === "PATCH" || e === "DELETE") { n.data = n.data || n.body } else if (e === "GET") { n.params = n.params || n.body } delete n.body } return n }; const p = (t, n = null) => { if (t) { let e = { ...t, config: t.config || n, status: t.statusCode || t.status, body: t.body || t.data, headers: t.headers || t.header }; if (typeof e.body === "string") { try { e.body = JSON.parse(e.body) } catch { } } delete t.data; return e } else { return t } }; const i = r => { if (!!r) { delete r["Content-Length"]; let e = new Set(["Accept", "Accept-CH", "Accept-Charset", "Accept-Features", "Accept-Encoding", "Accept-Language", "Accept-Ranges", "Access-Control-Allow-Credentials", "Access-Control-Allow-Origin", "Access-Control-Allow-Methods", "Access-Control-Allow-Headers", "Access-Control-Max-Age", "Access-Control-Expose-Headers", "Access-Control-Request-Method", "Access-Control-Request-Headers", "Age", "Allow", "Alternates", "Authorization", "Cache-Control", "Connection", "Content-Encoding", "Content-Language", "ontent-Length", "Content-Location", "Content-Range", "Content-Security-Policy", "Content-Type", "Cookie", "DNT", "Date", "ETag", "Expect", "Expires", "From", "Host", "If-Match", "If-Modified-Since", "If-None-Match", "If-Range", "If-Unmodified-Since", "Last-Event-ID", "Last-Modified", "Link", "Location", "Max-Forwards", "Negotiate", "Origin", "Pragma", "Proxy-Authenticate", "Proxy-Authorization", "Range", "Referer", "Retry-After", "Sec-Websocket-Extensions", "Sec-Websocket-Key", "Sec-Websocket-Origin", "Sec-Websocket-Protocol", "Sec-Websocket-Version", "Server", "Set-Cookie", "Set-Cookie2", "Strict-Transport-Security", "TCN", "TE", "Trailer", "Transfer-Encoding", "Upgrade", "User-Agent", "Variant-Vary", "Vary", "Via", "Warning", "WWW-Authenticate", "X-Content-Duration", "X-Content-Security-Policy", "X-DNSPrefetch-Control", "X-Frame-Options", "X-Requested-With"]); for (let n of Object.keys(r)) { if (!e.has(n)) { for (let t of e) { let e = n.replace(new RegExp(t, "ig"), t); if (n !== e) { r[e] = r[n]; delete r[n]; break } } } } if (!r["User-Agent"]) { if (u.isNode) { r["User-Agent"] = n } else { r["User-Agent"] = t } } return r } return r }; const g = (t, n = null) => { if (!!t && t.status >= 400) { c.debug(`Raise exception when status code is ${t.status}`); let e = { name: "RequestException", message: `Request failed with status code ${t.status}`, config: n || t.config, response: t }; return e } }; const o = { request: new e, response: new e(false) }; let y = []; let h = []; let m = true; function $(e) { if (typeof e === "object" && e["modify"] !== false) { e["headers"] = i(e["headers"]) } e = r(e); return e } function b(e) { try { e = !!e ? p(e) : e; c.sniffer(`HTTP ${e.config["method"].toUpperCase()}:\n${JSON.stringify(e.config)}\nSTATUS CODE:\n${e.status}\nRESPONSE:\n${typeof e.body === "object" ? JSON.stringify(e.body) : e.body}`); const t = g(e); if (!!t) { return Promise.reject(t) } return e } catch (t) { c.error(t); return e } } const S = t => { try { y = []; h = []; o.request.forEach(e => { if (typeof e.runWhen === "function" && e.runWhen(t) === false) { return } m = m && e.synchronous; y.unshift(e.fulfilled, e.rejected) }); o.response.forEach(e => { h.push(e.fulfilled, e.rejected) }) } catch (e) { c.error(`failed to register interceptors: ${e}`) } }; const s = (e, r) => { let i; const t = e.toUpperCase(); r = d(t, r); if (u.isNode) { i = f } else { if (u.isSurgeLike) { i = o => { return new Promise((r, i) => { $httpClient[e.toLowerCase()](o, (t, n, e) => { if (t) { let e = { name: t.name || t, message: t.message || t, stack: t.stack || t, config: o, response: p(n) }; i(e) } else { n.config = o; n.body = e; r(n) } }) }) } } else { i = i => { return new Promise((n, r) => { $task.fetch(i).then(e => { e = p(e, i); const t = g(e, i); if (t) { return Promise.reject(t) } n(e) }).catch(e => { let t = { name: e.message || e.error, message: e.message || e.error, stack: e.error, config: i, response: !!e.response ? p(e.response) : null }; r(t) }) }) } } } let o; S(r); const s = [$, undefined]; const a = [b, undefined]; if (!m) { c.debug("Interceptors are executed in asynchronous mode"); let n = [i, undefined]; Array.prototype.unshift.apply(n, s); Array.prototype.unshift.apply(n, y); Array.prototype.unshift.apply(n, s); n = n.concat(a); n = n.concat(h); o = Promise.resolve(r); while (n.length) { try { let e = n.shift(); let t = n.shift(); if (!u.isNode && r["timeout"] && e === i) { o = l(r) } else { o = o.then(e, t) } } catch (e) { c.error(`request exception: ${e}`) } } return o } else { c.debug("Interceptors are executed in synchronous mode"); Array.prototype.unshift.apply(y, s); y = y.concat([$, undefined]); while (y.length) { let e = y.shift(); let t = y.shift(); try { r = e(r) } catch (e) { t(e); break } } try { if (!u.isNode && r["timeout"]) { o = l(r) } else { o = i(r) } } catch (e) { return Promise.reject(e) } Array.prototype.unshift.apply(h, a); while (h.length) { o = o.then(h.shift(), h.shift()) } return o } function l(n) { try { const e = new Promise((e, t) => { setTimeout(() => { let e = { message: `timeout of ${n["timeout"]}ms exceeded`, config: n }; t(e) }, n["timeout"]) }); return Promise.race([i(n), e]) } catch (e) { c.error(`Request Timeout exception: ${e}`) } } }; return { request: s, interceptors: o, modifyHeaders: i, modifyResponse: p, get: e => { return s("GET", e) }, post: e => { return s("POST", e) }, put: e => { return s("PUT", e) }, patch: e => { return s("PATCH", e) }, delete: e => { return s("DELETE", e) }, head: e => { return s("HEAD", e) }, options: e => { return s("OPTIONS", e) } } } function MagicNotification(o, s, a, l) { let u = null; let c = null; const e = t => { try { let e = t.replace(/\/+$/g, ""); u = `${/^https?:\/\/([^/]*)/.exec(e)[0]}/push`; c = /\/([^\/]+)\/?$/.exec(e)[1] } catch (e) { a.error(`Bark url error: ${e}.`) } }; function t(e = o, t = "", n = "", r = "") { const i = n => { try { let t = {}; if (typeof n === "string") { if (s.isLoon) t = { openUrl: n }; else if (s.isQuanX) t = { "open-url": n }; else if (s.isSurge) t = { url: n } } else if (typeof n === "object") { if (s.isLoon) { t["openUrl"] = !!n["open-url"] ? n["open-url"] : ""; t["mediaUrl"] = !!n["media-url"] ? n["media-url"] : "" } else if (s.isQuanX) { t = !!n["open-url"] || !!n["media-url"] ? n : {} } else if (s.isSurge) { let e = n["open-url"] || n["openUrl"]; t = e ? { url: e } : {} } } return t } catch (e) { a.error(`Failed to convert notification option, ${e}`) } return n }; r = i(r); if (arguments.length == 1) { e = o; t = "", n = arguments[0] } a.notify(`title:${e}\nsubTitle:${t}\nbody:${n}\noptions:${typeof r === "object" ? JSON.stringify(r) : r}`); if (s.isSurge) { $notification.post(e, t, n, r) } else if (s.isLoon) { if (!!r) $notification.post(e, t, n, r); else $notification.post(e, t, n) } else if (s.isQuanX) { $notify(e, t, n, r) } if (u && c) { f(e, t, n) } } function n(e = o, t = "", n = "", r = "") { if (a.level === "DEBUG") { if (arguments.length == 1) { e = o; t = "", n = arguments[0] } this.notify(e, t, n, r) } } function f(e = o, t = "", n = "", r = "") { if (typeof l === "undefined" || typeof l.post === "undefined") { throw "Bark notification needs to import MagicHttp module." } let i = { url: u, headers: { "Content-Type": "application/json; charset=utf-8" }, body: { title: e, body: t ? `${t}\n${n}` : n, device_key: c } }; l.post(i).catch(e => { a.error(`Bark notify error: ${e}`) }) } return { post: t, debug: n, bark: f, setBark: e } } function MagicData(s, a) { let l = { fs: undefined, data: {} }; if (s.isNode) { l.fs = require("fs"); try { l.fs.accessSync("./magic.json", l.fs.constants.R_OK | l.fs.constants.W_OK) } catch (e) { l.fs.writeFileSync("./magic.json", "{}", { encoding: "utf8" }) } l.data = require("./magic.json") } const u = (e, t) => { if (typeof t === "object") { return false } else { return e === t } }; const c = e => { if (e === "true") { return true } else if (e === "false") { return false } else if (typeof e === "undefined") { return null } else { return e } }; const f = (e, t, n, r) => { if (n) { try { if (typeof e === "string") e = JSON.parse(e); if (e["magic_session"] === true) { e = e[n] } else { e = null } } catch { e = null } } if (typeof e === "string" && e !== "null") { try { e = JSON.parse(e) } catch { } } if (r === false && !!e && e["magic_session"] === true) { e = null } if ((e === null || typeof e === "undefined") && t !== null && typeof t !== "undefined") { e = t } e = c(e); return e }; const o = t => { if (typeof t === "string") { let e = {}; try { e = JSON.parse(t); const n = typeof e; if (n !== "object" || e instanceof Array || n === "bool" || e === null) { e = {} } } catch { } return e } else if (t instanceof Array || t === null || typeof t === "undefined" || t !== t || typeof t === "boolean") { return {} } else { return t } }; const d = (e, t = null, n = "", r = false, i = null) => { let o = i || l.data; if (!!o && typeof o[e] !== "undefined" && o[e] !== null) { val = o[e] } else { val = !!n ? {} : null } val = f(val, t, n, r); return val }; const p = (e, t = null, n = "", r = false, i = null) => { let o = ""; if (i || s.isNode) { o = d(e, t, n, r, i) } else { if (s.isSurgeLike) { o = $persistentStore.read(e) } else if (s.isQuanX) { o = $prefs.valueForKey(e) } o = f(o, t, n, r) } a.debug(`READ DATA [${e}]${!!n ? `[${n}]` : ""} <${typeof o}>\n${JSON.stringify(o)}`); return o }; const g = (t, n, r = "", e = null) => { let i = e || l.data; i = o(i); if (!!r) { let e = o(i[t]); e["magic_session"] = true; e[r] = n; i[t] = e } else { i[t] = n } if (e !== null) { e = i } return i }; const y = (e, t, n = "", r = null) => { if (typeof t === "undefined" || t !== t) { return false } if (!s.isNode && (typeof t === "boolean" || typeof t === "number")) { t = String(t) } let i = ""; if (r || s.isNode) { i = g(e, t, n, r) } else { if (!n) { i = t } else { if (s.isSurgeLike) { i = !!$persistentStore.read(e) ? $persistentStore.read(e) : i } else if (s.isQuanX) { i = !!$prefs.valueForKey(e) ? $prefs.valueForKey(e) : i } i = o(i); i["magic_session"] = true; i[n] = t } } if (!!i && typeof i === "object") { i = JSON.stringify(i, "", "\t") } a.debug(`WRITE DATA [${e}]${n ? `[${n}]` : ""} <${typeof t}>\n${JSON.stringify(t)}`); if (!r) { if (s.isSurgeLike) { return $persistentStore.write(i, e) } else if (s.isQuanX) { return $prefs.setValueForKey(i, e) } else if (s.isNode) { try { l.fs.writeFileSync("./magic.json", i); return true } catch (e) { a.error(e); return false } } } return true }; const e = (t, n, r, i = u, o = null) => { n = c(n); const e = p(t, null, r, false, o); if (i(e, n) === true) { return false } else { const s = y(t, n, r, o); let e = p(t, null, r, false, o); if (i === u && typeof e === "object") { return s } return i(n, e) } }; const h = (e, t, n) => { let r = n || l.data; r = o(r); if (!!t) { obj = o(r[e]); delete obj[t]; r[e] = obj } else { delete r[e] } if (!!n) { n = r } return r }; const t = (e, t = "", n = null) => { let r = {}; if (n || s.isNode) { r = h(e, t, n); if (!n) { l.fs.writeFileSync("./magic.json", JSON.stringify(r)) } else { n = r } } else { if (!t) { if (s.isStorm) { return $persistentStore.remove(e) } else if (s.isSurgeLike) { return $persistentStore.write(null, e) } else if (s.isQuanX) { return $prefs.removeValueForKey(e) } } else { if (s.isSurgeLike) { r = $persistentStore.read(e) } else if (s.isQuanX) { r = $prefs.valueForKey(e) } r = o(r); delete r[t]; const i = JSON.stringify(r); y(e, i) } } a.debug(`DELETE KEY [${e}]${!!t ? `[${t}]` : ""}`) }; const n = (e, t = null) => { let n = []; let r = p(e, null, null, true, t); r = o(r); if (r["magic_session"] !== true) { n = [] } else { n = Object.keys(r).filter(e => e !== "magic_session") } a.debug(`READ ALL SESSIONS [${e}] <${typeof n}>\n${JSON.stringify(n)}`); return n }; return { read: p, write: y, del: t, update: e, allSessions: n, defaultValueComparator: u, convertToObject: o } } function MagicUtils(r, u) { const e = (o, s = 5, a = 0, l = null) => { return (...e) => { return new Promise((n, r) => { function i(...t) { Promise.resolve().then(() => o.apply(this, t)).then(e => { if (typeof l === "function") { Promise.resolve().then(() => l(e)).then(() => { n(e) }).catch(e => { if (s >= 1) { if (a > 0) setTimeout(() => i.apply(this, t), a); else i.apply(this, t) } else { r(e) } s-- }) } else { n(e) } }).catch(e => { u.error(e); if (s >= 1 && a > 0) { setTimeout(() => i.apply(this, t), a) } else if (s >= 1) { i.apply(this, t) } else { r(e) } s-- }) } i.apply(this, e) }) } }; const t = (e, t = "yyyy-MM-dd hh:mm:ss") => { let n = { "M+": e.getMonth() + 1, "d+": e.getDate(), "h+": e.getHours(), "m+": e.getMinutes(), "s+": e.getSeconds(), "q+": Math.floor((e.getMonth() + 3) / 3), S: e.getMilliseconds() }; if (/(y+)/.test(t)) t = t.replace(RegExp.$1, (e.getFullYear() + "").substr(4 - RegExp.$1.length)); for (let e in n) if (new RegExp("(" + e + ")").test(t)) t = t.replace(RegExp.$1, RegExp.$1.length == 1 ? n[e] : ("00" + n[e]).substr(("" + n[e]).length)); return t }; const n = () => { return t(new Date, "yyyy-MM-dd hh:mm:ss") }; const i = () => { return t(new Date, "yyyy-MM-dd") }; const o = t => { return new Promise(e => setTimeout(e, t)) }; const s = (e, t = null) => { if (r.isNode) { const n = require("assert"); if (t) n(e, t); else n(e) } else { if (e !== true) { let e = `AssertionError: ${t || "The expression evaluated to a falsy value"}`; u.error(e) } } }; return { retry: e, formatTime: t, now: n, today: i, sleep: o, assert: s } } function MagicQingLong(e, l, i) { let o = ""; let s = ""; let a = ""; let u = ""; let c = ""; let t = ""; const f = "magic.json"; const n = 3e3; const d = MagicHttp(e, i); const r = (e, t, n, r, i) => { o = e; a = t; u = n; s = r; c = i }; function p(e) { o = o || l.read("magic_qlurl"); t = t || l.read("magic_qltoken"); return e } function g(e) { if (!o) { o = l.read("magic_qlurl") } if (e.url.indexOf(o) < 0) { e.url = `${o}${e.url}` } return { ...e, timeout: n } } function y(e) { e.params = { ...e.params, t: Date.now() }; return e } function h(e) { t = t || l.read("magic_qltoken"); if (t) { e.headers["Authorization"] = `Bearer ${t}` } return e } function m(e) { a = a || l.read("magic_qlclient"); if (!!a) { e.url = e.url.replace("/api/", "/open/") } return e } async function $(e) { try { const t = e.message || e.error || JSON.stringify(e); if ((t.indexOf("NSURLErrorDomain") >= 0 && t.indexOf("-1012") >= 0 || !!e.response && e.response.status === 401) && (!!e.config && e.config.refreshToken !== true)) { i.warning(`Qinglong panel token has expired`); await b(); e.config["refreshToken"] = true; return await d.request(e.config.method, e.config) } else { return Promise.reject(e) } } catch (e) { return Promise.reject(e) } } d.interceptors.request.use(p, undefined); d.interceptors.request.use(g, undefined); d.interceptors.request.use(m, undefined, { runWhen: e => { return e.url.indexOf("api/user/login") < 0 && e.url.indexOf("open/auth/token") < 0 } }); d.interceptors.request.use(h, undefined, { runWhen: e => { return e.url.indexOf("api/user/login") < 0 && e.url.indexOf("open/auth/token") < 0 } }); d.interceptors.request.use(y, undefined, { runWhen: e => { return e.url.indexOf("open/auth/token") < 0 && e.url.indexOf("t=") < 0 } }); d.interceptors.response.use(undefined, $); async function b() { a = a || l.read("magic_qlclient"); u = u || l.read("magic_qlsecrt"); s = s || l.read("magic_qlname"); c = c || l.read("magic_qlpwd"); if (o && a && u) { await d.get({ url: `/open/auth/token`, headers: { "Content-Type": "application/json" }, params: { client_id: a, client_secret: u } }).then(e => { i.info("Log in to Qinglong panel successfully"); t = e.body.data.token; l.update("magic_qltoken", t); return t }).catch(e => { i.error(`Failed to log in to Qinglong panel.\n${e.message}`) }) } else if (o && s && c) { await d.post({ url: `/api/user/login`, headers: { "Content-Type": "application/json" }, body: { username: s, password: c } }).then(e => { i.info("Log in to Qinglong panel successfully"); t = e.body.data.token; l.update("magic_qltoken", t); return t }).catch(e => { i.error(`Failed to log in to Qinglong panel.\n${e.message}`) }) } } async function S(t, n, r = null) { o = o || l.read("magic_qlurl"); if (r === null) { let e = await N([{ name: t, value: n }]); if (!!e && e.length === 1) { return e[0] } } else { d.put({ url: `/api/envs`, headers: { "Content-Type": "application/json" }, body: { name: t, value: n, id: r } }).then(e => { if (e.body.code === 200) { i.debug(`QINGLONG UPDATE ENV ${t} <${typeof n}> (${r})\n${JSON.stringify(n)}`); return true } else { i.error(`Failed to update Qinglong panel environment variable.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to update Qinglong panel environment variable.\n${e.message}`); return false }) } } async function N(e) { let t = []; await d.post({ url: `/api/envs`, headers: { "Content-Type": "application/json" }, body: e }).then(e => { if (e.body.code === 200) { e.body.data.forEach(e => { i.debug(`QINGLONG ADD ENV ${e.name} <${typeof e.value}> (${e.id})\n${JSON.stringify(e)}`); t.push(e.id) }) } else { i.error(`Failed to add Qinglong panel environment variable.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to add Qinglong panel environment variable.\n${e.message}`) }); return t } async function v(t) { return await d.delete({ url: `/api/envs`, headers: { Accept: "application/json", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", Connection: "keep-alive", "Content-Type": "application/json;charset=UTF-8", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30" }, body: t }).then(e => { if (e.body.code === 200) { i.debug(`QINGLONG DELETE ENV IDS: ${t}`); return true } else { i.error(`Failed to delete QingLong envs.\n${JSON.stringify(e)}`); return false } }).catch(e => { i.error(`Failed to delete QingLong envs.\n${e.message}`) }) } async function O(n = null, e = "") { let r = []; await d.get({ url: `/api/envs`, headers: { "Content-Type": "application/json" }, params: { searchValue: e } }).then(e => { if (e.body.code === 200) { const t = e.body.data; if (!!n) { let e = []; for (const e of t) { if (e.name === n) { r.push(e) } } r = e } r = t } else { i.error(`Failed to get environment variables from Qinglong panel.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to get environment variables from Qinglong panel.\n${JSON.stringify(e)}`) }); return r } async function E(e) { let t = null; const n = await O(); for (const r of n) { if (r.id === e) { t = r; break } } return t } async function T(t) { let n = false; await d.put({ url: `/api/envs/disable`, headers: { Accept: "application/json", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", Connection: "keep-alive", "Content-Type": "application/json;charset=UTF-8", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30" }, body: t }).then(e => { if (e.body.code === 200) { i.debug(`QINGLONG DISABLED ENV IDS: ${t}`); n = true } else { i.error(`Failed to disable QingLong envs.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to disable QingLong envs.\n${e.message}`) }); return n } async function w(t) { let n = false; await d.put({ url: `/api/envs/enable`, headers: { Accept: "application/json", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", Connection: "keep-alive", "Content-Type": "application/json;charset=UTF-8", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30" }, body: t }).then(e => { if (e.body.code === 200) { i.debug(`QINGLONG ENABLED ENV IDS: ${t}`); n = true } else { i.error(`Failed to enable QingLong envs.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to enable QingLong envs.\n${e.message}`) }); return n } async function C(e, t = "", n = "") { let r = false; await d.post({ url: `/api/scripts`, headers: { "Content-Type": "application/json" }, body: { filename: e, path: t, content: n } }).then(e => { if (e.body.code === 200) { r = true } else { i.error(`Failed to add script content from Qinglong panel.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to add script content from Qinglong panel.\n${e.message}`) }); return r } async function A(e, t = "") { let n = ""; await d.get({ url: `/api/scripts/${e}`, params: { path: t } }).then(e => { if (e.body.code === 200) { n = e.body.data } else { i.error(`Failed to read script content from Qinglong panel.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to read script content from Qinglong panel.\n${e.message}`) }); return n } async function k(e, t = "", n = "") { let r = false; await d.put({ url: `/api/scripts`, headers: { "Content-Type": "application/json" }, body: { filename: e, path: t, content: n } }).then(e => { if (e.body.code === 200) { r = true } else { i.error(`Failed to read script content from Qinglong panel.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to read script content from Qinglong panel.\n${e.message}`) }); return r } async function L(e, t = "") { let n = false; await d.delete({ url: `/api/scripts`, headers: { "Content-Type": "application/json" }, body: { filename: e, path: t } }).then(e => { if (e.body.code === 200) { n = true } else { i.error(`Failed to read script content from Qinglong panel.\n${JSON.stringify(e)}`) } }).catch(e => { i.error(`Failed to read script content from Qinglong panel.\n${e.message}`) }); return n } async function F(e, t, n = "") { let r = await A(f, ""); let i = l.convertToObject(r); let o = l.write(e, t, n, i); r = JSON.stringify(i, "", "\t"); let s = await k(f, "", r); return s && o } async function j(e, t, n, r = l.defaultValueComparator) { let i = await A(f, ""); let o = l.convertToObject(i); const s = l.update(e, t, n, r, o); let a = false; if (s === true) { i = JSON.stringify(o, "", "\t"); a = await k(f, "", i) } return s && a } async function M(e, t, n = "") { let r = await A(f, ""); let i = l.convertToObject(r); const o = l.read(e, t, n, false, i); return o } async function R(e, t = "") { let n = await A(f, ""); let r = l.convertToObject(n); const i = l.del(e, t, r); n = JSON.stringify(r, "", "\t"); const o = await k(f, "", n); return i && o } async function q(e) { let t = await A(f, ""); let n = l.convertToObject(t); const r = l.allSessions(e, n); return r } return { init: r, getToken: b, setEnv: S, setEnvs: N, getEnv: E, getEnvs: O, delEnvs: v, disableEnvs: T, enbleEnvs: w, addScript: C, getScript: A, editScript: k, delScript: L, write: F, read: M, del: R, update: j, allSessions: q } } \ No newline at end of file + * \__| \__| \_______| \____$$ |\__| \_______|\______/ \______/ \______/ + * $$\ $$ | + * \$$$$$$ | + * \______/ + * + */ +// prettier-ignore +function MagicJS(e="MagicJS",t="INFO"){const i=()=>{const e=typeof $loon!=="undefined";const t=typeof $task!=="undefined";const n=typeof module!=="undefined";const i=typeof $httpClient!=="undefined"&&!e;const s=typeof $storm!=="undefined";const r=typeof $environment!=="undefined"&&typeof $environment["stash-build"]!=="undefined";const o=i||e||s||r;const u=typeof importModule!=="undefined";return{isLoon:e,isQuanX:t,isNode:n,isSurge:i,isStorm:s,isStash:r,isSurgeLike:o,isScriptable:u,get name(){if(e){return"Loon"}else if(t){return"QuantumultX"}else if(n){return"NodeJS"}else if(i){return"Surge"}else if(u){return"Scriptable"}else{return"unknown"}},get build(){if(i){return $environment["surge-build"]}else if(r){return $environment["stash-build"]}else if(s){return $storm.buildVersion}},get language(){if(i||r){return $environment["language"]}},get version(){if(i){return $environment["surge-version"]}else if(r){return $environment["stash-version"]}else if(s){return $storm.appVersion}else if(n){return process.version}},get system(){if(i){return $environment["system"]}else if(n){return process.platform}},get systemVersion(){if(s){return $storm.systemVersion}},get deviceName(){if(s){return $storm.deviceName}}}};const s=(n,e="INFO")=>{let i=e;const s={SNIFFER:6,DEBUG:5,INFO:4,NOTIFY:3,WARNING:2,ERROR:1,CRITICAL:0,NONE:-1};const r={SNIFFER:"",DEBUG:"",INFO:"",NOTIFY:"",WARNING:"❗ ",ERROR:"❌ ",CRITICAL:"❌ ",NONE:""};const t=(e,t="INFO")=>{if(!(s[i]{i=e};return{setLevel:o,sniffer:e=>{t(e,"SNIFFER")},debug:e=>{t(e,"DEBUG")},info:e=>{t(e,"INFO")},notify:e=>{t(e,"NOTIFY")},warning:e=>{t(e,"WARNING")},error:e=>{t(e,"ERROR")},retry:e=>{t(e,"RETRY")}}};return new class{constructor(e,t){this._startTime=Date.now();this.version="3.0.0";this.scriptName=e;this.env=i();this.logger=s(e,t);this.http=typeof MagicHttp==="function"?MagicHttp(this.env,this.logger):undefined;this.data=typeof MagicData==="function"?MagicData(this.env,this.logger):undefined;this.notification=typeof MagicNotification==="function"?MagicNotification(this.scriptName,this.env,this.logger):undefined;this.utils=typeof MagicUtils==="function"?MagicUtils(this.env,this.logger):undefined;this.qinglong=typeof MagicQingLong==="function"?MagicQingLong(this.env,this.data,this.logger):undefined;if(typeof this.data!=="undefined"){let e=this.data.read("magic_loglevel");const n=this.data.read("magic_bark_url");if(e){this.logger.setLevel(e.toUpperCase())}if(n){this.notification.setBark(n)}}}get isRequest(){return typeof $request!=="undefined"&&typeof $response==="undefined"}get isResponse(){return typeof $response!=="undefined"}get isDebug(){return this.logger.level==="DEBUG"}get request(){if(typeof $request!=="undefined"){this.logger.sniffer(`RESPONSE:\n${JSON.stringify($request)}`);return $request}}get response(){if(typeof $response!=="undefined"){if($response.hasOwnProperty("status"))$response["statusCode"]=$response["status"];if($response.hasOwnProperty("statusCode"))$response["status"]=$response["statusCode"];this.logger.sniffer(`RESPONSE:\n${JSON.stringify($response)}`);return $response}else{return undefined}}done=(e={})=>{this._endTime=Date.now();let t=(this._endTime-this._startTime)/1e3;this.logger.info(`SCRIPT COMPLETED: ${t} S.`);if(typeof $done!=="undefined"){$done(e)}}}(e,t)} +// prettier-ignore +function MagicData(l,f){let u={fs:undefined,data:{}};if(l.isNode){u.fs=require("fs");try{u.fs.accessSync("./magic.json",u.fs.constants.R_OK|u.fs.constants.W_OK)}catch(e){u.fs.writeFileSync("./magic.json","{}",{encoding:"utf8"})}u.data=require("./magic.json")}const o=(e,t)=>{if(typeof t==="object"){return false}else{return e===t}};const a=e=>{if(e==="true"){return true}else if(e==="false"){return false}else if(typeof e==="undefined"){return null}else{return e}};const c=(e,t,r,s)=>{if(r){try{if(typeof e==="string")e=JSON.parse(e);if(e["magic_session"]===true){e=e[r]}else{e=null}}catch{e=null}}if(typeof e==="string"&&e!=="null"){try{e=JSON.parse(e)}catch{}}if(s===false&&!!e&&e["magic_session"]===true){e=null}if((e===null||typeof e==="undefined")&&t!==null&&typeof t!=="undefined"){e=t}e=a(e);return e};const i=t=>{if(typeof t==="string"){let e={};try{e=JSON.parse(t);const r=typeof e;if(r!=="object"||e instanceof Array||r==="bool"||e===null){e={}}}catch{}return e}else if(t instanceof Array||t===null||typeof t==="undefined"||t!==t||typeof t==="boolean"){return{}}else{return t}};const y=(e,t=null,r="",s=false,n=null)=>{let i=n||u.data;if(!!i&&typeof i[e]!=="undefined"&&i[e]!==null){val=i[e]}else{val=!!r?{}:null}val=c(val,t,r,s);return val};const d=(e,t=null,r="",s=false,n=null)=>{let i="";if(n||l.isNode){i=y(e,t,r,s,n)}else{if(l.isSurgeLike){i=$persistentStore.read(e)}else if(l.isQuanX){i=$prefs.valueForKey(e)}i=c(i,t,r,s)}f.debug(`READ DATA [${e}]${!!r?`[${r}]`:""} <${typeof i}>\n${JSON.stringify(i)}`);return i};const p=(t,r,s="",e=null)=>{let n=e||u.data;n=i(n);if(!!s){let e=i(n[t]);e["magic_session"]=true;e[s]=r;n[t]=e}else{n[t]=r}if(e!==null){e=n}return n};const g=(e,t,r="",s=null)=>{if(typeof t==="undefined"||t!==t){return false}if(!l.isNode&&(typeof t==="boolean"||typeof t==="number")){t=String(t)}let n="";if(s||l.isNode){n=p(e,t,r,s)}else{if(!r){n=t}else{if(l.isSurgeLike){n=!!$persistentStore.read(e)?$persistentStore.read(e):n}else if(l.isQuanX){n=!!$prefs.valueForKey(e)?$prefs.valueForKey(e):n}n=i(n);n["magic_session"]=true;n[r]=t}}if(!!n&&typeof n==="object"){n=JSON.stringify(n,"","\t")}f.debug(`WRITE DATA [${e}]${r?`[${r}]`:""} <${typeof t}>\n${JSON.stringify(t)}`);if(!s){if(l.isSurgeLike){return $persistentStore.write(n,e)}else if(l.isQuanX){return $prefs.setValueForKey(n,e)}else if(l.isNode){try{u.fs.writeFileSync("./magic.json",n);return true}catch(e){f.error(e);return false}}}return true};const e=(t,r,s,n=o,i=null)=>{r=a(r);const e=d(t,null,s,false,i);if(n(e,r)===true){return false}else{const l=g(t,r,s,i);let e=d(t,null,s,false,i);if(n===o&&typeof e==="object"){return l}return n(r,e)}};const S=(e,t,r)=>{let s=r||u.data;s=i(s);if(!!t){obj=i(s[e]);delete obj[t];s[e]=obj}else{delete s[e]}if(!!r){r=s}return s};const t=(e,t="",r=null)=>{let s={};if(r||l.isNode){s=S(e,t,r);if(!r){u.fs.writeFileSync("./magic.json",JSON.stringify(s))}else{r=s}}else{if(!t){if(l.isStorm){return $persistentStore.remove(e)}else if(l.isSurgeLike){return $persistentStore.write(null,e)}else if(l.isQuanX){return $prefs.removeValueForKey(e)}}else{if(l.isSurgeLike){s=$persistentStore.read(e)}else if(l.isQuanX){s=$prefs.valueForKey(e)}s=i(s);delete s[t];const n=JSON.stringify(s);g(e,n)}}f.debug(`DELETE KEY [${e}]${!!t?`[${t}]`:""}`)};const r=(e,t=null)=>{let r=[];let s=d(e,null,null,true,t);s=i(s);if(s["magic_session"]!==true){r=[]}else{r=Object.keys(s).filter(e=>e!=="magic_session")}f.debug(`READ ALL SESSIONS [${e}] <${typeof r}>\n${JSON.stringify(r)}`);return r};return{read:d,write:g,del:t,update:e,allSessions:r,defaultValueComparator:o,convertToObject:i}} +// prettier-ignore +function MagicHttp(l,u){const t="Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Mobile/15E148 Safari/604.1";const r="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36 Edg/84.0.522.59";let f;if(l.isNode){const a=require("axios");f=a.create()}class e{constructor(e=true){this.handlers=[];this.isRequest=e}use(e,t,r){this.handlers.push({fulfilled:e,rejected:t,synchronous:r?r.synchronous:false,runWhen:r?r.runWhen:null});return this.handlers.length-1}eject(e){if(this.handlers[e]){this.handlers[e]=null}}forEach(t){this.handlers.forEach(e=>{if(e!==null){t(e)}})}}function n(e){let r={...e};if(!!r.params){if(!l.isNode){let e=Object.keys(r.params).map(e=>{const t=encodeURIComponent(e);r.url=r.url.replace(new RegExp(`${e}=[^&]*`,"ig"),"");r.url=r.url.replace(new RegExp(`${t}=[^&]*`,"ig"),"");return`${t}=${encodeURIComponent(r.params[e])}`}).join("&");if(r.url.indexOf("?")<0)r.url+="?";if(!/(&|\?)$/g.test(r.url)){r.url+="&"}r.url+=e;delete r.params;u.debug(`Params to QueryString: ${r.url}`)}}return r}const d=(e,t)=>{let r=typeof t==="object"?{headers:{},...t}:{url:t,headers:{}};if(!r.method){r["method"]=e}r=n(r);if(r["rewrite"]===true){if(l.isSurge){r.headers["X-Surge-Skip-Scripting"]=false;delete r["rewrite"]}else if(l.isQuanX){r["hints"]=false;delete r["rewrite"]}}if(l.isSurge){if(r["method"]!=="GET"&&typeof r.headers["Content-Type"]==="string"&&r.headers["Content-Type"].indexOf("application/json")>=0&&r.body instanceof Array){r.body=JSON.stringify(r.body);u.debug(`Convert Array object to String: ${r.body}`)}}else if(l.isQuanX){if(r.hasOwnProperty("body")&&typeof r["body"]!=="string")r["body"]=JSON.stringify(r["body"]);r["method"]=e}else if(l.isNode){if(e==="POST"||e==="PUT"||e==="PATCH"||e==="DELETE"){r.data=r.data||r.body}else if(e==="GET"){r.params=r.params||r.body}delete r.body}return r};const h=(t,r=null)=>{if(t){let e={...t,config:t.config||r,status:t.statusCode||t.status,body:t.body||t.data||"",headers:t.headers||t.header};if(typeof e.body==="string"){try{e.body=JSON.parse(e.body)}catch{}}delete t.data;return e}else{let e={config:r,status:null,body:"",headers:{}};return e}};const o=n=>{if(!!n){delete n["Content-Length"];let e=new Set(["Accept","Accept-CH","Accept-Charset","Accept-Features","Accept-Encoding","Accept-Language","Accept-Ranges","Access-Control-Allow-Credentials","Access-Control-Allow-Origin","Access-Control-Allow-Methods","Access-Control-Allow-Headers","Access-Control-Max-Age","Access-Control-Expose-Headers","Access-Control-Request-Method","Access-Control-Request-Headers","Age","Allow","Alternates","Authorization","Cache-Control","Connection","Content-Encoding","Content-Language","ontent-Length","Content-Location","Content-Range","Content-Security-Policy","Content-Type","Cookie","DNT","Date","ETag","Expect","Expires","From","Host","If-Match","If-Modified-Since","If-None-Match","If-Range","If-Unmodified-Since","Last-Event-ID","Last-Modified","Link","Location","Max-Forwards","Negotiate","Origin","Pragma","Proxy-Authenticate","Proxy-Authorization","Range","Referer","Retry-After","Sec-Websocket-Extensions","Sec-Websocket-Key","Sec-Websocket-Origin","Sec-Websocket-Protocol","Sec-Websocket-Version","Server","Set-Cookie","Set-Cookie2","Strict-Transport-Security","TCN","TE","Trailer","Transfer-Encoding","Upgrade","User-Agent","Variant-Vary","Vary","Via","Warning","WWW-Authenticate","X-Content-Duration","X-Content-Security-Policy","X-DNSPrefetch-Control","X-Frame-Options","X-Requested-With"]);for(let r of Object.keys(n)){if(!e.has(r)){for(let t of e){let e=r.replace(new RegExp(t,"ig"),t);if(r!==e){n[e]=n[r];delete n[r];break}}}}if(!n["User-Agent"]){if(l.isNode){n["User-Agent"]=r}else{n["User-Agent"]=t}}return n}return n};const p=(t,r=null)=>{if(!!t&&t.status>=400){u.debug(`Raise exception when status code is ${t.status}`);let e={name:"RequestException",message:`Request failed with status code ${t.status}`,config:r||t.config,response:t};return e}};const s={request:new e,response:new e(false)};let y=[];let g=[];let m=true;function A(e){if(typeof e==="object"&&e["modify"]!==false){e["headers"]=o(e["headers"])}e=n(e);return e}function C(e){try{e=!!e?h(e):e;u.sniffer(`HTTP ${e.config["method"].toUpperCase()}:\n${JSON.stringify(e.config)}\nSTATUS CODE:\n${e.status}\nRESPONSE:\n${typeof e.body==="object"?JSON.stringify(e.body):e.body}`);const t=p(e);if(!!t){return Promise.reject(t)}return e}catch(t){u.error(t);return e}}const b=t=>{try{y=[];g=[];s.request.forEach(e=>{if(typeof e.runWhen==="function"&&e.runWhen(t)===false){return}m=m&&e.synchronous;y.unshift(e.fulfilled,e.rejected)});s.response.forEach(e=>{g.push(e.fulfilled,e.rejected)})}catch(e){u.error(`failed to register interceptors: ${e}`)}};const i=(e,n)=>{let o;const t=e.toUpperCase();n=d(t,n);if(l.isNode){o=f}else{if(l.isSurgeLike){o=s=>{return new Promise((n,o)=>{$httpClient[e.toLowerCase()](s,(t,r,e)=>{if(t){let e={name:t.name||t,message:t.message||t,stack:t.stack||t,config:s,response:h(r)};o(e)}else{r.config=s;r.body=e;n(r)}})})}}else{o=o=>{return new Promise((r,n)=>{$task.fetch(o).then(e=>{e=h(e,o);const t=p(e,o);if(t){return Promise.reject(t)}r(e)}).catch(e=>{let t={name:e.message||e.error,message:e.message||e.error,stack:e.error,config:o,response:!!e.response?h(e.response):null};n(t)})})}}}let s;b(n);const i=[A,undefined];const a=[C,undefined];if(!m){u.debug("Interceptors are executed in asynchronous mode");let r=[o,undefined];Array.prototype.unshift.apply(r,i);Array.prototype.unshift.apply(r,y);Array.prototype.unshift.apply(r,i);r=r.concat(a);r=r.concat(g);s=Promise.resolve(n);while(r.length){try{let e=r.shift();let t=r.shift();if(!l.isNode&&n["timeout"]&&e===o){s=c(n)}else{s=s.then(e,t)}}catch(e){u.error(`request exception: ${e}`)}}return s}else{u.debug("Interceptors are executed in synchronous mode");Array.prototype.unshift.apply(y,i);y=y.concat([A,undefined]);while(y.length){let e=y.shift();let t=y.shift();try{n=e(n)}catch(e){t(e);break}}try{if(!l.isNode&&n["timeout"]){s=c(n)}else{s=o(n)}}catch(e){return Promise.reject(e)}Array.prototype.unshift.apply(g,a);while(g.length){s=s.then(g.shift(),g.shift())}return s}function c(r){try{const e=new Promise((e,t)=>{setTimeout(()=>{let e={message:`timeout of ${r["timeout"]}ms exceeded`,config:r};t(e)},r["timeout"])});return Promise.race([o(r),e])}catch(e){u.error(`Request Timeout exception: ${e}`)}}};return{request:i,interceptors:s,modifyHeaders:o,modifyResponse:h,get:e=>{return i("GET",e)},post:e=>{return i("POST",e)},put:e=>{return i("PUT",e)},patch:e=>{return i("PATCH",e)},delete:e=>{return i("DELETE",e)},head:e=>{return i("HEAD",e)},options:e=>{return i("OPTIONS",e)}}} +// prettier-ignore +function MagicNotification(r,f,l){let s=null;let u=null;const c=typeof MagicHttp==="function"?MagicHttp(f,l):undefined;const e=t=>{try{let e=t.replace(/\/+$/g,"");s=`${/^https?:\/\/([^/]*)/.exec(e)[0]}/push`;u=/\/([^\/]+)\/?$/.exec(e)[1]}catch(e){l.error(`Bark url error: ${e}.`)}};function t(e=r,t="",i="",o=""){const n=i=>{try{let t={};if(typeof i==="string"){if(f.isLoon)t={openUrl:i};else if(f.isQuanX)t={"open-url":i};else if(f.isSurge)t={url:i}}else if(typeof i==="object"){if(f.isLoon){t["openUrl"]=!!i["open-url"]?i["open-url"]:"";t["mediaUrl"]=!!i["media-url"]?i["media-url"]:""}else if(f.isQuanX){t=!!i["open-url"]||!!i["media-url"]?i:{}}else if(f.isSurge){let e=i["open-url"]||i["openUrl"];t=e?{url:e}:{}}}return t}catch(e){l.error(`Failed to convert notification option, ${e}`)}return i};o=n(o);if(arguments.length==1){e=r;t="",i=arguments[0]}l.notify(`title:${e}\nsubTitle:${t}\nbody:${i}\noptions:${typeof o==="object"?JSON.stringify(o):o}`);if(f.isSurge){$notification.post(e,t,i,o)}else if(f.isLoon){if(!!o)$notification.post(e,t,i,o);else $notification.post(e,t,i)}else if(f.isQuanX){$notify(e,t,i,o)}if(s&&u&&typeof c!=="undefined"){p(e,t,i)}}function i(e=r,t="",i="",o=""){if(l.level==="DEBUG"){if(arguments.length==1){e=r;t="",i=arguments[0]}this.notify(e,t,i,o)}}function p(e=r,t="",i="",o=""){if(typeof c==="undefined"||typeof c.post==="undefined"){throw"Bark notification needs to import MagicHttp module."}let n={url:s,headers:{"Content-Type":"application/json; charset=utf-8"},body:{title:e,body:t?`${t}\n${i}`:i,device_key:u}};c.post(n).catch(e=>{l.error(`Bark notify error: ${e}`)})}return{post:t,debug:i,bark:p,setBark:e}} +// prettier-ignore +function MagicUtils(r,h){const e=(o,i=5,l=0,a=null)=>{return(...e)=>{return new Promise((s,r)=>{function n(...t){Promise.resolve().then(()=>o.apply(this,t)).then(e=>{if(typeof a==="function"){Promise.resolve().then(()=>a(e)).then(()=>{s(e)}).catch(e=>{if(i>=1){if(l>0)setTimeout(()=>n.apply(this,t),l);else n.apply(this,t)}else{r(e)}i--})}else{s(e)}}).catch(e=>{h.error(e);if(i>=1&&l>0){setTimeout(()=>n.apply(this,t),l)}else if(i>=1){n.apply(this,t)}else{r(e)}i--})}n.apply(this,e)})}};const t=(e,t="yyyy-MM-dd hh:mm:ss")=>{let s={"M+":e.getMonth()+1,"d+":e.getDate(),"h+":e.getHours(),"m+":e.getMinutes(),"s+":e.getSeconds(),"q+":Math.floor((e.getMonth()+3)/3),S:e.getMilliseconds()};if(/(y+)/.test(t))t=t.replace(RegExp.$1,(e.getFullYear()+"").substr(4-RegExp.$1.length));for(let e in s)if(new RegExp("("+e+")").test(t))t=t.replace(RegExp.$1,RegExp.$1.length==1?s[e]:("00"+s[e]).substr((""+s[e]).length));return t};const s=()=>{return t(new Date,"yyyy-MM-dd hh:mm:ss")};const n=()=>{return t(new Date,"yyyy-MM-dd")};const o=t=>{return new Promise(e=>setTimeout(e,t))};const i=(e,t=null)=>{if(r.isNode){const s=require("assert");if(t)s(e,t);else s(e)}else{if(e!==true){let e=`AssertionError: ${t||"The expression evaluated to a falsy value"}`;h.error(e)}}};return{retry:e,formatTime:t,now:s,today:n,sleep:o,assert:i}} +// prettier-ignore +function MagicQingLong(e,s,r){let i="";let o="";let l="";let c="";let d="";let n="";const u="magic.json";const t=3e3;const p=MagicHttp(e,r);const a=(e,n,t,a,r)=>{i=e;l=n;c=t;o=a;d=r};function g(e){i=i||s.read("magic_qlurl");n=n||s.read("magic_qltoken");return e}function f(e){if(!i){i=s.read("magic_qlurl")}if(e.url.indexOf(i)<0){e.url=`${i}${e.url}`}return{...e,timeout:t}}function y(e){e.params={...e.params,t:Date.now()};return e}function h(e){n=n||s.read("magic_qltoken");if(n){e.headers["Authorization"]=`Bearer ${n}`}return e}function m(e){l=l||s.read("magic_qlclient");if(!!l){e.url=e.url.replace("/api/","/open/")}return e}async function b(e){try{const n=e.message||e.error||JSON.stringify(e);if((n.indexOf("NSURLErrorDomain")>=0&&n.indexOf("-1012")>=0||!!e.response&&e.response.status===401)&&!!e.config&&e.config.refreshToken!==true){r.warning(`Qinglong panel token has expired`);await v();e.config["refreshToken"]=true;return await p.request(e.config.method,e.config)}else{return Promise.reject(e)}}catch(e){return Promise.reject(e)}}p.interceptors.request.use(g,undefined);p.interceptors.request.use(f,undefined);p.interceptors.request.use(m,undefined,{runWhen:e=>{return e.url.indexOf("api/user/login")<0&&e.url.indexOf("open/auth/token")<0}});p.interceptors.request.use(h,undefined,{runWhen:e=>{return e.url.indexOf("api/user/login")<0&&e.url.indexOf("open/auth/token")<0}});p.interceptors.request.use(y,undefined,{runWhen:e=>{return e.url.indexOf("open/auth/token")<0&&e.url.indexOf("t=")<0}});p.interceptors.response.use(undefined,b);async function v(){l=l||s.read("magic_qlclient");c=c||s.read("magic_qlsecrt");o=o||s.read("magic_qlname");d=d||s.read("magic_qlpwd");if(i&&l&&c){await p.get({url:`/open/auth/token`,headers:{"Content-Type":"application/json"},params:{client_id:l,client_secret:c}}).then(e=>{r.info("Log in to Qinglong panel successfully");n=e.body.data.token;s.update("magic_qltoken",n);return n}).catch(e=>{r.error(`Failed to log in to Qinglong panel.\n${e.message}`)})}else if(i&&o&&d){await p.post({url:`/api/user/login`,headers:{"Content-Type":"application/json"},body:{username:o,password:d}}).then(e=>{r.info("Log in to Qinglong panel successfully");n=e.body.data.token;s.update("magic_qltoken",n);return n}).catch(e=>{r.error(`Failed to log in to Qinglong panel.\n${e.message}`)})}}async function N(n,t,a=null){i=i||s.read("magic_qlurl");if(a===null){let e=await $([{name:n,value:t}]);if(!!e&&e.length===1){return e[0]}}else{p.put({url:`/api/envs`,headers:{"Content-Type":"application/json"},body:{name:n,value:t,id:a}}).then(e=>{if(e.body.code===200){r.debug(`QINGLONG UPDATE ENV ${n} <${typeof t}> (${a})\n${JSON.stringify(t)}`);return true}else{r.error(`Failed to update Qinglong panel environment variable.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to update Qinglong panel environment variable.\n${e.message}`);return false})}}async function $(e){let n=[];await p.post({url:`/api/envs`,headers:{"Content-Type":"application/json"},body:e}).then(e=>{if(e.body.code===200){e.body.data.forEach(e=>{r.debug(`QINGLONG ADD ENV ${e.name} <${typeof e.value}> (${e.id})\n${JSON.stringify(e)}`);n.push(e.id)})}else{r.error(`Failed to add Qinglong panel environment variable.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to add Qinglong panel environment variable.\n${e.message}`)});return n}async function O(n){return await p.delete({url:`/api/envs`,headers:{Accept:"application/json","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",Connection:"keep-alive","Content-Type":"application/json;charset=UTF-8","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30"},body:n}).then(e=>{if(e.body.code===200){r.debug(`QINGLONG DELETE ENV IDS: ${n}`);return true}else{r.error(`Failed to delete QingLong envs.\n${JSON.stringify(e)}`);return false}}).catch(e=>{r.error(`Failed to delete QingLong envs.\n${e.message}`)})}async function S(t=null,e=""){let a=[];await p.get({url:`/api/envs`,headers:{"Content-Type":"application/json"},params:{searchValue:e}}).then(e=>{if(e.body.code===200){const n=e.body.data;if(!!t){let e=[];for(const e of n){if(e.name===t){a.push(e)}}a=e}a=n}else{r.error(`Failed to get environment variables from Qinglong panel.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to get environment variables from Qinglong panel.\n${JSON.stringify(e)}`)});return a}async function q(e){let n=null;const t=await S();for(const a of t){if(a.id===e){n=a;break}}return n}async function w(n){let t=false;await p.put({url:`/api/envs/disable`,headers:{Accept:"application/json","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",Connection:"keep-alive","Content-Type":"application/json;charset=UTF-8","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30"},body:n}).then(e=>{if(e.body.code===200){r.debug(`QINGLONG DISABLED ENV IDS: ${n}`);t=true}else{r.error(`Failed to disable QingLong envs.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to disable QingLong envs.\n${e.message}`)});return t}async function Q(n){let t=false;await p.put({url:`/api/envs/enable`,headers:{Accept:"application/json","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",Connection:"keep-alive","Content-Type":"application/json;charset=UTF-8","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30"},body:n}).then(e=>{if(e.body.code===200){r.debug(`QINGLONG ENABLED ENV IDS: ${n}`);t=true}else{r.error(`Failed to enable QingLong envs.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to enable QingLong envs.\n${e.message}`)});return t}async function T(e,n="",t=""){let a=false;await p.post({url:`/api/scripts`,headers:{"Content-Type":"application/json"},body:{filename:e,path:n,content:t}}).then(e=>{if(e.body.code===200){a=true}else{r.error(`Failed to add script content from Qinglong panel.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to add script content from Qinglong panel.\n${e.message}`)});return a}async function F(e,n=""){let t="";await p.get({url:`/api/scripts/${e}`,params:{path:n}}).then(e=>{if(e.body.code===200){t=e.body.data}else{r.error(`Failed to read script content from Qinglong panel.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to read script content from Qinglong panel.\n${e.message}`)});return t}async function k(e,n="",t=""){let a=false;await p.put({url:`/api/scripts`,headers:{"Content-Type":"application/json"},body:{filename:e,path:n,content:t}}).then(e=>{if(e.body.code===200){a=true}else{r.error(`Failed to read script content from Qinglong panel.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to read script content from Qinglong panel.\n${e.message}`)});return a}async function E(e,n=""){let t=false;await p.delete({url:`/api/scripts`,headers:{"Content-Type":"application/json"},body:{filename:e,path:n}}).then(e=>{if(e.body.code===200){t=true}else{r.error(`Failed to read script content from Qinglong panel.\n${JSON.stringify(e)}`)}}).catch(e=>{r.error(`Failed to read script content from Qinglong panel.\n${e.message}`)});return t}async function L(e,n,t=""){let a=await F(u,"");let r=s.convertToObject(a);let i=s.write(e,n,t,r);a=JSON.stringify(r,"","\t");let o=await k(u,"",a);return o&&i}async function j(e,n,t,a=s.defaultValueComparator){let r=await F(u,"");let i=s.convertToObject(r);const o=s.update(e,n,t,a,i);let l=false;if(o===true){r=JSON.stringify(i,"","\t");l=await k(u,"",r)}return o&&l}async function C(e,n,t=""){let a=await F(u,"");let r=s.convertToObject(a);const i=s.read(e,n,t,false,r);return i}async function _(e,n=""){let t=await F(u,"");let a=s.convertToObject(t);const r=s.del(e,n,a);t=JSON.stringify(a,"","\t");const i=await k(u,"",t);return r&&i}async function A(e){let n=await F(u,"");let t=s.convertToObject(n);const a=s.allSessions(e,t);return a}return{init:a,getToken:v,setEnv:N,setEnvs:$,getEnv:q,getEnvs:S,delEnvs:O,disableEnvs:w,enbleEnvs:Q,addScript:T,getScript:F,editScript:k,delScript:E,write:L,read:C,del:_,update:j,allSessions:A,url:i||s.read("magic_qlurl"),clientId:l||s.read("magic_qlclient"),userName:o||s.read("magic_magic_qlname")}} diff --git a/script/tieba/tieba_signin.qxrewrite b/script/tieba/tieba_signin.qxrewrite index 498a2492992..55c532af96a 100644 --- a/script/tieba/tieba_signin.qxrewrite +++ b/script/tieba/tieba_signin.qxrewrite @@ -4,4 +4,4 @@ ^https?:\/\/c\.tieba\.baidu\.com\/c\/s\/channelIconConfig url script-request-header https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js ^https?:\/\/tiebac\.baidu\.com\/c\/u\/follow\/getFoldedMessageUserInfo url script-request-header https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/master/script/tieba/tieba_signin.js -hostname = c.tieba.baidu.com \ No newline at end of file +hostname = c.tieba.baidu.com,tiebac.baidu.com \ No newline at end of file diff --git a/script/zhihu/README.md b/script/zhihu/README.md index 821e9bbcee3..764a318148a 100644 --- a/script/zhihu/README.md +++ b/script/zhihu/README.md @@ -44,9 +44,7 @@ ## 最近更新 -1. 适配至8.22.0 (9926) -1. 去除视频标签页红点 -1. 增加知乎纯净版模块 +1. 适配至8.33.0 (11018) ## 版本切换 diff --git a/script/zhihu/zhihu.js b/script/zhihu/zhihu.js index 97bd4945cdc..70de301c103 100644 --- a/script/zhihu/zhihu.js +++ b/script/zhihu/zhihu.js @@ -5,95 +5,139 @@ const keywordBlockKey = "zhihu_keyword_block"; // 默认屏蔽推荐列表的用户,通常不是真实用户,无法通过加入黑名单屏蔽 const defaultAnswerBlockedUsers = ["会员推荐"]; const keywordMaxCount = 1000; // 允许设置的关键词数量 -let magicJS = MagicJS(scriptName, "INFO"); +const $ = MagicJS(scriptName, "INFO"); (() => { let response = null; - if (magicJS.isResponse) { + if ($.isResponse) { switch (true) { // 知乎8.3.0移除推荐页顶部项 - case magicJS.read("zhihu_settings_remove_sections") == true && /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/feed-root\/sections\/query\/v2/.test(magicJS.request.url): + case $.data.read("zhihu_settings_remove_sections", false) === true && + /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/feed-root\/sections\/query\/v2/.test( + $.request.url + ): response = removeFeedSections(); break; // 回答内容优化 - case magicJS.read("zhihu_settings_answer_tip") != false && - /^https?:\/\/(www\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/appview\/v2\/answer\/.*(entry=(?!(preload-topstory|preload-search|preload-subscription)))?/.test(magicJS.request.url): + case $.data.read("zhihu_settings_answer_tip", true) === true && + /^https?:\/\/(www\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/appview\/v2\/answer\/.*(entry=(?!(preload-topstory|preload-search|preload-subscription)))?/.test( + $.request.url + ): response = modifyAnswer(); break; // 处理登录用户信息 - case /^https:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/people\/self$/.test(magicJS.request.url): + case /^https:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/people\/self$/.test( + $.request.url + ): response = processUserInfo(); break; // 黑名单增强 - 浏览黑名单用户信息时自动加入脚本黑名单 - case magicJS.read("zhihu_settings_blocked_users") != false && /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/people\/((?!self).)*$/.test(magicJS.request.url): + case $.data.read("zhihu_settings_blocked_users", true) === true && + /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/people\/((?!self).)*$/.test( + $.request.url + ): response = autoInsertBlackList(); break; // 推荐去广告与黑名单增强 - case /^https:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/topstory\/recommend\?/.test(magicJS.request.url): + case /^https:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/topstory\/recommend\?/.test( + $.request.url + ): response = removeRecommendAds(); break; // 关注列表去广告 - case /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/moments(\/|\?)?(recommend|action=|feed_type=)(?!\/people)/.test(magicJS.request.url): + case /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/moments(\/|\?)?(recommend|action=|feed_type=)(?!\/people)/.test( + $.request.url + ): response = removeMomentsAds(); break; // 回答列表去广告与黑名单增强 - case /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/(v4\/)?questions\/\d+/.test(magicJS.request.url): + case /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/(v4\/)?questions\/\d+/.test( + $.request.url + ): response = removeQuestionsAds(); break; // 知乎V5版本评论去广告及黑名单增强 - case /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/comment_v5\/(answers|pins|comments?|articles)\/\d+\/(root|child)_comment/.test(magicJS.request.url): + case /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/comment_v5\/(answers|pins|comments?|articles)\/\d+\/(root|child)_comment/.test( + $.request.url + ): response = removeCommentV5Ads(); break; // 知乎旧版回答中的评论黑名单增强 - case /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/(answers|pins|comments?|articles)\/\d+\/(root|child)_comments/.test(magicJS.request.url): + case /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/(answers|pins|comments?|articles)\/\d+\/(root|child)_comments/.test( + $.request.url + ): response = removeCommentAds(); break; // 知乎热榜去广告 - case magicJS.read("zhihu_settings_hot_list") != false && /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/topstory\/hot-lists?(\?|\/)/.test(magicJS.request.url): + case $.data.read("zhihu_settings_hot_list", true) === true && + /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/topstory\/hot-lists?(\?|\/)/.test( + $.request.url + ): response = removeHotListAds(); break; // 拦截官方账号推广消息 - case magicJS.read("zhihu_settings_sys_msg") != false && /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/notifications\/v3\/timeline\/entry\/system_message/.test(magicJS.request.url): + case $.data.read("zhihu_settings_sys_msg", true) === true && + /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/notifications\/v3\/timeline\/entry\/system_message/.test( + $.request.url + ): response = removeSysMsgAds(); break; // 屏蔽官方营销消息 - case magicJS.read("zhihu_settings_sys_msg") != false && /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/notifications\/v3\/message/.test(magicJS.request.url): + case $.data.read("zhihu_settings_sys_msg", true) != false && + /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/notifications\/v3\/message/.test( + $.request.url + ): response = removeMarketingMsg(); break; // 去除预置关键字广告 - case magicJS.read("zhihu_settings_preset_words") == true && /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/search\/preset_words\?/.test(magicJS.request.url): + case $.data.read("zhihu_settings_preset_words", false) == true && + /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/search\/preset_words\?/.test( + $.request.url + ): response = removeKeywordAds(); break; // 优化知乎软件配置 - case magicJS.read("zhihu_settings_app_conf") == true && /^https?:\/\/appcloud2\.zhihu\.com\/v\d+\/config/.test(magicJS.request.url): + case $.data.read("zhihu_settings_app_conf") == true && + /^https?:\/\/appcloud2\.zhihu\.com\/v\d+\/config/.test($.request.url): response = modifyAppConfig(); break; // 知乎热搜去广告 - case magicJS.read("zhihu_settings_hot_search") == true && /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/search\/top_search\/tabs\/hot\/items/.test(magicJS.request.url): + case $.data.read("zhihu_settings_hot_search") == true && + /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/search\/top_search\/tabs\/hot\/items/.test( + $.request.url + ): response = removeHotSearchAds(); break; // 黑名单管理 - case magicJS.read("zhihu_settings_blocked_users") != false && /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/settings\/blocked_users/.test(magicJS.request.url): + case $.data.read("zhihu_settings_blocked_users") != false && + /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/settings\/blocked_users/.test( + $.request.url + ): manageBlackUser(); break; default: break; } - } else if (magicJS.isRequest) { + } else if ($.isRequest) { // 知乎屏蔽关键词解锁 - if (magicJS.read("zhihu_settings_blocked_keywords") != false && /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/feed-root\/block/.test(magicJS.request.url) === true) { + if ( + $.data.read("zhihu_settings_blocked_keywords") != false && + /^https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/feed-root\/block/.test( + $.request.url + ) === true + ) { response = unlockBlockedKeywords(response); } } else { - magicJS.write(currentUserInfoKey, ""); - magicJS.write(blockedUsersKey, ""); - magicJS.write(keywordBlockKey, ""); - magicJS.notify("知乎助手数据清理完毕"); + $.data.del(currentUserInfoKey); + $.data.del(blockedUsersKey); + $.data.del(keywordBlockKey); + $.notification.post("知乎助手数据清理完毕"); } if (response) { - magicJS.done(response); + $.done(response); } else { - magicJS.done(); + $.done(); } })(); @@ -106,7 +150,7 @@ let magicJS = MagicJS(scriptName, "INFO"); function removeMarketingMsg() { let response = null; try { - let obj = JSON.parse(magicJS.response.body); + let obj = JSON.parse($.response.body); let newItems = []; for (let item of obj["data"]) { if (item["detail_title"] === "官方帐号消息") { @@ -126,7 +170,7 @@ function removeMarketingMsg() { obj["data"] = newItems; response = { body: JSON.stringify(obj) }; } catch (err) { - magicJS.logError(`知乎屏蔽官方营销消息出现异常:${err}`); + $.logger.error(`知乎屏蔽官方营销消息出现异常:${err}`); } return response; } @@ -142,19 +186,20 @@ function unlockBlockedKeywords() { try { const userInfo = getUserInfo(); // 获取屏蔽关键词列表 - if (magicJS.request.method === "GET") { - let keywords = magicJS.read(keywordBlockKey, userInfo.id); + if ($.request.method === "GET") { + let keywords = $.data.read(keywordBlockKey, null, userInfo.id); if (!keywords) { keywords = []; } let headers = { - "Cache-Control": "no-cache, no-store, must-revalidate, private, max-age=0", - "Connection": "keep-alive", + "Cache-Control": + "no-cache, no-store, must-revalidate, private, max-age=0", + Connection: "keep-alive", "Content-Type": "application/json;charset=utf-8", - "Pragma": "no-cache", + Pragma: "no-cache", "Referrer-Policy": "no-referrer-when-downgrade", - "Server": "CLOUD ELB 1.0.0", - "Vary": "Accept-Encoding", + Server: "CLOUD ELB 1.0.0", + Vary: "Accept-Encoding", "X-Cache-Lookup": "Cache Miss", "x-cdn-provider": "tencent", }; @@ -166,32 +211,35 @@ function unlockBlockedKeywords() { kw_max_count: keywordMaxCount, data: keywords, }); - if (magicJS.isQuanX) { + if ($.env.isQuanX) { response = { body: body, headers: headers, status: "HTTP/1.1 200 OK" }; } else { response = { response: { body: body, headers: headers, status: 200 } }; } - magicJS.logDebug(`获取本地脚本屏蔽关键词:\n${keywords.join("、")}`); + $.logger.debug(`获取本地脚本屏蔽关键词:\n${keywords.join("、")}`); } // 添加屏蔽关键词 - else if (magicJS.request.method === "POST") { - if (!!magicJS.request.body) { + else if ($.request.method === "POST") { + if (!!$.request.body) { // 构造 response headers let headers = { - "Cache-Control": "no-cache, no-store, must-revalidate, private, max-age=0", - "Connection": "keep-alive", + "Cache-Control": + "no-cache, no-store, must-revalidate, private, max-age=0", + Connection: "keep-alive", "Content-Type": "application/json;charset=utf-8", - "Pragma": "no-cache", + Pragma: "no-cache", "Referrer-Policy": "no-referrer-when-downgrade", - "Server": "CLOUD ELB 1.0.0", - "Vary": "Accept-Encoding", + Server: "CLOUD ELB 1.0.0", + Vary: "Accept-Encoding", "X-Cache-Lookup": "Cache Miss", "x-cdn-provider": "tencent", }; // 读取关键词 - let keyword = decodeURIComponent(magicJS.request.body).match(/keyword=(.*)/)[1]; - let keywords = magicJS.read(keywordBlockKey, userInfo.id); + let keyword = decodeURIComponent($.request.body).match( + /keyword=(.*)/ + )[1]; + let keywords = $.data.read(keywordBlockKey, null, userInfo.id); if (!keywords) { keywords = []; } @@ -200,19 +248,26 @@ function unlockBlockedKeywords() { for (let i = 0; i < keywords.length; i++) { if (keyword === keywords[i]) { keywordExists = true; + break; } } // 不存在添加,存在返回异常 if (keywordExists === false) { keywords.push(keyword); - magicJS.write(keywordBlockKey, keywords, userInfo.id); + $.data.write(keywordBlockKey, keywords, userInfo.id); let body = JSON.stringify({ success: true }); - if (magicJS.isQuanX) { - response = { body: body, headers: headers, status: "HTTP/1.1 200 OK" }; + if ($.env.isQuanX) { + response = { + body: body, + headers: headers, + status: "HTTP/1.1 200 OK", + }; } else { - response = { response: { body: body, headers: headers, status: 200 } }; + response = { + response: { body: body, headers: headers, status: 200 }, + }; } - magicJS.logDebug(`添加本地脚本屏蔽关键词“${keyword}”`); + $.logger.debug(`添加本地脚本屏蔽关键词“${keyword}”`); } else { let body = JSON.stringify({ error: { @@ -220,51 +275,54 @@ function unlockBlockedKeywords() { code: 100002, }, }); - if (magicJS.isQuanX) { + if ($.env.isQuanX) { response = { body: body, headers: headers, status: "HTTP/1.1 400 Bad Request", }; } else { - response = { response: { body: body, headers: headers, status: 400 } }; + response = { + response: { body: body, headers: headers, status: 400 }, + }; } } } } // 删除屏蔽关键词 - else if (magicJS.request.method === "DELETE") { - let keyword = decodeURIComponent(magicJS.request.url).match(/keyword=(.*)/)[1]; - let keywords = magicJS.read(keywordBlockKey, userInfo.id); + else if ($.request.method === "DELETE") { + let keyword = decodeURIComponent($.request.url).match(/keyword=(.*)/)[1]; + let keywords = $.data.read(keywordBlockKey, null, userInfo.id); if (!keywords) { keywords = []; } keywords = keywords.filter((e) => { - return e != keyword; + return e !== keyword; }); - magicJS.write(keywordBlockKey, keywords, userInfo.id); + $.data.write(keywordBlockKey, keywords, userInfo.id); let headers = { - "Cache-Control": "no-cache, no-store, must-revalidate, private, max-age=0", - "Connection": "keep-alive", + "Cache-Control": + "no-cache, no-store, must-revalidate, private, max-age=0", + Connection: "keep-alive", "Content-Type": "application/json;charset=utf-8", - "Pragma": "no-cache", + Pragma: "no-cache", "Referrer-Policy": "no-referrer-when-downgrade", - "Server": "CLOUD ELB 1.0.0", - "Vary": "Accept-Encoding", + Server: "CLOUD ELB 1.0.0", + Vary: "Accept-Encoding", "X-Cache-Lookup": "Cache Miss", "x-cdn-provider": "tencent", }; let body = JSON.stringify({ success: true }); - if (magicJS.isQuanX) { + if ($.env.isQuanX) { response = { body: body, headers: headers, status: "HTTP/1.1 200 OK" }; } else { response = { response: { body: body, headers: headers, status: 200 } }; } - magicJS.logDebug(`删除本地脚本屏蔽关键词:“${keyword}”`); + $.logger.debug(`删除本地脚本屏蔽关键词:“${keyword}”`); } } catch (err) { - magicJS.logError(`知乎关键词屏蔽操作出现异常:${err}`); + $.logger.debug(`知乎关键词屏蔽操作出现异常:${err}`); } return response; } @@ -278,13 +336,13 @@ function unlockBlockedKeywords() { function removeHotSearchAds() { let response = null; try { - if (!!magicJS.response.body) { - let obj = JSON.parse(magicJS.response.body); + if (!!$.response.body) { + let obj = JSON.parse($.response.body); obj["commercial_data"] = []; response = { body: JSON.stringify(obj) }; } } catch (err) { - magicJS.logError(`去除知乎热搜广告出现异常:${err}`); + $.logger.error(`去除知乎热搜广告出现异常:${err}`); } return response; } @@ -298,16 +356,20 @@ function removeHotSearchAds() { function modifyAppConfig() { let response = null; try { - if (!!magicJS.response.body) { - let obj = JSON.parse(magicJS.response.body); - let tab_infos = obj["config"]["homepage_feed_tab"]["tab_infos"].filter((e) => { - if (e.tab_type === "activity_tab") { - e.end_time = (Date.parse(new Date()) - 120000).toString().substr(0, 10); - return true; - } else { - return false; + if (!!$.response.body) { + let obj = JSON.parse($.response.body); + let tab_infos = obj["config"]["homepage_feed_tab"]["tab_infos"].filter( + (e) => { + if (e.tab_type === "activity_tab") { + e.end_time = (Date.parse(new Date()) - 120000) + .toString() + .substr(0, 10); + return true; + } else { + return false; + } } - }); + ); obj["config"]["homepage_feed_tab"]["tab_infos"] = tab_infos; obj["config"]["zvideo_max_number"] = 1; // 试着去除一些配置,效果待验证 @@ -315,17 +377,20 @@ function modifyAppConfig() { delete obj["config"]["cronet"]; // 屏蔽知乎8.X版本以上本地DNS解析,以下修改不清楚哪些是有效的,暂时全部保留 if (obj["config"].hasOwnProperty("zhcnh_thread_sync")) { - magicJS.logDebug(JSON.stringify(obj["config"]["zhcnh_thread_sync"])); + $.logger.debug(JSON.stringify(obj["config"]["zhcnh_thread_sync"])); obj["config"]["zhcnh_thread_sync"]["LocalDNSSetHostWhiteList"] = []; obj["config"]["zhcnh_thread_sync"]["isOpenLocalDNS"] = "0"; obj["config"]["zhcnh_thread_sync"]["ZHBackUpIP_Switch_Open"] = "0"; - obj["config"]["zhcnh_thread_sync"]["dns_ip_detector_operation_lock"] = "1"; - obj["config"]["zhcnh_thread_sync"]["ZHHTTPSessionManager_setupZHHTTPHeaderField"] = "1"; + obj["config"]["zhcnh_thread_sync"]["dns_ip_detector_operation_lock"] = + "1"; + obj["config"]["zhcnh_thread_sync"][ + "ZHHTTPSessionManager_setupZHHTTPHeaderField" + ] = "1"; } response = { body: JSON.stringify(obj) }; } } catch (err) { - magicJS.logError(`优化知乎软件配置出现异常:${err}`); + $.logger.error(`优化知乎软件配置出现异常:${err}`); } return response; } @@ -339,9 +404,9 @@ function modifyAppConfig() { function removeKeywordAds() { let response = null; try { - if (!!magicJS.response.body) { - magicJS.logDebug(`预置关键字返回:${magicJS.response.body}`); - let obj = JSON.parse(magicJS.response.body); + if (!!$.response.body) { + $.logger.debug(`预置关键字返回:${$.response.body}`); + let obj = JSON.parse($.response.body); if (obj.hasOwnProperty("preset_words") && obj["preset_words"]["words"]) { let words = obj["preset_words"]["words"].filter((element) => { return element["type"] !== "ad"; @@ -351,7 +416,7 @@ function removeKeywordAds() { } } } catch (err) { - magicJS.logError(`知乎去除预置关键字广告出现异常:${err}`); + $.logger.error(`知乎去除预置关键字广告出现异常:${err}`); } return response; } @@ -365,15 +430,21 @@ function removeKeywordAds() { function removeSysMsgAds() { let response = null; try { - const sysmsg_blacklist = ["知乎小伙伴", "知乎视频", "知乎团队", "知乎礼券", "知乎读书会团队"]; - let obj = JSON.parse(magicJS.response.body); + const sysmsg_blacklist = [ + "知乎小伙伴", + "知乎视频", + "知乎团队", + "知乎礼券", + "知乎读书会团队", + ]; + let obj = JSON.parse($.response.body); let data = obj["data"].filter((element) => { return sysmsg_blacklist.indexOf(element["content"]["title"]) < 0; }); obj["data"] = data; response = { body: JSON.stringify(obj) }; } catch (err) { - magicJS.logError(`知乎拦截官方账号推广消息出现异常:${err}`); + $.logger.error(`知乎拦截官方账号推广消息出现异常:${err}`); } return response; } @@ -387,18 +458,20 @@ function removeSysMsgAds() { function removeHotListAds() { let response = null; try { - if (!!magicJS.response.body) { - let obj = JSON.parse(magicJS.response.body); - if ('data' in obj){ + if (!!$.response.body) { + let obj = JSON.parse($.response.body); + if ("data" in obj) { let data = obj["data"].filter((e) => { - return e["type"] === "hot_list_feed" || e["type"] === "hot_list_feed_video"; + return ( + e["type"] === "hot_list_feed" || e["type"] === "hot_list_feed_video" + ); }); obj["data"] = data; } response = { body: JSON.stringify(obj) }; } } catch (err) { - magicJS.logError(`去除知乎热榜广告出现异常:${err}`); + $.logger.error(`去除知乎热榜广告出现异常:${err}`); } return response; } @@ -412,31 +485,58 @@ function removeHotListAds() { function removeCommentAds() { let response = null; try { - if (!!magicJS.response.body) { + if (!!$.response.body) { // 评论区去广告 - let obj = JSON.parse(magicJS.response.body); - if (magicJS.read("zhihu_settings_blocked_users") != false) { + let obj = JSON.parse($.response.body); + if ($.data.read("zhihu_settings_blocked_users") != false) { // 屏蔽黑名单用户 let user_info = getUserInfo(); - let customBlockedUsers = magicJS.read(blockedUsersKey, user_info.id); + let customBlockedUsers = $.data.read(blockedUsersKey, "", user_info.id); let newData = []; obj.data.forEach((comment) => { // 评论人昵称 let commentUserName = comment.author.member.name; // 回复哪个人的评论(仅适用于独立子评论页面请求) let replyUserName = ""; - if (comment.reply_to_author && comment.reply_to_author.member && comment.reply_to_author.member.name) { + if ( + comment.reply_to_author && + comment.reply_to_author.member && + comment.reply_to_author.member.name + ) { replyUserName = comment.reply_to_author.member.name; } - if (customBlockedUsers[commentUserName] || customBlockedUsers[replyUserName]) { - if (customBlockedUsers[commentUserName] && !replyUserName && magicJS.request.url.indexOf("root_comment") > 0) { - magicJS.notifyDebug(`屏蔽黑名单用户“${commentUserName}”的主评论。`); - } else if (customBlockedUsers[commentUserName] && !replyUserName && magicJS.request.url.indexOf("child_comment") > 0) { - magicJS.notifyDebug(`屏蔽黑名单用户“${commentUserName}”的子评论。`); - } else if (customBlockedUsers[commentUserName] && replyUserName && magicJS.request.url.indexOf("child_comment") > 0) { - magicJS.notifyDebug(`屏蔽黑名单用户“${commentUserName}”回复“${replyUserName}”的子评论。`); + if ( + customBlockedUsers[commentUserName] || + customBlockedUsers[replyUserName] + ) { + if ( + customBlockedUsers[commentUserName] && + !replyUserName && + $.request.url.indexOf("root_comment") > 0 + ) { + $.notification.debug( + `屏蔽黑名单用户“${commentUserName}”的主评论。` + ); + } else if ( + customBlockedUsers[commentUserName] && + !replyUserName && + $.request.url.indexOf("child_comment") > 0 + ) { + $.notification.debug( + `屏蔽黑名单用户“${commentUserName}”的子评论。` + ); + } else if ( + customBlockedUsers[commentUserName] && + replyUserName && + $.request.url.indexOf("child_comment") > 0 + ) { + $.notification.debug( + `屏蔽黑名单用户“${commentUserName}”回复“${replyUserName}”的子评论。` + ); } else { - magicJS.notifyDebug(`屏蔽“${commentUserName}”回复黑名单用户“${replyUserName}”的子评论。`); + $.notification.debug( + `屏蔽“${commentUserName}”回复黑名单用户“${replyUserName}”的子评论。` + ); } // 减少主评论页面中的评论总数(仅适用于独立的主评论页面请求) if (obj.common_counts) { @@ -451,11 +551,18 @@ function removeCommentAds() { if (comment.child_comments) { let newChildComments = []; comment.child_comments.forEach((childComment) => { - if (customBlockedUsers[childComment.author.member.name] || customBlockedUsers[childComment.reply_to_author.member.name]) { + if ( + customBlockedUsers[childComment.author.member.name] || + customBlockedUsers[childComment.reply_to_author.member.name] + ) { if (customBlockedUsers[childComment.author.member.name]) { - magicJS.notifyDebug(`屏蔽黑名单用户“${childComment.author.member.name}”的主评论。`); + $.notification.debug( + `屏蔽黑名单用户“${childComment.author.member.name}”的主评论。` + ); } else { - magicJS.notifyDebug(`屏蔽“${childComment.author.member.name}”回复黑名单用户“${childComment.reply_to_author.member.name}”的子评论。`); + $.notification.debug( + `屏蔽“${childComment.author.member.name}”回复黑名单用户“${childComment.reply_to_author.member.name}”的子评论。` + ); } comment.child_comment_count -= 1; } else { @@ -472,7 +579,7 @@ function removeCommentAds() { response = { body: JSON.stringify(obj) }; } } catch (err) { - magicJS.logError(`去除知乎评论广告出现异常:${err}`); + $.logger.error(`去除知乎评论广告出现异常:${err}`); } return response; } @@ -486,13 +593,13 @@ function removeCommentAds() { function removeCommentV5Ads() { let response = null; try { - if (!!magicJS.response.body) { - let obj = JSON.parse(magicJS.response.body); + if (!!$.response.body) { + let obj = JSON.parse($.response.body); obj["ad_info"] = {}; // 屏蔽黑名单用户 - if (magicJS.read("zhihu_settings_blocked_users") != false) { + if ($.data.read("zhihu_settings_blocked_users") != false) { let user_info = getUserInfo(); - let customBlockedUsers = magicJS.read(blockedUsersKey, user_info.id); + let customBlockedUsers = $.data.read(blockedUsersKey, "", user_info.id); customBlockedUsers = !!customBlockedUsers ? customBlockedUsers : {}; let newComments = []; let blockCommentIdObj = {}; @@ -501,18 +608,45 @@ function removeCommentV5Ads() { let commentUserName = comment.author.name; // 回复哪个人的评论(仅适用于独立子评论页面请求) let replyUserName = ""; - if (comment.reply_to_author && comment.reply_to_author && comment.reply_to_author.name) { + if ( + comment.reply_to_author && + comment.reply_to_author && + comment.reply_to_author.name + ) { replyUserName = comment.reply_to_author.name; } - if (customBlockedUsers[commentUserName] || customBlockedUsers[replyUserName]) { - if (customBlockedUsers[commentUserName] && !replyUserName && magicJS.request.url.indexOf("root_comment") > 0) { - magicJS.notifyDebug(`屏蔽黑名单用户“${commentUserName}”的主评论。`); - } else if (customBlockedUsers[commentUserName] && !replyUserName && magicJS.request.url.indexOf("child_comment") > 0) { - magicJS.notifyDebug(`屏蔽黑名单用户“${commentUserName}”的子评论。`); - } else if (customBlockedUsers[commentUserName] && replyUserName && magicJS.request.url.indexOf("child_comment") > 0) { - magicJS.notifyDebug(`屏蔽黑名单用户“${commentUserName}”回复“${replyUserName}”的子评论。`); + if ( + customBlockedUsers[commentUserName] || + customBlockedUsers[replyUserName] + ) { + if ( + customBlockedUsers[commentUserName] && + !replyUserName && + $.request.url.indexOf("root_comment") > 0 + ) { + $.notification.debug( + `屏蔽黑名单用户“${commentUserName}”的主评论。` + ); + } else if ( + customBlockedUsers[commentUserName] && + !replyUserName && + $.request.url.indexOf("child_comment") > 0 + ) { + $.notification.debug( + `屏蔽黑名单用户“${commentUserName}”的子评论。` + ); + } else if ( + customBlockedUsers[commentUserName] && + replyUserName && + $.request.url.indexOf("child_comment") > 0 + ) { + $.notification.debug( + `屏蔽黑名单用户“${commentUserName}”回复“${replyUserName}”的子评论。` + ); } else { - magicJS.notifyDebug(`屏蔽“${commentUserName}”回复黑名单用户“${replyUserName}”的子评论。`); + $.notification.debug( + `屏蔽“${commentUserName}”回复黑名单用户“${replyUserName}”的子评论。` + ); } blockCommentIdObj[comment.id] = commentUserName; // 主评论数量-1,仅适用于root_comment主评论页面请求 @@ -531,12 +665,21 @@ function removeCommentV5Ads() { let newChildComments = []; comment.child_comments.forEach((childComment) => { let childCommentUserName = childComment.author.name; - if (customBlockedUsers[childCommentUserName] || blockCommentIdObj[childComment.reply_comment_id]) { + if ( + customBlockedUsers[childCommentUserName] || + blockCommentIdObj[childComment.reply_comment_id] + ) { if (customBlockedUsers[childCommentUserName]) { - magicJS.notifyDebug(`屏蔽黑名单用户“${childCommentUserName}”的子评论。`); + $.notification.debug( + `屏蔽黑名单用户“${childCommentUserName}”的子评论。` + ); blockCommentIdObj[childComment.id] = childCommentUserName; } else { - magicJS.notifyDebug(`屏蔽“${childCommentUserName}”回复黑名单用户“${blockCommentIdObj[childComment.reply_comment_id]}”的子评论。`); + $.notification.debug( + `屏蔽“${childCommentUserName}”回复黑名单用户“${ + blockCommentIdObj[childComment.reply_comment_id] + }”的子评论。` + ); } comment.child_comment_count -= 1; } else { @@ -553,7 +696,7 @@ function removeCommentV5Ads() { response = { body: JSON.stringify(obj) }; } } catch (err) { - magicJS.logError(`去除知乎评论广告出现异常:${err}`); + $.logger.error(`去除知乎评论广告出现异常:${err}`); } return response; } @@ -568,36 +711,40 @@ function removeQuestionsAds() { let response = null; try { const userInfo = getUserInfo(); - let customBlockedUsers = magicJS.read(blockedUsersKey, userInfo.id); + let customBlockedUsers = $.data.read(blockedUsersKey, "", userInfo.id); customBlockedUsers = !!customBlockedUsers ? customBlockedUsers : {}; - let obj = JSON.parse(magicJS.response.body); - magicJS.logDebug(`当前黑名单列表: ${JSON.stringify(customBlockedUsers)}`); + let obj = JSON.parse($.response.body); + $.logger.debug(`当前黑名单列表: ${JSON.stringify(customBlockedUsers)}`); delete obj["ad_info"]; delete obj["roundtable_info"]; // 去除回答列表中的黑名单用户 - if ('data' in obj){ - let data = obj["data"].filter((element) => { + if ("data" in obj) { + delete obj["data"]["ad_info"]; + let data = obj.data["data"] || obj.data; + data = data.filter((element) => { let blackUserName = ""; - try{ - if ("author" in element){ - blackUserName = element["author"]["name"] + try { + if ("author" in element) { + blackUserName = element["author"]["name"]; + } else if ("target" in element) { + blackUserName = element["target"]["author"]["name"]; } - else if("target" in element){ - blackUserName = element["target"]["author"]["name"] - } - } - catch (ex){ - magicJS.logError(`获取回答列表用户名出现异常:${err}`); + } catch (ex) { + $.logger.error(`获取回答列表用户名出现异常:${err}`); } return blackUserName == "" || !customBlockedUsers[blackUserName]; }); - obj["data"] = data; + if (obj.data.hasOwnProperty("data")) { + obj.data["data"] = data; + } else { + obj["data"] = data; + } } let body = JSON.stringify(obj); - magicJS.logDebug(`修改后的回答列表数据:${body}`); + $.logger.debug(`修改后的回答列表数据:${body}`); response = { body: body }; } catch (err) { - magicJS.logError(`知乎回答列表去广告出现异常:${err}`); + $.logger.error(`知乎回答列表去广告出现异常:${err}`); } return response; } @@ -611,22 +758,34 @@ function removeQuestionsAds() { function removeMomentsAds() { let response = null; try { - let obj = JSON.parse(magicJS.response.body.replace(/(\w+"+\s?):\s?(\d{15,})/g, '$1:"$2"')); + let obj = JSON.parse( + $.response.body.replace(/(\w+"+\s?):\s?(\d{15,})/g, '$1:"$2"') + ); const user_info = getUserInfo(); - let customBlockedUsers = magicJS.read(blockedUsersKey, user_info.id); + let customBlockedUsers = $.data.read(blockedUsersKey, "", user_info.id); customBlockedUsers = !!customBlockedUsers ? customBlockedUsers : {}; let data = []; - const settings_moments_stream = magicJS.read("zhihu_settings_moments_stream") == true; - const settings_blocked_users = magicJS.read("zhihu_settings_blocked_users") != false; + const settings_moments_stream = + $.data.read("zhihu_settings_moments_stream") == true; + const settings_blocked_users = + $.data.read("zhihu_settings_blocked_users") != false; for (let i = 0; i < obj["data"].length; i++) { // let element = targetIdFix(obj["data"][i]); let element = obj["data"][i]; if (!element["ad"] && !element["adjson"] && !element["ad_list"]) { // 判断转发的想法是否含有黑名单用户 - if (settings_blocked_users && element.target && element.target.origin_pin && element.target.origin_pin.author && customBlockedUsers[element.target.origin_pin.author.name]) { - magicJS.notifyDebug(`屏蔽“${element.target.author.name}”转发黑名单用户“${element.target.origin_pin.author.name}”的想法。`); + if ( + settings_blocked_users && + element.target && + element.target.origin_pin && + element.target.origin_pin.author && + customBlockedUsers[element.target.origin_pin.author.name] + ) { + $.notification.debug( + `屏蔽“${element.target.author.name}”转发黑名单用户“${element.target.origin_pin.author.name}”的想法。` + ); } // 屏蔽关注页的“最新视频” @@ -638,7 +797,7 @@ function removeMomentsAds() { obj["data"] = data; response = { body: JSON.stringify(obj) }; } catch (err) { - magicJS.logError(`知乎关注列表去广告出现异常:${err}`); + $.logger.error(`知乎关注列表去广告出现异常:${err}`); } return response; } @@ -652,43 +811,68 @@ function removeMomentsAds() { function removeRecommendAds() { let response = null; try { - const settings_remove_yanxuan = magicJS.read("zhihu_settings_remove_yanxuan") == true; - const settings_recommend_stream = magicJS.read("zhihu_settings_recommend_stream") == true; - const settings_remove_article = magicJS.read("zhihu_settings_remove_article") == true; + const settings_remove_yanxuan = + $.data.read("zhihu_settings_remove_yanxuan") == true; + const settings_recommend_stream = + $.data.read("zhihu_settings_recommend_stream") == true; + const settings_remove_article = + $.data.read("zhihu_settings_remove_article") == true; // 默认开启 - const settings_blocked_keywords = magicJS.read("zhihu_settings_blocked_keywords") != false; - const settings_blocked_users = magicJS.read("zhihu_settings_blocked_users") != false; + const settings_blocked_keywords = + $.data.read("zhihu_settings_blocked_keywords") != false; + const settings_blocked_users = + $.data.read("zhihu_settings_blocked_users") != false; const user_info = getUserInfo(); - let keywords = magicJS.read(keywordBlockKey, user_info.id); + let keywords = $.data.read(keywordBlockKey, "", user_info.id); keywords = settings_blocked_keywords && !!keywords ? keywords : []; - let customBlockedUsers = magicJS.read(blockedUsersKey, user_info.id); - customBlockedUsers = settings_blocked_users && !!customBlockedUsers ? customBlockedUsers : {}; + let customBlockedUsers = $.data.read(blockedUsersKey, "", user_info.id); + customBlockedUsers = + settings_blocked_users && !!customBlockedUsers ? customBlockedUsers : {}; const dataFilter = (element) => { let elementStr = JSON.stringify(element); // 是否为广告 - let isAd = element["card_type"] === "slot_event_card" || element["card_type"] === "slot_video_event_card" || element.hasOwnProperty("ad"); + let isAd = + element["card_type"] === "slot_event_card" || + element["card_type"] === "slot_video_event_card" || + element.hasOwnProperty("ad") || + element["extra"]["type"] === "Training"; // 是否为流媒体 - let isStream = isAd != true && elementStr.search(/"(type|style)+"\s?:\s?"(drama|zvideo|Video|BIG_IMAGE)+"/i) >= 0; + let isStream = + isAd != true && + elementStr.search( + /"(type|style)+"\s?:\s?"(drama|zvideo|Video|BIG_IMAGE)+"/i + ) >= 0; let removeStream = isStream && settings_recommend_stream; // 是否为文章 - let isArticle = elementStr.search(/"(type|style)+"\s?:\s?"article"/i) >= 0; + let isArticle = + elementStr.search(/"(type|style)+"\s?:\s?"article"/i) >= 0; let removeArticle = isArticle && settings_remove_article; // 是否匹配脚本关键词过滤 let matchKeyword = false; if (isStream != true && settings_blocked_keywords) { for (let i = 0; i < keywords.length; i++) { if (elementStr.search(keywords[i]) >= 0) { - if (magicJS.isDebug) { - let elementTitle = element.common_card.feed_content.title.panel_text; - let elementContent = element.common_card.feed_content.content.panel_text; + if ($.isDebug) { + let elementTitle = + element.common_card.feed_content.title.panel_text; + let elementContent = + element.common_card.feed_content.content.panel_text; let actionUrl = ""; try { - actionUrl = element.common_card.feed_content.title.action.intent_url; - } catch { } - magicJS.logDebug(`匹配关键字:\n${keywords[i]}\n标题:\n${elementTitle}\n内容:\n${elementContent}`); - magicJS.notifyDebug(scriptName, `关键字:${keywords[i]}`, `${elementTitle}\n${elementContent}`, actionUrl); + actionUrl = + element.common_card.feed_content.title.action.intent_url; + } catch {} + $.logger.debug( + `匹配关键字:\n${keywords[i]}\n标题:\n${elementTitle}\n内容:\n${elementContent}` + ); + $.notification.debug( + scriptName, + `关键字:${keywords[i]}`, + `${elementTitle}\n${elementContent}`, + actionUrl + ); } matchKeyword = true; break; @@ -699,19 +883,32 @@ function removeRecommendAds() { let isBlockedUser = false; try { isBlockedUser = - matchKeyword != true && settings_blocked_users && customBlockedUsers && element["common_card"]["feed_content"]["source_line"]["elements"][1]["text"]["panel_text"] in customBlockedUsers; + matchKeyword != true && + settings_blocked_users && + customBlockedUsers && + element["common_card"]["feed_content"]["source_line"]["elements"][1][ + "text" + ]["panel_text"] in customBlockedUsers; } catch { isBlockedUser = false; } - return !(isAd || removeStream || matchKeyword || isBlockedUser || removeArticle); + return !( + isAd || + removeStream || + matchKeyword || + isBlockedUser || + removeArticle + ); }; // 修复number类型精度丢失 - let obj = JSON.parse(magicJS.response.body.replace(/(\w+"+\s?):\s?(\d{15,})/g, '$1:"$2"')); + let obj = JSON.parse( + $.response.body.replace(/(\w+"+\s?):\s?(\d{15,})/g, '$1:"$2"') + ); obj["data"] = obj["data"].filter(dataFilter); response = { body: JSON.stringify(obj) }; } catch (err) { - magicJS.logError(`知乎推荐列表去广告出现异常:${err}`); + $.logger.error(`知乎推荐列表去广告出现异常:${err}`); } return response; } @@ -725,25 +922,36 @@ function removeRecommendAds() { function autoInsertBlackList() { let response = null; try { - let obj = JSON.parse(magicJS.response.body); + let obj = JSON.parse($.response.body); // 删除MCN信息 delete obj["mcn_user_info"]; response = { body: JSON.stringify(obj) }; // 如已是黑名单用户,但不在脚本黑名单中,则自动加入 if (obj.name && obj.id && obj.is_blocking === true) { const userInfo = getUserInfo(); - let customBlockedUsers = magicJS.read(blockedUsersKey, userInfo.id); - customBlockedUsers = typeof customBlockedUsers === "object" && !!customBlockedUsers ? customBlockedUsers : {}; + let customBlockedUsers = $.data.read(blockedUsersKey, "", userInfo.id); + customBlockedUsers = + typeof customBlockedUsers === "object" && !!customBlockedUsers + ? customBlockedUsers + : {}; if (!customBlockedUsers[obj.name]) { - magicJS.logDebug(`当前需要加入黑名单的用户Id:${obj["id"]},用户名:${obj["name"]}`); + $.logger.debug( + `当前需要加入黑名单的用户Id:${obj["id"]},用户名:${obj["name"]}` + ); customBlockedUsers[obj["name"]] = obj["id"]; - magicJS.write(blockedUsersKey, customBlockedUsers, userInfo.id); - magicJS.logDebug(`${obj["name"]}写入脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify(customBlockedUsers)}`); - magicJS.notify(`已自动将用户“${obj["name"]}”写入脚本黑名单。`); + $.data.write(blockedUsersKey, customBlockedUsers, userInfo.id); + $.logger.debug( + `${ + obj["name"] + }写入脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify( + customBlockedUsers + )}` + ); + $.notification.post(`已自动将用户“${obj["name"]}”写入脚本黑名单。`); } } } catch (err) { - magicJS.logError(`知乎去除MCN信息出现异常:${err}`); + $.logger.error(`知乎去除MCN信息出现异常:${err}`); } return response; } @@ -757,26 +965,40 @@ function autoInsertBlackList() { function processUserInfo() { let response = null; try { - let obj = JSON.parse(magicJS.response.body); - magicJS.logDebug(`用户登录用户信息,接口响应:${magicJS.response.body}`); - if (obj && obj["id"] && obj.hasOwnProperty("vip_info") && obj["vip_info"].hasOwnProperty("is_vip")) { + let obj = JSON.parse($.response.body); + $.logger.debug(`用户登录用户信息,接口响应:${$.response.body}`); + if ( + obj && + obj["id"] && + obj.hasOwnProperty("vip_info") && + obj["vip_info"].hasOwnProperty("is_vip") + ) { const userInfo = { id: obj["id"], - is_vip: obj["vip_info"]["is_vip"] ? obj["vip_info"]["is_vip"] !== undefined : false, + is_vip: obj["vip_info"]["is_vip"] + ? obj["vip_info"]["is_vip"] !== undefined + : false, }; - magicJS.logDebug(`当前用户id:${obj["id"]},是否为VIP:${obj["vip_info"]["is_vip"]}`); - magicJS.write(currentUserInfoKey, userInfo); + $.logger.debug( + `当前用户id:${obj["id"]},是否为VIP:${obj["vip_info"]["is_vip"]}` + ); + $.data.write(currentUserInfoKey, userInfo); // 在知乎APP显示VIP,仅自己可见,打开后才能使用屏蔽关键词解锁 - if (magicJS.read("zhihu_settings_fake_vip") != false && obj["vip_info"]["is_vip"] === false) { + if ( + $.data.read("zhihu_settings_fake_vip") != false && + obj["vip_info"]["is_vip"] === false + ) { obj["vip_info"]["is_vip"] = true; obj["vip_info"]["vip_icon"] = { url: "https://pic1.zhimg.com/v2-4812630bc27d642f7cafcd6cdeca3d7a_r.png", - night_mode_url: "https://pic1.zhimg.com/v2-c9686ff064ea3579730756ac6c289978_r.png", + night_mode_url: + "https://pic1.zhimg.com/v2-c9686ff064ea3579730756ac6c289978_r.png", }; obj["vip_info"]["entrance"] = { icon: { url: "https://pic1.zhimg.com/v2-5b7012c8c22fd520f5677305e1e551bf.png", - night_mode_url: "https://pic1.zhimg.com/v2-e51e3252d7a2cb016a70879defd5da0b.png", + night_mode_url: + "https://pic1.zhimg.com/v2-e51e3252d7a2cb016a70879defd5da0b.png", }, title: "我的盐选会员", expires_day: "2033-12-24", @@ -808,10 +1030,12 @@ function processUserInfo() { response = { body: JSON.stringify(obj) }; } } else { - magicJS.logWarning(`没有获取到本次登录用户信息,如未对功能造成影响,请忽略此日志。`); + $.logger.warning( + `没有获取到本次登录用户信息,如未对功能造成影响,请忽略此日志。` + ); } } catch (err) { - magicJS.logError(`知乎获取当前用户信息出现异常:${err}`); + $.logger.error(`知乎获取当前用户信息出现异常:${err}`); } return response; } @@ -825,23 +1049,35 @@ function processUserInfo() { function modifyAnswer() { let response = null; try { - let html = magicJS.response.body; + let html = $.response.body; // 付费内容提醒 - if ((html.indexOf("查看完整内容") >= 0 || html.indexOf("查看全部章节") >= 0) && html.indexOf("paid") >= 0) { + if ( + (html.indexOf("查看完整内容") >= 0 || + html.indexOf("查看全部章节") >= 0) && + html.indexOf("paid") >= 0 + ) { let matchStr = html.match(/(richText[^<]*>)(.)/)[1]; let start = html.lastIndexOf(matchStr) + matchStr.length; let insertText = '
知乎助手 · 本文为付费内容
'; - response = { body: html.slice(0, start) + insertText + html.slice(start) }; + response = { + body: html.slice(0, start) + insertText + html.slice(start), + }; } // 营销推广提醒 - else if (html.indexOf("ad-link-card") >= 0 || html.indexOf("xg.zhihu.com") >= 0 || html.indexOf("知乎营销平台") >= 0) { + else if ( + html.indexOf("ad-link-card") >= 0 || + html.indexOf("xg.zhihu.com") >= 0 || + html.indexOf("知乎营销平台") >= 0 + ) { let matchStr = html.match(/(richText[^<]*>)(.)/)[1]; let start = html.lastIndexOf(matchStr) + matchStr.length; let insertText = '
知乎助手 · 本文含有营销推广
'; - response = { body: html.slice(0, start) + insertText + html.slice(start) }; + response = { + body: html.slice(0, start) + insertText + html.slice(start), + }; } // 购物推广提醒 @@ -850,7 +1086,9 @@ function modifyAnswer() { let start = html.lastIndexOf(matchStr) + matchStr.length; let insertText = '
知乎助手 · 本文含有购物推广
'; - response = { body: html.slice(0, start) + insertText + html.slice(start) }; + response = { + body: html.slice(0, start) + insertText + html.slice(start), + }; } // 彩蛋 @@ -859,15 +1097,16 @@ function modifyAnswer() { let start = html.lastIndexOf(matchStr) + matchStr.length; let insertText = '
知乎助手 · 本文为免费内容
'; - response = { body: html.slice(0, start) + insertText + html.slice(start) }; + response = { + body: html.slice(0, start) + insertText + html.slice(start), + }; } } catch (err) { - magicJS.logError(`知乎付费内容提醒出现异常:${err}`); + $.logger.error(`知乎付费内容提醒出现异常:${err}`); } return response; } - /** * @description: 黑名单管理 * @param {*} @@ -876,96 +1115,128 @@ function modifyAnswer() { function manageBlackUser() { const userInfo = getUserInfo(); let defaultBlockedUsers = {}; - let customBlockedUsers = magicJS.read(blockedUsersKey, userInfo.id); - customBlockedUsers = typeof customBlockedUsers === "object" && !!customBlockedUsers ? customBlockedUsers : {}; + let customBlockedUsers = $.data.read(blockedUsersKey, "", userInfo.id); + customBlockedUsers = + typeof customBlockedUsers === "object" && !!customBlockedUsers + ? customBlockedUsers + : {}; defaultAnswerBlockedUsers.forEach((element) => { customBlockedUsers[element] = "00000000000000000000000000000000"; defaultBlockedUsers[element] = "00000000000000000000000000000000"; }); - magicJS.logDebug(`当前用户id:${userInfo.id},脚本黑名单:${JSON.stringify(customBlockedUsers)}`); + $.logger.debug( + `当前用户id:${userInfo.id},脚本黑名单:${JSON.stringify( + customBlockedUsers + )}` + ); // 获取黑名单 - if (magicJS.request.method == "GET") { + if ($.request.method == "GET") { try { // 加载黑名单首页时,清空历史黑名单,仅保留脚本默认黑名单 - if (magicJS.request.url.indexOf("offset") < 0) { + if ($.request.url.indexOf("offset") < 0) { customBlockedUsers = defaultBlockedUsers; - magicJS.logDebug("脚本黑名单已清空,请滑动至黑名单末尾保证重新获取完成。"); - magicJS.notify("脚本黑名单已清空,请滑动至黑名单末尾保证重新获取完成。"); + $.logger.debug("脚本黑名单已清空,请滑动至黑名单末尾保证重新获取完成。"); + $.notification.post( + "脚本黑名单已清空,请滑动至黑名单末尾保证重新获取完成。" + ); } - let obj = JSON.parse(magicJS.response.body); + let obj = JSON.parse($.response.body); if (!!obj["data"]) { - magicJS.logDebug(`本次滑动获取的黑名单信息:${JSON.stringify(obj["data"])}`); + $.logger.debug(`本次滑动获取的黑名单信息:${JSON.stringify(obj["data"])}`); obj["data"].forEach((element) => { if (element["name"] != "[已重置]") { customBlockedUsers[element["name"]] = element["id"]; } }); - magicJS.write(blockedUsersKey, customBlockedUsers, userInfo.id); + $.data.write(blockedUsersKey, customBlockedUsers, userInfo.id); if (obj["paging"]["is_end"] == true) { - magicJS.notify(`获取脚本黑名单结束,当前黑名单共${Object.keys(customBlockedUsers).length - defaultAnswerBlockedUsers.length}人。\n脚本内置黑名单${defaultAnswerBlockedUsers.length}人。`); - magicJS.logDebug(`脚本黑名单内容:${JSON.stringify(customBlockedUsers)}。`); + $.notification.post( + `获取脚本黑名单结束,当前黑名单共${ + Object.keys(customBlockedUsers).length - + defaultAnswerBlockedUsers.length + }人。\n脚本内置黑名单${defaultAnswerBlockedUsers.length}人。` + ); + $.logger.debug(`脚本黑名单内容:${JSON.stringify(customBlockedUsers)}。`); } } else { - magicJS.logWarning(`获取黑名单失败,接口响应不合法:${magicJS.response.body}`); + $.logger.warning(`获取黑名单失败,接口响应不合法:${$.response.body}`); } } catch (err) { - magicJS.del(blockedUsersKey); - magicJS.logError(`获取黑名单失败,异常信息:${err}`); - magicJS.notify("获取黑名单失败,执行异常,已清空黑名单。"); + $.data.del(blockedUsersKey); + $.logger.error(`获取黑名单失败,异常信息:${err}`); + $.notification.post("获取黑名单失败,执行异常,已清空黑名单。"); } } // 写入黑名单 - else if (magicJS.request.method == "POST") { + else if ($.request.method == "POST") { try { - let obj = JSON.parse(magicJS.response.body); + let obj = JSON.parse($.response.body); if (obj.hasOwnProperty("name") && obj.hasOwnProperty("id")) { - magicJS.logDebug(`当前需要加入黑名单的用户Id:${obj["id"]},用户名:${obj["name"]}`); + $.logger.debug( + `当前需要加入黑名单的用户Id:${obj["id"]},用户名:${obj["name"]}` + ); if (obj["id"]) { customBlockedUsers[obj["name"]] = obj["id"]; - magicJS.write(blockedUsersKey, customBlockedUsers, userInfo.id); - magicJS.logDebug(`${obj["name"]}写入脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify(customBlockedUsers)}`); - magicJS.notify(`已将用户“${obj["name"]}”写入脚本黑名单。`); + $.data.write(blockedUsersKey, customBlockedUsers, userInfo.id); + $.logger.debug( + `${ + obj["name"] + }写入脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify( + customBlockedUsers + )}` + ); + $.notification.post(`已将用户“${obj["name"]}”写入脚本黑名单。`); } else { - magicJS.logError(`${obj["name"]}写入脚本黑名单失败,没有获取到用户Id。`); - magicJS.notify(`将用户“${obj["name"]}”写入脚本黑名单失败!`); + $.logger.error(`${obj["name"]}写入脚本黑名单失败,没有获取到用户Id。`); + $.notification.post(`将用户“${obj["name"]}”写入脚本黑名单失败!`); } } else { - magicJS.logWarning(`写入黑名单失败,接口响应不合法:${magicJS.response.body}`); - magicJS.notify("写入脚本黑名单失败,接口返回不合法。"); + $.logger.warning(`写入黑名单失败,接口响应不合法:${$.response.body}`); + $.notification.post("写入脚本黑名单失败,接口返回不合法。"); } } catch (err) { - magicJS.logError(`写入黑名单失败,异常信息:${err}`); - magicJS.notify("写入脚本黑名单失败,执行异常,请查阅日志。"); + $.logger.error(`写入黑名单失败,异常信息:${err}`); + $.notification.post("写入脚本黑名单失败,执行异常,请查阅日志。"); } } // 移出黑名单 - else if (magicJS.request.method == "DELETE") { + else if ($.request.method == "DELETE") { try { - let obj = JSON.parse(magicJS.response.body); + let obj = JSON.parse($.response.body); if (obj.success) { - let user_id = magicJS.request.url.match(/https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/settings\/blocked_users\/([0-9a-zA-Z]*)/)[1]; + let user_id = $.request.url.match( + /https?:\/\/(api\.zhihu\.com|(103\.41\.167\.(226|234|235|236)))\/settings\/blocked_users\/([0-9a-zA-Z]*)/ + )[1]; if (user_id) { - magicJS.logDebug(`当前需要移出黑名单的用户Id:${user_id}`); + $.logger.debug(`当前需要移出黑名单的用户Id:${user_id}`); for (let username in customBlockedUsers) { if (customBlockedUsers[username] == user_id) { delete customBlockedUsers[username]; - magicJS.write(blockedUsersKey, customBlockedUsers, userInfo.id); - magicJS.logDebug(`${username}移出脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify(customBlockedUsers)}`); - magicJS.notify(`已将用户“${username}”移出脚本黑名单!`); + $.data.write(blockedUsersKey, customBlockedUsers, userInfo.id); + $.logger.debug( + `${username}移出脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify( + customBlockedUsers + )}` + ); + $.notification.post(`已将用户“${username}”移出脚本黑名单!`); break; } } } else { - magicJS.logError("将用户移出脚本黑名单失败!\n建议从设置中刷新黑名单数据。"); - magicJS.notify(`将用户移出脚本黑名单失败,没有获取到用户Id。\n建议从设置中刷新黑名单数据。`); + $.logger.error( + "将用户移出脚本黑名单失败!\n建议从设置中刷新黑名单数据。" + ); + $.notification.post( + `将用户移出脚本黑名单失败,没有获取到用户Id。\n建议从设置中刷新黑名单数据。` + ); } } else { - magicJS.logWarning(`移出黑名单失败,接口响应不合法:${magicJS.response.body}`); - magicJS.notify("移出脚本黑名单失败,接口返回不合法。"); + $.logger.warning(`移出黑名单失败,接口响应不合法:${$.response.body}`); + $.notification.post("移出脚本黑名单失败,接口返回不合法。"); } } catch (err) { - magicJS.logError(`移出黑名单失败,异常信息:${err}`); - magicJS.notify("移出脚本黑名单失败,执行异常,请查阅日志。"); + $.logger.error(`移出黑名单失败,异常信息:${err}`); + $.notification.post("移出脚本黑名单失败,执行异常,请查阅日志。"); } } } @@ -978,7 +1249,7 @@ function manageBlackUser() { function getUserInfo() { let defaultUserInfo = { id: "default", is_vip: false }; try { - const userInfo = magicJS.read(currentUserInfoKey); + const userInfo = $.data.read(currentUserInfoKey); if (typeof userInfo === "string") userInfo = JSON.parse(userInfo); if (!!userInfo && userInfo.hasOwnProperty("id")) { return userInfo; @@ -986,12 +1257,11 @@ function getUserInfo() { return defaultUserInfo; } } catch (err) { - magicJS.logError(`获取用户信息出现异常:${err}`); + $.logger.error(`获取用户信息出现异常:${err}`); return defaultUserInfo; } } - /** * @description: 知乎8.3.0移除推荐页顶部项 * @param {*} @@ -1000,16 +1270,36 @@ function getUserInfo() { function removeFeedSections() { let response = null; try { - let obj = JSON.parse(magicJS.response.body); + let obj = JSON.parse($.response.body); obj.guess_like_sections = []; obj.selected_sections = []; obj.more_sections = []; response = { body: JSON.stringify(obj) }; } catch (err) { - magicJS.logError(`知乎移除推荐页顶部项出现异常:${err}`); + $.logger.error(`知乎移除推荐页顶部项出现异常:${err}`); } return response; } // prettier-ignore -function MagicJS(scriptName = "MagicJS", logLevel = "INFO") { return new class { constructor() { if (this._startTime = Date.now(), this.version = "2.2.3.6", this.scriptName = scriptName, this.logLevels = { DEBUG: 5, INFO: 4, NOTIFY: 3, WARNING: 2, ERROR: 1, CRITICAL: 0, NONE: -1 }, this.isLoon = "undefined" != typeof $loon, this.isQuanX = "undefined" != typeof $task, this.isJSBox = "undefined" != typeof $drive, this.isNode = "undefined" != typeof module && !this.isJSBox, this.isSurge = "undefined" != typeof $httpClient && !this.isLoon, this.node = { request: void 0, fs: void 0, data: {} }, this.iOSUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Mobile/15E148 Safari/604.1", this.pcUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36 Edg/84.0.522.59", this._logLevel = "INFO", this.logLevel = logLevel, this._barkUrl = "", this._barkKey = "", this.isNode) { this.node.fs = require("fs"), this.node.request = require("request"); try { this.node.fs.accessSync("./magic.json", this.node.fs.constants.R_OK | this.node.fs.constants.W_OK) } catch (err) { this.node.fs.writeFileSync("./magic.json", "{}", { encoding: "utf8" }) } this.node.data = require("./magic.json") } else this.isJSBox && ($file.exists("drive://MagicJS") || $file.mkdir("drive://MagicJS"), $file.exists("drive://MagicJS/magic.json") || $file.write({ data: $data({ string: "{}" }), path: "drive://MagicJS/magic.json" })) } set barkUrl(url) { try { let _url = url.replace(/\/+$/g, ""); this._barkUrl = `${/^https?:\/\/([^/]*)/.exec(_url)[0]}/push`, this._barkKey = /\/([^\/]+)\/?$/.exec(_url)[1] } catch (err) { this.logDebug("Bark config error.") } } set logLevel(level) { let magic_loglevel = this.read("magicjs_loglevel"); this._logLevel = magic_loglevel || level.toUpperCase() } get logLevel() { return this._logLevel } get isRequest() { return "undefined" != typeof $request && "undefined" == typeof $response } get isResponse() { return "undefined" != typeof $response } get isDebug() { return "DEBUG" === this.logLevel } get request() { return "undefined" != typeof $request ? $request : void 0 } get response() { return "undefined" != typeof $response ? ($response.hasOwnProperty("status") && ($response.statusCode = $response.status), $response.hasOwnProperty("statusCode") && ($response.status = $response.statusCode), $response) : void 0 } get platform() { return this.isSurge ? "Surge" : this.isQuanX ? "Quantumult X" : this.isLoon ? "Loon" : this.isJSBox ? "JSBox" : this.isNode ? "Node.js" : "Unknown" } read(key, session = "") { let val = ""; this.isSurge || this.isLoon ? val = $persistentStore.read(key) : this.isQuanX ? val = $prefs.valueForKey(key) : this.isNode ? val = this.node.data : this.isJSBox && (val = $file.read("drive://MagicJS/magic.json").string); try { this.isNode && (val = val[key]), this.isJSBox && (val = JSON.parse(val)[key]), session && ("string" == typeof val && (val = JSON.parse(val)), val = val && "object" == typeof val ? val[session] : null) } catch (err) { this.logError(err), val = session ? {} : null, this.del(key) } void 0 === val && (val = null); try { val && "string" == typeof val && (val = JSON.parse(val)) } catch (err) { } return this.logDebug(`READ DATA [${key}]${session ? `[${session}]` : ""}(${typeof val})\n${JSON.stringify(val)}`), val } write(key, val, session = "") { let data = session ? {} : ""; if (session && (this.isSurge || this.isLoon) ? data = $persistentStore.read(key) : session && this.isQuanX ? data = $prefs.valueForKey(key) : this.isNode ? data = this.node.data : this.isJSBox && (data = JSON.parse($file.read("drive://MagicJS/magic.json").string)), session) { try { "string" == typeof data && (data = JSON.parse(data)), data = "object" == typeof data && data ? data : {} } catch (err) { this.logError(err), this.del(key), data = {} } this.isJSBox || this.isNode ? (data[key] && "object" == typeof data[key] || (data[key] = {}), data[key].hasOwnProperty(session) || (data[key][session] = null), void 0 === val ? delete data[key][session] : data[key][session] = val) : void 0 === val ? delete data[session] : data[session] = val } else this.isNode || this.isJSBox ? void 0 === val ? delete data[key] : data[key] = val : data = void 0 === val ? null : val; "object" == typeof data && (data = JSON.stringify(data)), this.isSurge || this.isLoon ? $persistentStore.write(data, key) : this.isQuanX ? $prefs.setValueForKey(data, key) : this.isNode ? this.node.fs.writeFileSync("./magic.json", data) : this.isJSBox && $file.write({ data: $data({ string: data }), path: "drive://MagicJS/magic.json" }), this.logDebug(`WRITE DATA [${key}]${session ? `[${session}]` : ""}(${typeof val})\n${JSON.stringify(val)}`) } del(key, session = "") { this.logDebug(`DELETE KEY [${key}]${session ? `[${session}]` : ""}`), this.write(key, null, session) } notify(title = this.scriptName, subTitle = "", body = "", opts = "") { let convertOptions; if (opts = (_opts => { let newOpts = {}; if ("string" == typeof _opts) this.isLoon ? newOpts = { openUrl: _opts } : this.isQuanX ? newOpts = { "open-url": _opts } : this.isSurge && (newOpts = { url: _opts }); else if ("object" == typeof _opts) if (this.isLoon) newOpts.openUrl = _opts["open-url"] ? _opts["open-url"] : "", newOpts.mediaUrl = _opts["media-url"] ? _opts["media-url"] : ""; else if (this.isQuanX) newOpts = _opts["open-url"] || _opts["media-url"] ? _opts : {}; else if (this.isSurge) { let openUrl = _opts["open-url"] || _opts.openUrl; newOpts = openUrl ? { url: openUrl } : {} } return newOpts })(opts), 1 == arguments.length && (title = this.scriptName, subTitle = "", body = arguments[0]), this.logNotify(`title:${title}\nsubTitle:${subTitle}\nbody:${body}\noptions:${"object" == typeof opts ? JSON.stringify(opts) : opts}`), this.isSurge) $notification.post(title, subTitle, body, opts); else if (this.isLoon) opts ? $notification.post(title, subTitle, body, opts) : $notification.post(title, subTitle, body); else if (this.isQuanX) $notify(title, subTitle, body, opts); else if (this.isJSBox) { let push = { title: title, body: subTitle ? `${subTitle}\n${body}` : body }; $push.schedule(push) } this._barkUrl && this._barkKey && this.notifyBark(title, subTitle, body) } notifyDebug(title = this.scriptName, subTitle = "", body = "", opts = "") { "DEBUG" === this.logLevel && (1 == arguments.length && (title = this.scriptName, subTitle = "", body = arguments[0]), this.notify(title, subTitle, body, opts)) } notifyBark(title = this.scriptName, subTitle = "", body = "", opts = "") { let options = { url: this._barkUrl, headers: { "Content-Type": "application/json; charset=utf-8" }, body: { title: title, body: subTitle ? `${subTitle}\n${body}` : body, device_key: this._barkKey } }; this.post(options, err => { }) } log(msg, level = "INFO") { this.logLevels[this._logLevel] < this.logLevels[level.toUpperCase()] || console.log(`[${level}] [${this.scriptName}]\n${msg}\n`) } logDebug(msg) { this.log(msg, "DEBUG") } logInfo(msg) { this.log(msg, "INFO") } logNotify(msg) { this.log(msg, "NOTIFY") } logWarning(msg) { this.log(msg, "WARNING") } logError(msg) { this.log(msg, "ERROR") } logRetry(msg) { this.log(msg, "RETRY") } adapterHttpOptions(options, method) { let _options = "object" == typeof options ? Object.assign({}, options) : { url: options, headers: {} }; _options.hasOwnProperty("header") && !_options.hasOwnProperty("headers") && (_options.headers = _options.header, delete _options.header), _options.headers && "object" == typeof _options.headers && _options.headers["User-Agent"] || (_options.headers && "object" == typeof _options.headers || (_options.headers = {}), this.isNode ? _options.headers["User-Agent"] = this.pcUserAgent : _options.headers["User-Agent"] = this.iOSUserAgent); let skipScripting = !1; if (("object" == typeof _options.opts && (!0 === _options.opts.hints || !0 === _options.opts["Skip-Scripting"]) || "object" == typeof _options.headers && !0 === _options.headers["X-Surge-Skip-Scripting"]) && (skipScripting = !0), skipScripting || (this.isSurge ? _options.headers["X-Surge-Skip-Scripting"] = !1 : this.isLoon ? _options.headers["X-Requested-With"] = "XMLHttpRequest" : this.isQuanX && ("object" != typeof _options.opts && (_options.opts = {}), _options.opts.hints = !1)), this.isSurge && !skipScripting || delete _options.headers["X-Surge-Skip-Scripting"], !this.isQuanX && _options.hasOwnProperty("opts") && delete _options.opts, this.isQuanX && _options.hasOwnProperty("opts") && delete _options.opts["Skip-Scripting"], "GET" === method && !this.isNode && _options.body) { let qs = Object.keys(_options.body).map(key => void 0 === _options.body ? "" : `${encodeURIComponent(key)}=${encodeURIComponent(_options.body[key])}`).join("&"); _options.url.indexOf("?") < 0 && (_options.url += "?"), _options.url.lastIndexOf("&") + 1 != _options.url.length && _options.url.lastIndexOf("?") + 1 != _options.url.length && (_options.url += "&"), _options.url += qs, delete _options.body } return this.isQuanX ? (_options.hasOwnProperty("body") && "string" != typeof _options.body && (_options.body = JSON.stringify(_options.body)), _options.method = method) : this.isNode ? (delete _options.headers["Accept-Encoding"], "object" == typeof _options.body && ("GET" === method ? (_options.qs = _options.body, delete _options.body) : "POST" === method && (_options.json = !0, _options.body = _options.body))) : this.isJSBox && (_options.header = _options.headers, delete _options.headers), _options } adapterHttpResponse(resp) { let _resp = { body: resp.body, headers: resp.headers, json: () => JSON.parse(_resp.body) }; return resp.hasOwnProperty("statusCode") && resp.statusCode && (_resp.status = resp.statusCode), _resp } get(options, callback) { let _options = this.adapterHttpOptions(options, "GET"); this.logDebug(`HTTP GET: ${JSON.stringify(_options)}`), this.isSurge || this.isLoon ? $httpClient.get(_options, callback) : this.isQuanX ? $task.fetch(_options).then(resp => { resp.status = resp.statusCode, callback(null, resp, resp.body) }, reason => callback(reason.error, null, null)) : this.isNode ? this.node.request.get(_options, (err, resp, data) => { resp = this.adapterHttpResponse(resp), callback(err, resp, data) }) : this.isJSBox && (_options.handler = resp => { let err = resp.error ? JSON.stringify(resp.error) : void 0, data = "object" == typeof resp.data ? JSON.stringify(resp.data) : resp.data; callback(err, resp.response, data) }, $http.get(_options)) } getPromise(options) { return new Promise((resolve, reject) => { magicJS.get(options, (err, resp) => { err ? reject(err) : resolve(resp) }) }) } post(options, callback) { let _options = this.adapterHttpOptions(options, "POST"); if (this.logDebug(`HTTP POST: ${JSON.stringify(_options)}`), this.isSurge || this.isLoon) $httpClient.post(_options, callback); else if (this.isQuanX) $task.fetch(_options).then(resp => { resp.status = resp.statusCode, callback(null, resp, resp.body) }, reason => { callback(reason.error, null, null) }); else if (this.isNode) { let resp = this.node.request.post(_options, callback); resp.status = resp.statusCode, delete resp.statusCode } else this.isJSBox && (_options.handler = resp => { let err = resp.error ? JSON.stringify(resp.error) : void 0, data = "object" == typeof resp.data ? JSON.stringify(resp.data) : resp.data; callback(err, resp.response, data) }, $http.post(_options, {})) } done(value = {}) { this._endTime = Date.now(); let span = (this._endTime - this._startTime) / 1e3; magicJS.logDebug(`SCRIPT COMPLETED: ${span}S.`), "undefined" != typeof $done && $done(value) } isToday(day) { if (null == day) return !1; { let today = new Date; return "string" == typeof day && (day = new Date(day)), today.getFullYear() == day.getFullYear() && today.getMonth() == day.getMonth() && today.getDay() == day.getDay() } } isNumber(val) { return "NaN" !== parseFloat(val).toString() } attempt(promise, defaultValue = null) { return promise.then(args => [null, args]).catch(ex => (this.logError(ex), [ex, defaultValue])) } retry(fn, retries = 5, interval = 0, callback = null) { return (...args) => new Promise((resolve, reject) => { function _retry(...args) { Promise.resolve().then(() => fn.apply(this, args)).then(result => { "function" == typeof callback ? Promise.resolve().then(() => callback(result)).then(() => { resolve(result) }).catch(ex => { retries >= 1 ? interval > 0 ? setTimeout(() => _retry.apply(this, args), interval) : _retry.apply(this, args) : reject(ex), retries-- }) : resolve(result) }).catch(ex => { this.logRetry(ex), retries >= 1 && interval > 0 ? setTimeout(() => _retry.apply(this, args), interval) : retries >= 1 ? _retry.apply(this, args) : reject(ex), retries-- }) } _retry.apply(this, args) }) } formatTime(time, fmt = "yyyy-MM-dd hh:mm:ss") { var o = { "M+": time.getMonth() + 1, "d+": time.getDate(), "h+": time.getHours(), "m+": time.getMinutes(), "s+": time.getSeconds(), "q+": Math.floor((time.getMonth() + 3) / 3), S: time.getMilliseconds() }; /(y+)/.test(fmt) && (fmt = fmt.replace(RegExp.$1, (time.getFullYear() + "").substr(4 - RegExp.$1.length))); for (let k in o) new RegExp("(" + k + ")").test(fmt) && (fmt = fmt.replace(RegExp.$1, 1 == RegExp.$1.length ? o[k] : ("00" + o[k]).substr(("" + o[k]).length))); return fmt } now() { return this.formatTime(new Date, "yyyy-MM-dd hh:mm:ss") } today() { return this.formatTime(new Date, "yyyy-MM-dd") } sleep(time) { return new Promise(resolve => setTimeout(resolve, time)) } }(scriptName) } +/** + * + * $$\ $$\ $$\ $$$$$\ $$$$$$\ $$$$$$\ + * $$$\ $$$ | \__| \__$$ |$$ __$$\ $$ ___$$\ + * $$$$\ $$$$ | $$$$$$\ $$$$$$\ $$\ $$$$$$$\ $$ |$$ / \__| \_/ $$ | + * $$\$$\$$ $$ | \____$$\ $$ __$$\ $$ |$$ _____| $$ |\$$$$$$\ $$$$$ / + * $$ \$$$ $$ | $$$$$$$ |$$ / $$ |$$ |$$ / $$\ $$ | \____$$\ \___$$\ + * $$ |\$ /$$ |$$ __$$ |$$ | $$ |$$ |$$ | $$ | $$ |$$\ $$ | $$\ $$ | + * $$ | \_/ $$ |\$$$$$$$ |\$$$$$$$ |$$ |\$$$$$$$\\$$$$$$ |\$$$$$$ | \$$$$$$ | + * \__| \__| \_______| \____$$ |\__| \_______|\______/ \______/ \______/ + * $$\ $$ | + * \$$$$$$ | + * \______/ + * + */ +// prettier-ignore +function MagicJS(e="MagicJS",t="INFO"){const i=()=>{const e=typeof $loon!=="undefined";const t=typeof $task!=="undefined";const n=typeof module!=="undefined";const i=typeof $httpClient!=="undefined"&&!e;const s=typeof $storm!=="undefined";const r=typeof $environment!=="undefined"&&typeof $environment["stash-build"]!=="undefined";const o=i||e||s||r;const u=typeof importModule!=="undefined";return{isLoon:e,isQuanX:t,isNode:n,isSurge:i,isStorm:s,isStash:r,isSurgeLike:o,isScriptable:u,get name(){if(e){return"Loon"}else if(t){return"QuantumultX"}else if(n){return"NodeJS"}else if(i){return"Surge"}else if(u){return"Scriptable"}else{return"unknown"}},get build(){if(i){return $environment["surge-build"]}else if(r){return $environment["stash-build"]}else if(s){return $storm.buildVersion}},get language(){if(i||r){return $environment["language"]}},get version(){if(i){return $environment["surge-version"]}else if(r){return $environment["stash-version"]}else if(s){return $storm.appVersion}else if(n){return process.version}},get system(){if(i){return $environment["system"]}else if(n){return process.platform}},get systemVersion(){if(s){return $storm.systemVersion}},get deviceName(){if(s){return $storm.deviceName}}}};const s=(n,e="INFO")=>{let i=e;const s={SNIFFER:6,DEBUG:5,INFO:4,NOTIFY:3,WARNING:2,ERROR:1,CRITICAL:0,NONE:-1};const r={SNIFFER:"",DEBUG:"",INFO:"",NOTIFY:"",WARNING:"❗ ",ERROR:"❌ ",CRITICAL:"❌ ",NONE:""};const t=(e,t="INFO")=>{if(!(s[i]{i=e};return{setLevel:o,sniffer:e=>{t(e,"SNIFFER")},debug:e=>{t(e,"DEBUG")},info:e=>{t(e,"INFO")},notify:e=>{t(e,"NOTIFY")},warning:e=>{t(e,"WARNING")},error:e=>{t(e,"ERROR")},retry:e=>{t(e,"RETRY")}}};return new class{constructor(e,t){this._startTime=Date.now();this.version="3.0.0";this.scriptName=e;this.env=i();this.logger=s(e,t);this.http=typeof MagicHttp==="function"?MagicHttp(this.env,this.logger):undefined;this.data=typeof MagicData==="function"?MagicData(this.env,this.logger):undefined;this.notification=typeof MagicNotification==="function"?MagicNotification(this.scriptName,this.env,this.logger):undefined;this.utils=typeof MagicUtils==="function"?MagicUtils(this.env,this.logger):undefined;this.qinglong=typeof MagicQingLong==="function"?MagicQingLong(this.env,this.data,this.logger):undefined;if(typeof this.data!=="undefined"){let e=this.data.read("magic_loglevel");const n=this.data.read("magic_bark_url");if(e){this.logger.setLevel(e.toUpperCase())}if(n){this.notification.setBark(n)}}}get isRequest(){return typeof $request!=="undefined"&&typeof $response==="undefined"}get isResponse(){return typeof $response!=="undefined"}get isDebug(){return this.logger.level==="DEBUG"}get request(){if(typeof $request!=="undefined"){this.logger.sniffer(`RESPONSE:\n${JSON.stringify($request)}`);return $request}}get response(){if(typeof $response!=="undefined"){if($response.hasOwnProperty("status"))$response["statusCode"]=$response["status"];if($response.hasOwnProperty("statusCode"))$response["status"]=$response["statusCode"];this.logger.sniffer(`RESPONSE:\n${JSON.stringify($response)}`);return $response}else{return undefined}}done=(e={})=>{this._endTime=Date.now();let t=(this._endTime-this._startTime)/1e3;this.logger.info(`SCRIPT COMPLETED: ${t} S.`);if(typeof $done!=="undefined"){$done(e)}}}(e,t)} +// prettier-ignore +function MagicNotification(r,f,l){let s=null;let u=null;const c=typeof MagicHttp==="function"?MagicHttp(f,l):undefined;const e=t=>{try{let e=t.replace(/\/+$/g,"");s=`${/^https?:\/\/([^/]*)/.exec(e)[0]}/push`;u=/\/([^\/]+)\/?$/.exec(e)[1]}catch(e){l.error(`Bark url error: ${e}.`)}};function t(e=r,t="",i="",o=""){const n=i=>{try{let t={};if(typeof i==="string"){if(f.isLoon)t={openUrl:i};else if(f.isQuanX)t={"open-url":i};else if(f.isSurge)t={url:i}}else if(typeof i==="object"){if(f.isLoon){t["openUrl"]=!!i["open-url"]?i["open-url"]:"";t["mediaUrl"]=!!i["media-url"]?i["media-url"]:""}else if(f.isQuanX){t=!!i["open-url"]||!!i["media-url"]?i:{}}else if(f.isSurge){let e=i["open-url"]||i["openUrl"];t=e?{url:e}:{}}}return t}catch(e){l.error(`Failed to convert notification option, ${e}`)}return i};o=n(o);if(arguments.length==1){e=r;t="",i=arguments[0]}l.notify(`title:${e}\nsubTitle:${t}\nbody:${i}\noptions:${typeof o==="object"?JSON.stringify(o):o}`);if(f.isSurge){$notification.post(e,t,i,o)}else if(f.isLoon){if(!!o)$notification.post(e,t,i,o);else $notification.post(e,t,i)}else if(f.isQuanX){$notify(e,t,i,o)}if(s&&u&&typeof c!=="undefined"){p(e,t,i)}}function i(e=r,t="",i="",o=""){if(l.level==="DEBUG"){if(arguments.length==1){e=r;t="",i=arguments[0]}this.notify(e,t,i,o)}}function p(e=r,t="",i="",o=""){if(typeof c==="undefined"||typeof c.post==="undefined"){throw"Bark notification needs to import MagicHttp module."}let n={url:s,headers:{"Content-Type":"application/json; charset=utf-8"},body:{title:e,body:t?`${t}\n${i}`:i,device_key:u}};c.post(n).catch(e=>{l.error(`Bark notify error: ${e}`)})}return{post:t,debug:i,bark:p,setBark:e}} +// prettier-ignore +function MagicData(l,f){let u={fs:undefined,data:{}};if(l.isNode){u.fs=require("fs");try{u.fs.accessSync("./magic.json",u.fs.constants.R_OK|u.fs.constants.W_OK)}catch(e){u.fs.writeFileSync("./magic.json","{}",{encoding:"utf8"})}u.data=require("./magic.json")}const o=(e,t)=>{if(typeof t==="object"){return false}else{return e===t}};const a=e=>{if(e==="true"){return true}else if(e==="false"){return false}else if(typeof e==="undefined"){return null}else{return e}};const c=(e,t,r,s)=>{if(r){try{if(typeof e==="string")e=JSON.parse(e);if(e["magic_session"]===true){e=e[r]}else{e=null}}catch{e=null}}if(typeof e==="string"&&e!=="null"){try{e=JSON.parse(e)}catch{}}if(s===false&&!!e&&e["magic_session"]===true){e=null}if((e===null||typeof e==="undefined")&&t!==null&&typeof t!=="undefined"){e=t}e=a(e);return e};const i=t=>{if(typeof t==="string"){let e={};try{e=JSON.parse(t);const r=typeof e;if(r!=="object"||e instanceof Array||r==="bool"||e===null){e={}}}catch{}return e}else if(t instanceof Array||t===null||typeof t==="undefined"||t!==t||typeof t==="boolean"){return{}}else{return t}};const y=(e,t=null,r="",s=false,n=null)=>{let i=n||u.data;if(!!i&&typeof i[e]!=="undefined"&&i[e]!==null){val=i[e]}else{val=!!r?{}:null}val=c(val,t,r,s);return val};const d=(e,t=null,r="",s=false,n=null)=>{let i="";if(n||l.isNode){i=y(e,t,r,s,n)}else{if(l.isSurgeLike){i=$persistentStore.read(e)}else if(l.isQuanX){i=$prefs.valueForKey(e)}i=c(i,t,r,s)}f.debug(`READ DATA [${e}]${!!r?`[${r}]`:""} <${typeof i}>\n${JSON.stringify(i)}`);return i};const p=(t,r,s="",e=null)=>{let n=e||u.data;n=i(n);if(!!s){let e=i(n[t]);e["magic_session"]=true;e[s]=r;n[t]=e}else{n[t]=r}if(e!==null){e=n}return n};const g=(e,t,r="",s=null)=>{if(typeof t==="undefined"||t!==t){return false}if(!l.isNode&&(typeof t==="boolean"||typeof t==="number")){t=String(t)}let n="";if(s||l.isNode){n=p(e,t,r,s)}else{if(!r){n=t}else{if(l.isSurgeLike){n=!!$persistentStore.read(e)?$persistentStore.read(e):n}else if(l.isQuanX){n=!!$prefs.valueForKey(e)?$prefs.valueForKey(e):n}n=i(n);n["magic_session"]=true;n[r]=t}}if(!!n&&typeof n==="object"){n=JSON.stringify(n,"","\t")}f.debug(`WRITE DATA [${e}]${r?`[${r}]`:""} <${typeof t}>\n${JSON.stringify(t)}`);if(!s){if(l.isSurgeLike){return $persistentStore.write(n,e)}else if(l.isQuanX){return $prefs.setValueForKey(n,e)}else if(l.isNode){try{u.fs.writeFileSync("./magic.json",n);return true}catch(e){f.error(e);return false}}}return true};const e=(t,r,s,n=o,i=null)=>{r=a(r);const e=d(t,null,s,false,i);if(n(e,r)===true){return false}else{const l=g(t,r,s,i);let e=d(t,null,s,false,i);if(n===o&&typeof e==="object"){return l}return n(r,e)}};const S=(e,t,r)=>{let s=r||u.data;s=i(s);if(!!t){obj=i(s[e]);delete obj[t];s[e]=obj}else{delete s[e]}if(!!r){r=s}return s};const t=(e,t="",r=null)=>{let s={};if(r||l.isNode){s=S(e,t,r);if(!r){u.fs.writeFileSync("./magic.json",JSON.stringify(s))}else{r=s}}else{if(!t){if(l.isStorm){return $persistentStore.remove(e)}else if(l.isSurgeLike){return $persistentStore.write(null,e)}else if(l.isQuanX){return $prefs.removeValueForKey(e)}}else{if(l.isSurgeLike){s=$persistentStore.read(e)}else if(l.isQuanX){s=$prefs.valueForKey(e)}s=i(s);delete s[t];const n=JSON.stringify(s);g(e,n)}}f.debug(`DELETE KEY [${e}]${!!t?`[${t}]`:""}`)};const r=(e,t=null)=>{let r=[];let s=d(e,null,null,true,t);s=i(s);if(s["magic_session"]!==true){r=[]}else{r=Object.keys(s).filter(e=>e!=="magic_session")}f.debug(`READ ALL SESSIONS [${e}] <${typeof r}>\n${JSON.stringify(r)}`);return r};return{read:d,write:g,del:t,update:e,allSessions:r,defaultValueComparator:o,convertToObject:i}}