diff --git a/Rewrite/AdBlock/Zhihu.conf b/Rewrite/AdBlock/Zhihu.conf new file mode 100644 index 0000000..b40efb3 --- /dev/null +++ b/Rewrite/AdBlock/Zhihu.conf @@ -0,0 +1,59 @@ +# 脚本来自: https://github.com/blackmatrix7/ios_rule_script/ + +hostname = www.zhihu.com,api.zhihu.com,zhuanlan.zhihu.com,appcloud2.zhihu.com,103.41.167.236,103.41.167.234,103.41.167.235,103.41.167.226 + +# 知乎处理用户信息 +^https?:\/\/api\.zhihu\.com\/people\/ url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js +# 知乎信息流去广告 +^https?:\/\/api\.zhihu\.com\/(moments|topstory)(\/|\?)?(recommend|action=|feed_type=)(?!\/people) url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js +# 知乎回答列表去广告 +^https?:\/\/api\.zhihu\.com\/(v4\/)?questions\/\d+ url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js +# 知乎获取黑名单 +^https?:\/\/api\.zhihu\.com\/settings\/blocked_users url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js +# 知乎官方消息去广告 +^https?:\/\/api\.zhihu\.com\/notifications\/v3\/(message|timeline\/entry\/system_message) url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js +# 知乎预置关键词去广告 +^https?:\/\/api\.zhihu\.com\/search\/preset_words\? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js +# 优化软件配置 +^https?:\/\/appcloud2\.zhihu\.com\/v\d+\/config url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js +# 知乎热搜去广告 +^https?:\/\/api\.zhihu\.com\/search\/top_search\/tabs\/hot\/items url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js +# 知乎热榜去广告 +^https?:\/\/api\.zhihu\.com\/topstory\/hot-lists?(\?|\/) url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js +# 知乎评论去广告 +^https?:\/\/api\.zhihu\.com\/(comment_v5\/)?(answers|comments?|articles|pins)\/\d+\/(root_|child_)?comments? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js +# 知乎回答列表去广告 +^https?:\/\/www\.zhihu\.com\/appview\/v2\/answer\/.*(entry=(?!(preload-topstory|preload-search|preload-subscription)))? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js +# 知乎屏蔽关键词解锁 +^https?:\/\/api\.zhihu\.com\/feed-root\/block url script-analyze-echo-response https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js +# 知乎8.3.0移除推荐页顶部项 +^https?:\/\/api\.zhihu\.com\/feed-root\/sections\/query\/v2 url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js +# 拦截知乎开屏广告 +URL-REGEX,^https?:\/\/api\.zhihu\.com\/commercial_api\/launch_v2\? url reject-dict +# 知乎去除最常访问 +^https?:\/\/api\.zhihu\.com\/moments\/recent url reject-dict +# 知乎去除回答下的广告 +^https?:\/\/www\.zhihu\.com\/api\/v4\/answers\/\d+\/recommendations url reject-dict +# 知乎其他广告拦截 +^https?:\/\/api\.zhihu\.com\/(notifications\/v\d\/count|v\d\/package|me\/guides|drama\/living-info|ad|fringe|commercial|market\/popovers|.*featured-comment-ad|ad-style-service) url reject-dict +# 知乎拦截部分预加载 +# ^https?:\/\/www\.zhihu\.com\/appview\/(p|v2\/answer|zvideo)\/.*entry=(preload-topstory|preload-search|preload-subscription) url reject-dict +# 知乎网页版去广告 +^https?:\/\/www\.zhihu\.com\/api\/v4/(questions|anwsers)\/\d+/related-readings url reject-dict +^https?:\/\/www\.zhihu\.com\/api\/v4\/hot_recommendation url reject-dict +^https?:\/\/www\.zhihu\.com\/commercial_api\/banners_v3\/mobile_banner url reject-dict +^https?:\/\/zhuanlan\.zhihu\.com\/api\/articles\/\d+\/recommendation url reject-dict +# 知乎品牌提问广告 +^https?:\/\/api\.zhihu\.com\/brand\/question\/\d+/card\? url reject-dict +^https?:\/\/www\.zhihu\.com\/api\/v\d+\/brand\/question/\d+/card\? url reject-dict +# 屏蔽消息页面上拉的用户精选 +^https?:\/\/api\.zhihu\.com/moments/hybrid\? url reject-dict +# 知乎下发的配置,如皮肤等 +^https?:\/\/api\.zhihu\.com\/ab\/api\/v1\/products\/zhihu\/platforms\/ios\/config url reject-200 +# 屏蔽知乎“我的”页面推荐开通会员的卡片 +^https?:\/\/api\.zhihu\.com\/people\/self\/new_user_card url reject-200 +# 知乎去除Tab页关注人头像 +^https?:\/\/api\.zhihu\.com\/moments\/tab_v2 url reject-dict +# 屏蔽知乎8.3.0版本首页顶部的视频角标 +^https?:\/\/api\.zhihu\.com\/explore\/entry\/tips url reject + diff --git a/Scripts/AdBlock/Zhihu/Zhihu.js b/Scripts/AdBlock/Zhihu/Zhihu.js new file mode 100644 index 0000000..feaf14d --- /dev/null +++ b/Scripts/AdBlock/Zhihu/Zhihu.js @@ -0,0 +1,1289 @@ +const scriptName = "知乎助手"; +const blockedUsersKey = "zhihu_blocked_users"; +const currentUserInfoKey = "zhihu_current_userinfo"; +const keywordBlockKey = "zhihu_keyword_block"; +// 默认屏蔽推荐列表的用户,通常不是真实用户,无法通过加入黑名单屏蔽 +const defaultAnswerBlockedUsers = ["会员推荐"]; +const keywordMaxCount = 1000; // 允许设置的关键词数量 +const $ = MagicJS(scriptName, "INFO"); + +(() => { + let response = null; + if ($.isResponse) { + switch (true) { + // 知乎8.3.0移除推荐页顶部项 + 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 $.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( + $.request.url + ): + response = processUserInfo(); + break; + // 黑名单增强 - 浏览黑名单用户信息时自动加入脚本黑名单 + 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( + $.request.url + ): + response = removeRecommendAds(); + break; + // 关注列表去广告 + 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( + $.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( + $.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( + $.request.url + ): + response = removeCommentAds(); + break; + // 知乎热榜去广告 + 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 $.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 $.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 $.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 $.data.read("zhihu_settings_app_conf") == true && + /^https?:\/\/appcloud2\.zhihu\.com\/v\d+\/config/.test($.request.url): + response = modifyAppConfig(); + break; + // 知乎热搜去广告 + 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 $.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 ($.isRequest) { + // 知乎屏蔽关键词解锁 + 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 { + $.data.del(currentUserInfoKey); + $.data.del(blockedUsersKey); + $.data.del(keywordBlockKey); + $.notification.post("知乎助手数据清理完毕"); + } + if (response) { + $.done(response); + } else { + $.done(); + } +})(); + +/** + * 屏蔽官方营销消息 + * + * @param {*} + * @return {*} + */ +function removeMarketingMsg() { + let response = null; + try { + let obj = JSON.parse($.response.body); + let newItems = []; + for (let item of obj["data"]) { + if (item["detail_title"] === "官方帐号消息") { + let unread_count = item["unread_count"]; + if (unread_count > 0) { + item["content"]["text"] = "未读消息" + unread_count + "条"; + } else { + item["content"]["text"] = "全部消息已读"; + } + item["is_read"] = true; + item["unread_count"] = 0; + newItems.push(item); + } else if (item["detail_title"] !== "知乎活动助手") { + newItems.push(item); + } + } + obj["data"] = newItems; + response = { body: JSON.stringify(obj) }; + } catch (err) { + $.logger.error(`知乎屏蔽官方营销消息出现异常:${err}`); + } + return response; +} + +/** + * 知乎屏蔽关键词解锁 + * + * @param {*} + * @return {*} + */ +function unlockBlockedKeywords() { + let response = null; + try { + const userInfo = getUserInfo(); + // 获取屏蔽关键词列表 + 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", + "Content-Type": "application/json;charset=utf-8", + Pragma: "no-cache", + "Referrer-Policy": "no-referrer-when-downgrade", + Server: "CLOUD ELB 1.0.0", + Vary: "Accept-Encoding", + "X-Cache-Lookup": "Cache Miss", + "x-cdn-provider": "tencent", + }; + let body = JSON.stringify({ + success: true, + is_vip: true, + kw_min_length: 2, + kw_max_length: 100, + kw_max_count: keywordMaxCount, + data: keywords, + }); + if ($.env.isQuanX) { + response = { body: body, headers: headers, status: "HTTP/1.1 200 OK" }; + } else { + response = { response: { body: body, headers: headers, status: 200 } }; + } + $.logger.debug(`获取本地脚本屏蔽关键词:\n${keywords.join("、")}`); + } + + // 添加屏蔽关键词 + 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", + "Content-Type": "application/json;charset=utf-8", + Pragma: "no-cache", + "Referrer-Policy": "no-referrer-when-downgrade", + Server: "CLOUD ELB 1.0.0", + Vary: "Accept-Encoding", + "X-Cache-Lookup": "Cache Miss", + "x-cdn-provider": "tencent", + }; + // 读取关键词 + let keyword = decodeURIComponent($.request.body).match( + /keyword=(.*)/ + )[1]; + let keywords = $.data.read(keywordBlockKey, null, userInfo.id); + if (!keywords) { + keywords = []; + } + // 判断关键词是否存在 + let keywordExists = false; + for (let i = 0; i < keywords.length; i++) { + if (keyword === keywords[i]) { + keywordExists = true; + break; + } + } + // 不存在添加,存在返回异常 + if (keywordExists === false) { + keywords.push(keyword); + $.data.write(keywordBlockKey, keywords, userInfo.id); + let body = JSON.stringify({ success: true }); + if ($.env.isQuanX) { + response = { + body: body, + headers: headers, + status: "HTTP/1.1 200 OK", + }; + } else { + response = { + response: { body: body, headers: headers, status: 200 }, + }; + } + $.logger.debug(`添加本地脚本屏蔽关键词“${keyword}”`); + } else { + let body = JSON.stringify({ + error: { + message: "关键词已存在", + code: 100002, + }, + }); + if ($.env.isQuanX) { + response = { + body: body, + headers: headers, + status: "HTTP/1.1 400 Bad Request", + }; + } else { + response = { + response: { body: body, headers: headers, status: 400 }, + }; + } + } + } + } + + // 删除屏蔽关键词 + 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; + }); + $.data.write(keywordBlockKey, keywords, userInfo.id); + let headers = { + "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", + "Referrer-Policy": "no-referrer-when-downgrade", + 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 ($.env.isQuanX) { + response = { body: body, headers: headers, status: "HTTP/1.1 200 OK" }; + } else { + response = { response: { body: body, headers: headers, status: 200 } }; + } + $.logger.debug(`删除本地脚本屏蔽关键词:“${keyword}”`); + } + } catch (err) { + $.logger.debug(`知乎关键词屏蔽操作出现异常:${err}`); + } + return response; +} + +/** + * 知乎热搜去广告 + * + * @param {*} + * @return {*} + */ +function removeHotSearchAds() { + let response = null; + try { + if (!!$.response.body) { + let obj = JSON.parse($.response.body); + obj["commercial_data"] = []; + response = { body: JSON.stringify(obj) }; + } + } catch (err) { + $.logger.error(`去除知乎热搜广告出现异常:${err}`); + } + return response; +} + +/** + * 优化知乎软件配置 + * + * @param {*} + * @return {*} + */ +function modifyAppConfig() { + let response = null; + try { + 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; + // 试着去除一些配置,效果待验证 + delete obj["config"]["soso_des"]; + delete obj["config"]["cronet"]; + // 屏蔽知乎8.X版本以上本地DNS解析,以下修改不清楚哪些是有效的,暂时全部保留 + if (obj["config"].hasOwnProperty("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"; + } + response = { body: JSON.stringify(obj) }; + } + } catch (err) { + $.logger.error(`优化知乎软件配置出现异常:${err}`); + } + return response; +} + +/** + * 去除预置关键字广告 + * + * @param {*} + * @return {*} + */ +function removeKeywordAds() { + let response = null; + try { + 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"; + }); + obj["preset_words"]["words"] = words; + response = { body: JSON.stringify(obj) }; + } + } + } catch (err) { + $.logger.error(`知乎去除预置关键字广告出现异常:${err}`); + } + return response; +} + +/** + * 拦截官方账号推广消息 + * + * @param {*} + * @return {*} + */ +function removeSysMsgAds() { + let response = null; + try { + 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) { + $.logger.error(`知乎拦截官方账号推广消息出现异常:${err}`); + } + return response; +} + +/** + * 知乎热榜去广告 + * + * @param {*} + * @return {*} + */ +function removeHotListAds() { + let response = null; + try { + 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" + ); + }); + obj["data"] = data; + } + response = { body: JSON.stringify(obj) }; + } + } catch (err) { + $.logger.error(`去除知乎热榜广告出现异常:${err}`); + } + return response; +} + +/** + * 知乎旧版回答中的评论黑名单增强 + * + * @param {*} + * @return {*} + */ +function removeCommentAds() { + let response = null; + try { + if (!!$.response.body) { + // 评论区去广告 + let obj = JSON.parse($.response.body); + if ($.data.read("zhihu_settings_blocked_users") != false) { + // 屏蔽黑名单用户 + let user_info = getUserInfo(); + 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 + ) { + replyUserName = comment.reply_to_author.member.name; + } + 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 { + $.notification.debug( + `屏蔽“${commentUserName}”回复黑名单用户“${replyUserName}”的子评论。` + ); + } + // 减少主评论页面中的评论总数(仅适用于独立的主评论页面请求) + if (obj.common_counts) { + obj.common_counts -= 1; + } + // 减少子评论页面中的评论总数(仅适用于独立子评论页面请求) + if (obj.paging && obj.paging.totals) { + obj.paging.totals -= 1; + } + } else { + // 屏蔽子评论中的黑名单用户(仅适用于独立的主评论页面请求) + 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]) { + $.notification.debug( + `屏蔽黑名单用户“${childComment.author.member.name}”的主评论。` + ); + } else { + $.notification.debug( + `屏蔽“${childComment.author.member.name}”回复黑名单用户“${childComment.reply_to_author.member.name}”的子评论。` + ); + } + comment.child_comment_count -= 1; + } else { + newChildComments.push(childComment); + } + }); + comment.child_comments = newChildComments; + } + newData.push(comment); + } + }); + obj.data = newData; + } + response = { body: JSON.stringify(obj) }; + } + } catch (err) { + $.logger.error(`去除知乎评论广告出现异常:${err}`); + } + return response; +} + +/** + * 知乎V5版本评论去广告及黑名单增强 + * + * @param {*} + * @return {*} + */ +function removeCommentV5Ads() { + let response = null; + try { + if (!!$.response.body) { + let obj = JSON.parse($.response.body); + obj["ad_info"] = {}; + // 屏蔽黑名单用户 + if ($.data.read("zhihu_settings_blocked_users") != false) { + let user_info = getUserInfo(); + let customBlockedUsers = $.data.read(blockedUsersKey, "", user_info.id); + customBlockedUsers = !!customBlockedUsers ? customBlockedUsers : {}; + let newComments = []; + let blockCommentIdObj = {}; + obj.data.forEach((comment) => { + // 评论人昵称 + let commentUserName = comment.author.name; + // 回复哪个人的评论(仅适用于独立子评论页面请求) + let replyUserName = ""; + 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 && + $.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 { + $.notification.debug( + `屏蔽“${commentUserName}”回复黑名单用户“${replyUserName}”的子评论。` + ); + } + blockCommentIdObj[comment.id] = commentUserName; + // 主评论数量-1,仅适用于root_comment主评论页面请求 + if (obj.counts && obj.counts.total_counts) { + obj.counts.total_counts -= 1; + } + // 子评论数量-1,仅适用于child_comment子评论页面请求 + if (obj.paging && obj.paging.totals) { + obj.paging.totals -= 1; + } + if (obj.root && obj.root.child_comment_count) { + obj.root.child_comment_count -= 1; + } + } else { + if (comment.child_comments) { + let newChildComments = []; + comment.child_comments.forEach((childComment) => { + let childCommentUserName = childComment.author.name; + if ( + customBlockedUsers[childCommentUserName] || + blockCommentIdObj[childComment.reply_comment_id] + ) { + if (customBlockedUsers[childCommentUserName]) { + $.notification.debug( + `屏蔽黑名单用户“${childCommentUserName}”的子评论。` + ); + blockCommentIdObj[childComment.id] = childCommentUserName; + } else { + $.notification.debug( + `屏蔽“${childCommentUserName}”回复黑名单用户“${ + blockCommentIdObj[childComment.reply_comment_id] + }”的子评论。` + ); + } + comment.child_comment_count -= 1; + } else { + newChildComments.push(childComment); + } + }); + comment.child_comments = newChildComments; + } + newComments.push(comment); + } + }); + obj.data = newComments; + } + response = { body: JSON.stringify(obj) }; + } + } catch (err) { + $.logger.error(`去除知乎评论广告出现异常:${err}`); + } + return response; +} + +/** + * 回答列表去广告与黑名单增强 + * + * @param {*} + * @return {*} + */ +function removeQuestionsAds() { + let response = null; + try { + const userInfo = getUserInfo(); + let customBlockedUsers = $.data.read(blockedUsersKey, "", userInfo.id); + customBlockedUsers = !!customBlockedUsers ? customBlockedUsers : {}; + let obj = JSON.parse($.response.body); + $.logger.debug(`当前黑名单列表: ${JSON.stringify(customBlockedUsers)}`); + delete obj["ad_info"]; + delete obj["roundtable_info"]; + // 去除回答列表中的黑名单用户 + 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"]; + } else if ("target" in element) { + blackUserName = element["target"]["author"]["name"]; + } + } catch (ex) { + $.logger.error(`获取回答列表用户名出现异常:${err}`); + } + return blackUserName == "" || !customBlockedUsers[blackUserName]; + }); + if (obj.data.hasOwnProperty("data")) { + obj.data["data"] = data; + } else { + obj["data"] = data; + } + } + let body = JSON.stringify(obj); + $.logger.debug(`修改后的回答列表数据:${body}`); + response = { body: body }; + } catch (err) { + $.logger.error(`知乎回答列表去广告出现异常:${err}`); + } + return response; +} + +/** + * 关注列表去广告 + * + * @param {*} + * @return {*} + */ +function removeMomentsAds() { + let response = null; + try { + let obj = JSON.parse( + $.response.body.replace(/(\w+"+\s?):\s?(\d{15,})/g, '$1:"$2"') + ); + const user_info = getUserInfo(); + let customBlockedUsers = $.data.read(blockedUsersKey, "", user_info.id); + customBlockedUsers = !!customBlockedUsers ? customBlockedUsers : {}; + let data = []; + + 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] + ) { + $.notification.debug( + `屏蔽“${element.target.author.name}”转发黑名单用户“${element.target.origin_pin.author.name}”的想法。` + ); + } + + // 屏蔽关注页的“最新视频” + else if (!settings_moments_stream || element["type"] != "videos") { + data.push(element); + } + } + } + obj["data"] = data; + response = { body: JSON.stringify(obj) }; + } catch (err) { + $.logger.error(`知乎关注列表去广告出现异常:${err}`); + } + return response; +} + +/** + * 推荐去广告与黑名单增强 + * + * @param {*} + * @return {*} + */ +function removeRecommendAds() { + let response = null; + try { + 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 = + $.data.read("zhihu_settings_blocked_keywords") != false; + const settings_blocked_users = + $.data.read("zhihu_settings_blocked_users") != false; + const user_info = getUserInfo(); + + let keywords = $.data.read(keywordBlockKey, "", user_info.id); + keywords = settings_blocked_keywords && !!keywords ? keywords : []; + 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") || + element["extra"]["type"] === "Training"; + // 是否为流媒体 + 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 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 ($.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 {} + $.logger.debug( + `匹配关键字:\n${keywords[i]}\n标题:\n${elementTitle}\n内容:\n${elementContent}` + ); + $.notification.debug( + scriptName, + `关键字:${keywords[i]}`, + `${elementTitle}\n${elementContent}`, + actionUrl + ); + } + matchKeyword = true; + break; + } + } + } + // 是否为黑名单用户 + 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; + } catch { + isBlockedUser = false; + } + return !( + isAd || + removeStream || + matchKeyword || + isBlockedUser || + removeArticle + ); + }; + + // 修复number类型精度丢失 + 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) { + $.logger.error(`知乎推荐列表去广告出现异常:${err}`); + } + return response; +} + +/** + * 黑名单增强 - 浏览黑名单用户信息时自动加入脚本黑名单 + * + * @param {*} + * @return {*} + */ +function autoInsertBlackList() { + let response = null; + try { + 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 = $.data.read(blockedUsersKey, "", userInfo.id); + customBlockedUsers = + typeof customBlockedUsers === "object" && !!customBlockedUsers + ? customBlockedUsers + : {}; + if (!customBlockedUsers[obj.name]) { + $.logger.debug( + `当前需要加入黑名单的用户Id:${obj["id"]},用户名:${obj["name"]}` + ); + customBlockedUsers[obj["name"]] = obj["id"]; + $.data.write(blockedUsersKey, customBlockedUsers, userInfo.id); + $.logger.debug( + `${ + obj["name"] + }写入脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify( + customBlockedUsers + )}` + ); + $.notification.post(`已自动将用户“${obj["name"]}”写入脚本黑名单。`); + } + } + } catch (err) { + $.logger.error(`知乎去除MCN信息出现异常:${err}`); + } + return response; +} + +/** + * 处理登录用户信息 + * + * @param {*} + * @return {*} + */ +function processUserInfo() { + let response = null; + try { + 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, + }; + $.logger.debug( + `当前用户id:${obj["id"]},是否为VIP:${obj["vip_info"]["is_vip"]}` + ); + $.data.write(currentUserInfoKey, userInfo); + // 在知乎APP显示VIP,仅自己可见,打开后才能使用屏蔽关键词解锁 + 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", + }; + obj["vip_info"]["entrance"] = { + icon: { + url: "https://pic1.zhimg.com/v2-5b7012c8c22fd520f5677305e1e551bf.png", + night_mode_url: + "https://pic1.zhimg.com/v2-e51e3252d7a2cb016a70879defd5da0b.png", + }, + title: "我的盐选会员", + expires_day: "2033-12-24", + sub_title: null, + button_text: "你好,知乎!", + jump_url: "zhihu://vip/purchase", + button_jump_url: "zhihu://vip/purchase", + sub_title_new: null, + identity: "svip", + }; + obj["vip_info"]["entrance_new"] = { + left_button: { + title: "精选会员内容", + description: "为您严选好内容", + jump_url: "zhihu://market/home", + }, + right_button: { + title: "我的盐选会员", + description: "畅享 10w+ 优质内容", + jump_url: "zhihu://vip/my", + }, + }; + obj["vip_info"]["entrance_v2"] = { + title: "我的盐选会员", + sub_title: "畅享 10w+ 优质内容", + jump_url: "zhihu://vip/my", + button_text: "查看权益", + }; + response = { body: JSON.stringify(obj) }; + } + } else { + $.logger.warning( + `没有获取到本次登录用户信息,如未对功能造成影响,请忽略此日志。` + ); + } + } catch (err) { + $.logger.error(`知乎获取当前用户信息出现异常:${err}`); + } + return response; +} + +/** + * 回答内容优化 + * + * @param {*} + * @return {*} + */ +function modifyAnswer() { + let response = null; + try { + let html = $.response.body; + // 付费内容提醒 + 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), + }; + } + + // 营销推广提醒 + 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), + }; + } + + // 购物推广提醒 + else if (html.indexOf("mcn-link-card") >= 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), + }; + } + + // 彩蛋 + else if (Math.floor(Math.random() * 200) == 7) { + 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), + }; + } + } catch (err) { + $.logger.error(`知乎付费内容提醒出现异常:${err}`); + } + return response; +} + +/** + * @description: 黑名单管理 + * @param {*} + * @return {*} + */ +function manageBlackUser() { + const userInfo = getUserInfo(); + let defaultBlockedUsers = {}; + let customBlockedUsers = $.data.read(blockedUsersKey, "", userInfo.id); + customBlockedUsers = + typeof customBlockedUsers === "object" && !!customBlockedUsers + ? customBlockedUsers + : {}; + defaultAnswerBlockedUsers.forEach((element) => { + customBlockedUsers[element] = "00000000000000000000000000000000"; + defaultBlockedUsers[element] = "00000000000000000000000000000000"; + }); + $.logger.debug( + `当前用户id:${userInfo.id},脚本黑名单:${JSON.stringify( + customBlockedUsers + )}` + ); + // 获取黑名单 + if ($.request.method == "GET") { + try { + // 加载黑名单首页时,清空历史黑名单,仅保留脚本默认黑名单 + if ($.request.url.indexOf("offset") < 0) { + customBlockedUsers = defaultBlockedUsers; + $.logger.debug("脚本黑名单已清空,请滑动至黑名单末尾保证重新获取完成。"); + $.notification.post( + "脚本黑名单已清空,请滑动至黑名单末尾保证重新获取完成。" + ); + } + let obj = JSON.parse($.response.body); + if (!!obj["data"]) { + $.logger.debug(`本次滑动获取的黑名单信息:${JSON.stringify(obj["data"])}`); + obj["data"].forEach((element) => { + if (element["name"] != "[已重置]") { + customBlockedUsers[element["name"]] = element["id"]; + } + }); + $.data.write(blockedUsersKey, customBlockedUsers, userInfo.id); + if (obj["paging"]["is_end"] == true) { + $.notification.post( + `获取脚本黑名单结束,当前黑名单共${ + Object.keys(customBlockedUsers).length - + defaultAnswerBlockedUsers.length + }人。\n脚本内置黑名单${defaultAnswerBlockedUsers.length}人。` + ); + $.logger.debug(`脚本黑名单内容:${JSON.stringify(customBlockedUsers)}。`); + } + } else { + $.logger.warning(`获取黑名单失败,接口响应不合法:${$.response.body}`); + } + } catch (err) { + $.data.del(blockedUsersKey); + $.logger.error(`获取黑名单失败,异常信息:${err}`); + $.notification.post("获取黑名单失败,执行异常,已清空黑名单。"); + } + } + // 写入黑名单 + else if ($.request.method == "POST") { + try { + let obj = JSON.parse($.response.body); + if (obj.hasOwnProperty("name") && obj.hasOwnProperty("id")) { + $.logger.debug( + `当前需要加入黑名单的用户Id:${obj["id"]},用户名:${obj["name"]}` + ); + if (obj["id"]) { + customBlockedUsers[obj["name"]] = obj["id"]; + $.data.write(blockedUsersKey, customBlockedUsers, userInfo.id); + $.logger.debug( + `${ + obj["name"] + }写入脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify( + customBlockedUsers + )}` + ); + $.notification.post(`已将用户“${obj["name"]}”写入脚本黑名单。`); + } else { + $.logger.error(`${obj["name"]}写入脚本黑名单失败,没有获取到用户Id。`); + $.notification.post(`将用户“${obj["name"]}”写入脚本黑名单失败!`); + } + } else { + $.logger.warning(`写入黑名单失败,接口响应不合法:${$.response.body}`); + $.notification.post("写入脚本黑名单失败,接口返回不合法。"); + } + } catch (err) { + $.logger.error(`写入黑名单失败,异常信息:${err}`); + $.notification.post("写入脚本黑名单失败,执行异常,请查阅日志。"); + } + } + // 移出黑名单 + else if ($.request.method == "DELETE") { + try { + let obj = JSON.parse($.response.body); + if (obj.success) { + 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) { + $.logger.debug(`当前需要移出黑名单的用户Id:${user_id}`); + for (let username in customBlockedUsers) { + if (customBlockedUsers[username] == user_id) { + delete customBlockedUsers[username]; + $.data.write(blockedUsersKey, customBlockedUsers, userInfo.id); + $.logger.debug( + `${username}移出脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify( + customBlockedUsers + )}` + ); + $.notification.post(`已将用户“${username}”移出脚本黑名单!`); + break; + } + } + } else { + $.logger.error( + "将用户移出脚本黑名单失败!\n建议从设置中刷新黑名单数据。" + ); + $.notification.post( + `将用户移出脚本黑名单失败,没有获取到用户Id。\n建议从设置中刷新黑名单数据。` + ); + } + } else { + $.logger.warning(`移出黑名单失败,接口响应不合法:${$.response.body}`); + $.notification.post("移出脚本黑名单失败,接口返回不合法。"); + } + } catch (err) { + $.logger.error(`移出黑名单失败,异常信息:${err}`); + $.notification.post("移出脚本黑名单失败,执行异常,请查阅日志。"); + } + } +} + +/** + * @description: 获取用户信息 + * @param {*} + * @return {*} + */ +function getUserInfo() { + let defaultUserInfo = { id: "default", is_vip: false }; + try { + const userInfo = $.data.read(currentUserInfoKey); + if (typeof userInfo === "string") userInfo = JSON.parse(userInfo); + if (!!userInfo && userInfo.hasOwnProperty("id")) { + return userInfo; + } else { + return defaultUserInfo; + } + } catch (err) { + $.logger.error(`获取用户信息出现异常:${err}`); + return defaultUserInfo; + } +} + +/** + * @description: 知乎8.3.0移除推荐页顶部项 + * @param {*} + * @return {*} + */ +function removeFeedSections() { + let response = null; + try { + let obj = JSON.parse($.response.body); + obj.guess_like_sections = []; + obj.selected_sections = []; + obj.more_sections = []; + response = { body: JSON.stringify(obj) }; + } catch (err) { + $.logger.error(`知乎移除推荐页顶部项出现异常:${err}`); + } + return response; +} + + +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}} \ No newline at end of file