diff --git a/Rewrite/AdBlock/Zhihu.adblock b/Rewrite/AdBlock/Zhihu.adblock
index 9bcd2a4..78267ea 100644
--- a/Rewrite/AdBlock/Zhihu.adblock
+++ b/Rewrite/AdBlock/Zhihu.adblock
@@ -1,7 +1,5 @@
-
hostname = 118.89.204.198,103.41.167.237,2402:4e00:1200:ed00:0:9089:6dac:96b6,www.zhihu.com,api.zhihu.com,zhuanlan.zhihu.com,appcloud2.zhihu.com,m-cloud.zhihu.com,103.41.167.236,103.41.167.234,103.41.167.235,103.41.167.226
-# 拦截DNS解析
^https?:\/\/118\.89\.204\.198 url reject-dict
^https?:\/\/103\.41\.167\.237 url reject-dict
^https?:\/\/2402:4e00:1200:ed00:0:9089:6dac:96b6 url reject-200
@@ -49,56 +47,57 @@ hostname = 118.89.204.198,103.41.167.237,2402:4e00:1200:ed00:0:9089:6dac:96b6,ww
# 暂不清楚作用
^https?:\/\/api\.zhihu\.com\/commercial_api\/banners_v3\/app_topstory_banner url reject-dict
+^https?:\/\/api\.zhihu\.com\/ad-style-service\/request url reject
# 获取用户信息 - 隔离用户数据,开启本地会员等
-^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\/people\/ url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.js
# 关键词屏蔽 - 解锁本地的关键词屏蔽功能,需要开启本地VIP
-^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
+^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.min.js
# 优化软件配置 - 优化下发的配置文件来实现某些效果
-^https?:\/\/m-cloud\.zhihu\.com\/api\/cloud\/config\/all\? 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-analyze-echo-response https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js
+^https?:\/\/m-cloud\.zhihu\.com\/api\/cloud\/config\/all\? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.js
+^https?:\/\/appcloud2\.zhihu\.com\/v\d+\/config url script-analyze-echo-response https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.js
# 用户信息 - 修改用户盐值
-^https?:\/\/api\.zhihu\.com\/user-credit\/basis url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js
+^https?:\/\/api\.zhihu\.com\/user-credit\/basis url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.js
# 关注页 - 内容优化及屏蔽转发的黑名单用户想法
-^https?:\/\/api\.zhihu\.com\/moments_v3\? 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_v3\? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.js
# 推荐页 - 移除黑名单用户发布的文章、去除广告,及自定义一些屏蔽项目
-^https:\/\/api\.zhihu\.com\/topstory\/recommend 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\/recommend url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.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\/settings\/blocked_users url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.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\/(v4\/)?questions\/\d+ url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.js
# 回答信息流 - 移除黑名单用户的回答、去除广告
-^https?:\/\/api\.zhihu\.com\/next-data url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js
+^https?:\/\/api\.zhihu\.com\/next-data url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.js
# 回答页底部评论摘要 - 移除黑名单用户发表的评论
-^https?:\/\/www\.zhihu\.com\/api\/v4\/comment_v5\/answers\/\d+\/abstract_comment\? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js
+^https?:\/\/www\.zhihu\.com\/api\/v4\/comment_v5\/answers\/\d+\/abstract_comment\? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.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?:\/\/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.min.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\/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.min.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?:\/\/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.min.js
# 回答页 - 屏蔽下翻出现的黑名单用户的回答
-^https?:\/\/api\.zhihu\.com\/next\? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js
+^https?:\/\/api\.zhihu\.com\/next\? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.js
# 文章页 - 去除底部广告
-^https?:\/\/www\.zhihu\.com\/api\/v\d\/articles\/\d+\/recommendation\? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.js
+^https?:\/\/www\.zhihu\.com\/api\/v\d\/articles\/\d+\/recommendation\? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.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\/topstory\/hot-lists?(\?|\/) url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.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?:\/\/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.min.js
diff --git a/Rewrite/AdBlock/Zhihu.conf b/Rewrite/AdBlock/Zhihu.conf
index b40efb3..af8eb33 100644
--- a/Rewrite/AdBlock/Zhihu.conf
+++ b/Rewrite/AdBlock/Zhihu.conf
@@ -1,59 +1,106 @@
-# 脚本来自: 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
+hostname = 118.89.204.198,103.41.167.237,2402:4e00:1200:ed00:0:9089:6dac:96b6,www.zhihu.com,api.zhihu.com,zhuanlan.zhihu.com,appcloud2.zhihu.com,m-cloud.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?:\/\/118\.89\.204\.198 url reject-dict
+^https?:\/\/103\.41\.167\.237 url reject-dict
+^https?:\/\/2402:4e00:1200:ed00:0:9089:6dac:96b6 url reject-200
+
+# 屏蔽下发的配置,如皮肤等
+^https?:\/\/api\.zhihu\.com\/ab\/api\/v1\/products\/zhihu\/platforms\/ios\/config url reject
+
+# 屏蔽我的页面开通会员的卡片
+# ^https?:\/\/api\.zhihu\.com\/unlimited\/go\/my_card url reject
+
+# 拦截开屏广告
+^https?:\/\/api\.zhihu\.com\/commercial_api\/launch_v2\? url reject-dict
+^https?:\/\/api\.zhihu\.com\/commercial_api\/real_time_launch_v2\? 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
+
+# 去除底部标签页关注人角标
+^https?:\/\/api\.zhihu\.com\/moments\/tab_v2 url reject-dict
+
+# 去除消息通知角标
+^https?:\/\/api\.zhihu\.com\/(notifications\/v\d\/count) url reject-dict
+
+# 拦截回答下的卡片广告
+^https?:\/\/www\.zhihu\.com\/api\/v\d\/answers\/\d+\/recommendations url reject-dict
+
+# 拦截应用内弹窗
+^https?:\/\/api\.zhihu\.com\/me\/guides url reject-dict
+
+# 去除关注页最常访问
+^https?:\/\/api\.zhihu\.com\/moments\/recent url reject-dict
+
+# 拦截推荐页顶部广告
+^https?:\/\/api\.zhihu\.com\/api\/v4\/ecom_data\/config url reject-dict
+
+# 底栏加号的广告
+^https?:\/\/api\.zhihu\.com\/content-distribution-core\/bubble\/common\/settings url reject-dict
+
+# 推荐页搜索栏左侧图标
+^https?:\/\/api\.zhihu\.com\/feed\/render\/revisit\/current_reading url reject-dict
+
+# 疑似推荐页内容更新红点
+^https?:\/\/api\.zhihu\.com\/feed\/render\/revisit\/tag_config url reject-dict
+
+# 暂不清楚作用
+^https?:\/\/api\.zhihu\.com\/commercial_api\/banners_v3\/app_topstory_banner url reject-dict
+^https?:\/\/api\.zhihu\.com\/ad-style-service\/request url reject
+
+# 获取用户信息 - 隔离用户数据,开启本地会员等
+^https?:\/\/api\.zhihu\.com\/people\/ url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.js
+
+# 关键词屏蔽 - 解锁本地的关键词屏蔽功能,需要开启本地VIP
+^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.min.js
+
+# 优化软件配置 - 优化下发的配置文件来实现某些效果
+^https?:\/\/m-cloud\.zhihu\.com\/api\/cloud\/config\/all\? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.js
+^https?:\/\/appcloud2\.zhihu\.com\/v\d+\/config url script-analyze-echo-response https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.js
+
+# 用户信息 - 修改用户盐值
+^https?:\/\/api\.zhihu\.com\/user-credit\/basis url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.js
+
+# 关注页 - 内容优化及屏蔽转发的黑名单用户想法
+^https?:\/\/api\.zhihu\.com\/moments_v3\? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.js
+
+# 推荐页 - 移除黑名单用户发布的文章、去除广告,及自定义一些屏蔽项目
+^https:\/\/api\.zhihu\.com\/topstory\/recommend url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.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.min.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.min.js
+
+# 回答信息流 - 移除黑名单用户的回答、去除广告
+^https?:\/\/api\.zhihu\.com\/next-data url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.js
+
+# 回答页底部评论摘要 - 移除黑名单用户发表的评论
+^https?:\/\/www\.zhihu\.com\/api\/v4\/comment_v5\/answers\/\d+\/abstract_comment\? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.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.min.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.min.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.min.js
+
+# 回答页 - 屏蔽下翻出现的黑名单用户的回答
+^https?:\/\/api\.zhihu\.com\/next\? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.js
+
+# 文章页 - 去除底部广告
+^https?:\/\/www\.zhihu\.com\/api\/v\d\/articles\/\d+\/recommendation\? url script-response-body https://cdn.jsdelivr.net/gh/sve1r/Rules-For-Quantumult-X@develop/Scripts/AdBlock/Zhihu/Zhihu.min.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.min.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.min.js
diff --git a/Scripts/AdBlock/Zhihu/OpenAds.js b/Scripts/AdBlock/Zhihu/OpenAds.js
new file mode 100644
index 0000000..adf812d
--- /dev/null
+++ b/Scripts/AdBlock/Zhihu/OpenAds.js
@@ -0,0 +1,5 @@
+
+var body = $response.body
+ .replace(/img_play_duration\\":\d+/g, 'img_play_duration":0')
+ .replace(/launch_timeout\\":\d+/g, 'launch_timeout":0');
+$done({ body });
diff --git a/Scripts/AdBlock/Zhihu/Zhihu.js b/Scripts/AdBlock/Zhihu/Zhihu.js
index 16da55c..99e2868 100644
--- a/Scripts/AdBlock/Zhihu/Zhihu.js
+++ b/Scripts/AdBlock/Zhihu/Zhihu.js
@@ -3,130 +3,103 @@ const blockedUsersKey = "zhihu_blocked_users";
const currentUserInfoKey = "zhihu_current_userinfo";
const keywordBlockKey = "zhihu_keyword_block";
const blackAnswersIdKey = "zhihu_black_answers";
-const userCreditScore = "zhihu_credit_score";
-// 默认屏蔽推荐列表的用户,通常不是真实用户,无法通过加入黑名单屏蔽
+const userCreditScoreKey = "zhihu_credit_score";
+const zheyeServerKey = "zheye_server_url";
const defaultAnswerBlockedUsers = ["会员推荐", "盐选推荐"];
-const keywordMaxCount = 1000; // 允许设置的关键词数量
+const keywordMaxCount = 1e3;
const $ = MagicJS(scriptName, "INFO");
-
-/**
- * @description: 获取用户信息
- * @return {*}
- */
function getUserInfo() {
- let defaultUserInfo = { id: "default", is_vip: false };
+ let t = { id: "default", is_vip: false };
try {
- let userInfo = $.data.read(currentUserInfoKey);
- if (typeof userInfo === "string") userInfo = JSON.parse(userInfo);
- if (!!userInfo && userInfo.hasOwnProperty("id")) {
- return userInfo;
+ let e = $.data.read(currentUserInfoKey);
+ if (typeof e === "string") e = JSON.parse(e);
+ if (!!e && e.hasOwnProperty("id")) {
+ return e;
} else {
- return defaultUserInfo;
+ return t;
}
- } catch (err) {
- $.logger.error(`获取用户信息出现异常:${err}`);
- return defaultUserInfo;
+ } catch (e) {
+ $.logger.error(`获取用户信息出现异常:${e}`);
+ return t;
}
}
-
-/**
- * 优化软件配置
- * @return {*}
- */
function modifyAppConfig() {
- let response = null;
+ let t = null;
try {
if (!!$.response.body) {
- let obj = JSON.parse($.response.body);
- obj["config"]["homepage_feed_tab"]["tab_infos"] = obj["config"][
+ let e = JSON.parse($.response.body);
+ e["config"]["homepage_feed_tab"]["tab_infos"] = e["config"][
"homepage_feed_tab"
]["tab_infos"].filter((e) => {
- // 将活动标签设置为已过期
if (e["tab_type"] === "activity_tab") {
- e["end_time"] = (new Date() - 120000).toString().slice(0, 10);
+ e["end_time"] = (new Date() - 12e4).toString().slice(0, 10);
return true;
} else {
return false;
}
});
- obj["config"]["zvideo_max_number"] = 1;
- // 似乎是控制内部弹窗
- obj["config"]["is_show_followguide_alert"] = false;
- // 似乎是某个地方的标签,待定
- delete obj["config"]["hp_channel_tab"];
- // 灰色模式
- if (obj["config"]["zombie_conf"]) {
- obj["config"]["zombie_conf"]["zombieEnable"] = false;
+ e["config"]["zvideo_max_number"] = 1;
+ e["config"]["is_show_followguide_alert"] = false;
+ delete e["config"]["hp_channel_tab"];
+ if (e["config"]["zombie_conf"]) {
+ e["config"]["zombie_conf"]["zombieEnable"] = false;
}
- if (obj["config"]["gray_mode"]) {
- obj["config"]["gray_mode"]["enable"] = false;
- obj["config"]["gray_mode"]["start_time"] = "4092566400";
- obj["config"]["gray_mode"]["end_time"] = "4092566400";
+ if (e["config"]["gray_mode"]) {
+ e["config"]["gray_mode"]["enable"] = false;
+ e["config"]["gray_mode"]["start_time"] = "4092566400";
+ e["config"]["gray_mode"]["end_time"] = "4092566400";
}
- // 屏蔽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"] =
+ if (e["config"].hasOwnProperty("zhcnh_thread_sync")) {
+ $.logger.debug(JSON.stringify(e["config"]["zhcnh_thread_sync"]));
+ e["config"]["zhcnh_thread_sync"]["LocalDNSSetHostWhiteList"] = [];
+ e["config"]["zhcnh_thread_sync"]["isOpenLocalDNS"] = "0";
+ e["config"]["zhcnh_thread_sync"]["ZHBackUpIP_Switch_Open"] = "0";
+ e["config"]["zhcnh_thread_sync"]["dns_ip_detector_operation_lock"] =
"1";
- obj["config"]["zhcnh_thread_sync"][
+ e["config"]["zhcnh_thread_sync"][
"ZHHTTPSessionManager_setupZHHTTPHeaderField"
] = "1";
}
- response = { body: JSON.stringify(obj) };
+ t = { body: JSON.stringify(e) };
}
- } catch (err) {
- $.logger.error(`优化软件配置出现异常:${err}`);
+ } catch (e) {
+ $.logger.error(`优化软件配置出现异常:${e}`);
}
- return response;
+ return t;
}
-
-/**
- * 修改云端下发的配置
- * @return {*}
- */
function modifyMCloudConfig() {
- let response = null;
+ let t = null;
try {
if (!!$.response.body) {
- let obj = JSON.parse($.response.body);
- if (obj.data && obj.data["configs"]) {
- // 去除灰色主题
- obj.data["configs"].forEach((element) => {
- if (element["configKey"] === "feed_gray_theme") {
- element["configValue"].start_time = "1669824000";
- element["configValue"].end_time = "1669824001";
- element.status = false;
+ let e = JSON.parse($.response.body);
+ if (e.data && e.data["configs"]) {
+ e.data["configs"].forEach((e) => {
+ if (e["configKey"] === "feed_gray_theme") {
+ e["configValue"].start_time = "1669824000";
+ e["configValue"].end_time = "1669824001";
+ e.status = false;
}
});
}
- const body = JSON.stringify(obj);
- $.logger.debug(body);
- response = { body: body };
+ const r = JSON.stringify(e);
+ $.logger.debug(r);
+ t = { body: r };
}
- } catch (err) {
- $.logger.error(`优化软件配置出现异常:${err}`);
+ } catch (e) {
+ $.logger.error(`优化软件配置出现异常:${e}`);
}
- return response;
+ return t;
}
-
-/**
- * 屏蔽关键词解锁
- * @return {*}
- */
function unlockBlockedKeywords() {
- let response = null;
+ let i = null;
try {
- const userInfo = getUserInfo();
- // 获取屏蔽关键词列表
+ const s = getUserInfo();
if ($.request.method === "GET") {
- let keywords = $.data.read(keywordBlockKey, null, userInfo.id);
- if (!keywords) {
- keywords = [];
+ let e = $.data.read(keywordBlockKey, null, s.id);
+ if (!e) {
+ e = [];
}
- let headers = {
+ let t = {
"Cache-Control":
"no-cache, no-store, must-revalidate, private, max-age=0",
Connection: "keep-alive",
@@ -138,27 +111,23 @@ function unlockBlockedKeywords() {
"X-Cache-Lookup": "Cache Miss",
"x-cdn-provider": "tencent",
};
- let body = JSON.stringify({
+ let r = JSON.stringify({
success: true,
is_vip: true,
kw_min_length: 2,
kw_max_length: 100,
kw_max_count: keywordMaxCount,
- data: keywords,
+ data: e,
});
if ($.env.isQuanX) {
- response = { body: body, headers: headers, status: "HTTP/1.1 200 OK" };
+ i = { body: r, headers: t, status: "HTTP/1.1 200 OK" };
} else {
- response = { response: { body: body, headers: headers, status: 200 } };
+ i = { response: { body: r, headers: t, status: 200 } };
}
- $.logger.debug(`获取本地脚本屏蔽关键词:\n${keywords.join("、")}`);
- }
-
- // 添加屏蔽关键词
- else if ($.request.method === "POST") {
+ $.logger.debug(`获取本地脚本屏蔽关键词:\n${e.join("、")}`);
+ } else if ($.request.method === "POST") {
if (!!$.request.body) {
- // 构造 response headers
- let headers = {
+ let t = {
"Cache-Control":
"no-cache, no-store, must-revalidate, private, max-age=0",
Connection: "keep-alive",
@@ -170,73 +139,50 @@ function unlockBlockedKeywords() {
"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 r = decodeURIComponent($.request.body).match(/keyword=(.*)/)[1];
+ let n = $.data.read(keywordBlockKey, null, s.id);
+ if (!n) {
+ n = [];
}
- // 判断关键词是否存在
- let keywordExists = false;
- for (let i = 0; i < keywords.length; i++) {
- if (keyword === keywords[i]) {
- keywordExists = true;
+ let o = false;
+ for (let e = 0; e < n.length; e++) {
+ if (r === n[e]) {
+ o = true;
break;
}
}
- // 不存在添加,存在返回异常
- if (keywordExists === false) {
- keywords.push(keyword);
- $.data.write(keywordBlockKey, keywords, userInfo.id);
- let body = JSON.stringify({ success: true });
+ if (o === false) {
+ n.push(r);
+ $.data.write(keywordBlockKey, n, s.id);
+ let e = JSON.stringify({ success: true });
if ($.env.isQuanX) {
- response = {
- body: body,
- headers: headers,
- status: "HTTP/1.1 200 OK",
- };
+ i = { body: e, headers: t, status: "HTTP/1.1 200 OK" };
} else {
- response = {
- response: { body: body, headers: headers, status: 200 },
- };
+ i = { response: { body: e, headers: t, status: 200 } };
}
- $.logger.debug(`添加本地脚本屏蔽关键词“${keyword}”`);
+ $.logger.debug(`添加本地脚本屏蔽关键词“${r}”`);
} else {
- let body = JSON.stringify({
- error: {
- message: "关键词已存在",
- code: 100002,
- },
+ let e = JSON.stringify({
+ error: { message: "关键词已存在", code: 100002 },
});
if ($.env.isQuanX) {
- response = {
- body: body,
- headers: headers,
- status: "HTTP/1.1 400 Bad Request",
- };
+ i = { body: e, headers: t, status: "HTTP/1.1 400 Bad Request" };
} else {
- response = {
- response: { body: body, headers: headers, status: 400 },
- };
+ i = { response: { body: e, headers: t, 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 = [];
+ } else if ($.request.method === "DELETE") {
+ let t = decodeURIComponent($.request.url).match(/keyword=(.*)/)[1];
+ let e = $.data.read(keywordBlockKey, null, s.id);
+ if (!e) {
+ e = [];
}
- keywords = keywords.filter((e) => {
- return e !== keyword;
+ e = e.filter((e) => {
+ return e !== t;
});
- $.data.write(keywordBlockKey, keywords, userInfo.id);
- let headers = {
+ $.data.write(keywordBlockKey, e, s.id);
+ let r = {
"Cache-Control":
"no-cache, no-store, must-revalidate, private, max-age=0",
Connection: "keep-alive",
@@ -248,65 +194,58 @@ function unlockBlockedKeywords() {
"X-Cache-Lookup": "Cache Miss",
"x-cdn-provider": "tencent",
};
- let body = JSON.stringify({ success: true });
+ let n = JSON.stringify({ success: true });
if ($.env.isQuanX) {
- response = { body: body, headers: headers, status: "HTTP/1.1 200 OK" };
+ i = { body: n, headers: r, status: "HTTP/1.1 200 OK" };
} else {
- response = { response: { body: body, headers: headers, status: 200 } };
+ i = { response: { body: n, headers: r, status: 200 } };
}
- $.logger.debug(`删除本地脚本屏蔽关键词:“${keyword}”`);
+ $.logger.debug(`删除本地脚本屏蔽关键词:“${t}”`);
}
- } catch (err) {
- $.logger.debug(`关键词屏蔽操作出现异常:${err}`);
+ } catch (e) {
+ $.logger.debug(`关键词屏蔽操作出现异常:${e}`);
}
- return response;
+ return i;
}
-
-/**
- * 处理登录用户信息
- *
- * @return {*}
- */
function processUserInfo() {
- let response = null;
+ let t = null;
try {
- let obj = JSON.parse($.response.body);
+ let e = JSON.parse($.response.body);
$.data.write(blackAnswersIdKey, []);
$.logger.debug(`用户登录用户信息,接口响应:${$.response.body}`);
if (
- obj &&
- obj["id"] &&
- obj.hasOwnProperty("vip_info") &&
- obj["vip_info"].hasOwnProperty("is_vip")
+ e &&
+ e["id"] &&
+ e.hasOwnProperty("vip_info") &&
+ e["vip_info"].hasOwnProperty("is_vip")
) {
- const userInfo = {
- id: obj["id"],
- is_vip: obj["vip_info"]["is_vip"]
- ? obj["vip_info"]["is_vip"] !== undefined
+ const r = {
+ id: e["id"],
+ is_vip: e["vip_info"]["is_vip"]
+ ? e["vip_info"]["is_vip"] !== undefined
: false,
};
$.logger.debug(
- `当前用户id:${obj["id"]},是否为VIP:${obj["vip_info"]["is_vip"]}`
+ `当前用户id:${e["id"]},是否为VIP:${e["vip_info"]["is_vip"]}`
);
- $.data.write(currentUserInfoKey, userInfo);
- // 在APP显示VIP,仅自己可见,打开后才能使用屏蔽关键词解锁
+ $.data.write(currentUserInfoKey, r);
if (
$.data.read("zhihu_settings_fake_vip") !== false &&
- obj["vip_info"]["is_vip"] === false
+ e["vip_info"]["is_vip"] === false
) {
- obj["vip_info"]["is_vip"] = true;
- obj["vip_info"]["vip_type"] = 2;
- obj["vip_info"]["vip_icon"] = {
+ e["vip_info"]["is_vip"] = true;
+ e["vip_info"]["vip_type"] = 2;
+ e["vip_info"]["vip_icon"] = {
url: "https://picx.zhimg.com/v2-aa8a1823abfc46f14136f01d55224925.jpg?source=88ceefae",
night_mode_url:
"https://picx.zhimg.com/v2-aa8a1823abfc46f14136f01d55224925.jpg?source=88ceefae",
};
- obj["vip_info"]["vip_icon_v2"] = {
+ e["vip_info"]["vip_icon_v2"] = {
url: "https://picx.zhimg.com/v2-aa8a1823abfc46f14136f01d55224925.jpg?source=88ceefae",
night_mode_url:
"https://picx.zhimg.com/v2-aa8a1823abfc46f14136f01d55224925.jpg?source=88ceefae",
};
- obj["vip_info"]["entrance"] = {
+ e["vip_info"]["entrance"] = {
icon: {
url: "https://pic3.zhimg.com/v2-5b7012c8c22fd520f5677305e1e551bf.png",
night_mode_url:
@@ -321,7 +260,7 @@ function processUserInfo() {
sub_title_new: null,
identity: "super_svip",
};
- obj["vip_info"]["entrance_new"] = {
+ e["vip_info"]["entrance_new"] = {
left_button: {
title: "精选会员内容",
description: "为您严选好内容",
@@ -333,7 +272,7 @@ function processUserInfo() {
jump_url: "zhihu://vip/purchase",
},
};
- obj["vip_info"]["entrance_v2"] = {
+ e["vip_info"]["entrance_v2"] = {
title: "我的超级盐选会员",
sub_title: "畅享 5000W+ 优质内容",
jump_url: "zhihu://market/home",
@@ -343,46 +282,32 @@ function processUserInfo() {
card_jump_url: "zhihu://market/home",
};
$.logger.debug("设置用户为本地盐选会员");
- response = { body: JSON.stringify(obj) };
+ t = { body: JSON.stringify(e) };
}
} else {
$.logger.warning(
`没有获取到本次登录用户信息,如未对功能造成影响,请忽略此日志。`
);
}
- } catch (err) {
- $.logger.error(`获取当前用户信息出现异常:${err}`);
+ } catch (e) {
+ $.logger.error(`获取当前用户信息出现异常:${e}`);
}
- return response;
+ return t;
}
-
-/**
- * @description: 黑名单管理
- * @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";
+ const r = getUserInfo();
+ let t = {};
+ let n = $.data.read(blockedUsersKey, "", r.id);
+ n = typeof n === "object" && !!n ? n : {};
+ defaultAnswerBlockedUsers.forEach((e) => {
+ n[e] = "00000000000000000000000000000000";
+ t[e] = "00000000000000000000000000000000";
});
- $.logger.debug(
- `当前用户id:${userInfo.id},脚本黑名单:${JSON.stringify(
- customBlockedUsers
- )}`
- );
- // 获取黑名单
+ $.logger.debug(`当前用户id:${r.id},脚本黑名单:${JSON.stringify(n)}`);
if ($.request.method === "GET") {
try {
- // 加载黑名单首页时,清空历史黑名单,仅保留脚本默认黑名单
if ($.request.url.indexOf("offset") < 0) {
- customBlockedUsers = defaultBlockedUsers;
+ n = t;
$.logger.debug(
"脚本黑名单已清空,请滑动至黑名单末尾保证重新获取完成。"
);
@@ -390,91 +315,80 @@ function manageBlackUser() {
"开始同步黑名单数据,请滑动至黑名单末尾,直至弹出“同步成功”的通知。"
);
}
- let obj = JSON.parse($.response.body);
- if (!!obj["data"]) {
+ let e = JSON.parse($.response.body);
+ if (!!e["data"]) {
$.logger.debug(
- `本次滑动获取的黑名单信息:${JSON.stringify(obj["data"])}`
+ `本次滑动获取的黑名单信息:${JSON.stringify(e["data"])}`
);
- obj["data"].forEach((element) => {
- if (element["name"] !== "[已重置]") {
- customBlockedUsers[element["name"]] = element["id"];
+ e["data"].forEach((e) => {
+ if (e["name"] !== "[已重置]") {
+ n[e["name"]] = e["id"];
}
});
- $.data.write(blockedUsersKey, customBlockedUsers, userInfo.id);
- if (obj["paging"]["is_end"] === true) {
+ $.data.write(blockedUsersKey, n, r.id);
+ if (e["paging"]["is_end"] === true) {
$.notification.post(
`同步黑名单数据成功!当前黑名单共${
- Object.keys(customBlockedUsers).length -
- defaultAnswerBlockedUsers.length
+ Object.keys(n).length - defaultAnswerBlockedUsers.length
}人。\n脚本内置黑名单${defaultAnswerBlockedUsers.length}人。`
);
- $.logger.debug(
- `脚本黑名单内容:${JSON.stringify(customBlockedUsers)}。`
- );
+ $.logger.debug(`脚本黑名单内容:${JSON.stringify(n)}。`);
}
} else {
$.logger.warning(`获取黑名单失败,接口响应不合法:${$.response.body}`);
}
- } catch (err) {
+ } catch (e) {
$.data.del(blockedUsersKey);
- $.logger.error(`获取黑名单失败,异常信息:${err}`);
+ $.logger.error(`获取黑名单失败,异常信息:${e}`);
$.notification.post("获取黑名单失败,执行异常,已清空黑名单。");
}
- }
- // 写入黑名单
- else if ($.request.method === "POST") {
+ } else if ($.request.method === "POST") {
try {
- let obj = JSON.parse($.response.body);
- if (obj.hasOwnProperty("name") && obj.hasOwnProperty("id")) {
+ let e = JSON.parse($.response.body);
+ if (e.hasOwnProperty("name") && e.hasOwnProperty("id")) {
$.logger.debug(
- `当前需要加入黑名单的用户Id:${obj["id"]},用户名:${obj["name"]}`
+ `当前需要加入黑名单的用户Id:${e["id"]},用户名:${e["name"]}`
);
- if (obj["id"]) {
- customBlockedUsers[obj["name"]] = obj["id"];
- $.data.write(blockedUsersKey, customBlockedUsers, userInfo.id);
+ if (e["id"]) {
+ n[e["name"]] = e["id"];
+ $.data.write(blockedUsersKey, n, r.id);
$.logger.debug(
`${
- obj["name"]
- }写入脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify(
- customBlockedUsers
- )}`
+ e["name"]
+ }写入脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify(n)}`
);
- $.notification.post(`已将用户“${obj["name"]}”写入脚本黑名单。`);
+ $.notification.post(`已将用户“${e["name"]}”写入脚本黑名单。`);
} else {
- $.logger.error(
- `${obj["name"]}写入脚本黑名单失败,没有获取到用户Id。`
- );
- $.notification.post(`将用户“${obj["name"]}”写入脚本黑名单失败!`);
+ $.logger.error(`${e["name"]}写入脚本黑名单失败,没有获取到用户Id。`);
+ $.notification.post(`将用户“${e["name"]}”写入脚本黑名单失败!`);
}
} else {
$.logger.warning(`写入黑名单失败,接口响应不合法:${$.response.body}`);
$.notification.post("写入脚本黑名单失败,接口返回不合法。");
}
- } catch (err) {
- $.logger.error(`写入黑名单失败,异常信息:${err}`);
+ } catch (e) {
+ $.logger.error(`写入黑名单失败,异常信息:${e}`);
$.notification.post("写入脚本黑名单失败,执行异常,请查阅日志。");
}
- }
- // 移出黑名单
- else if ($.request.method === "DELETE") {
+ } else if ($.request.method === "DELETE") {
try {
- let obj = JSON.parse($.response.body);
- if (obj.success) {
- let user_id = $.request.url.match(
+ let e = JSON.parse($.response.body);
+ if (e.success) {
+ let t = $.request.url.match(
/^https?:\/\/api\.zhihu\.com\/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);
+ if (t) {
+ $.logger.debug(`当前需要移出黑名单的用户Id:${t}`);
+ for (let e in n) {
+ if (n[e] === t) {
+ delete n[e];
+ $.data.write(blockedUsersKey, n, r.id);
$.logger.debug(
- `${username}移出脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify(
- customBlockedUsers
+ `${e}移出脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify(
+ n
)}`
);
- $.notification.post(`已将用户“${username}”移出脚本黑名单!`);
+ $.notification.post(`已将用户“${e}”移出脚本黑名单!`);
break;
}
}
@@ -490,855 +404,747 @@ function manageBlackUser() {
$.logger.warning(`移出黑名单失败,接口响应不合法:${$.response.body}`);
$.notification.post("移出脚本黑名单失败,接口返回不合法。");
}
- } catch (err) {
- $.logger.error(`移出黑名单失败,异常信息:${err}`);
+ } catch (e) {
+ $.logger.error(`移出黑名单失败,异常信息:${e}`);
$.notification.post("移出脚本黑名单失败,执行异常,请查阅日志。");
}
}
}
-
-/**
- * 黑名单增强 - 浏览黑名单用户信息时自动加入脚本黑名单
- * @return {*}
- */
function autoInsertBlackList() {
- let response = null;
+ let e = 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]) {
+ let t = JSON.parse($.response.body);
+ delete t["mcn_user_info"];
+ e = { body: JSON.stringify(t) };
+ if (t.name && t.id && t["is_blocking"] === true) {
+ const r = getUserInfo();
+ let e = $.data.read(blockedUsersKey, "", r.id);
+ e = typeof e === "object" && !!e ? e : {};
+ if (!e[t.name]) {
$.logger.debug(
- `当前需要加入黑名单的用户Id:${obj["id"]},用户名:${obj["name"]}`
+ `当前需要加入黑名单的用户Id:${t["id"]},用户名:${t["name"]}`
);
- customBlockedUsers[obj["name"]] = obj["id"];
- $.data.write(blockedUsersKey, customBlockedUsers, userInfo.id);
+ e[t["name"]] = t["id"];
+ $.data.write(blockedUsersKey, e, r.id);
$.logger.debug(
- `${
- obj["name"]
- }写入脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify(
- customBlockedUsers
+ `${t["name"]}写入脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify(
+ e
)}`
);
- $.notification.post(`已自动将用户“${obj["name"]}”写入脚本黑名单。`);
+ $.notification.post(`已自动将用户“${t["name"]}”写入脚本黑名单。`);
}
}
- } catch (err) {
- $.logger.error(`去除MCN信息出现异常:${err}`);
+ } catch (e) {
+ $.logger.error(`去除MCN信息出现异常:${e}`);
}
- return response;
+ return e;
}
-
-/**
- * 关注列表去广告
- *
- * @return {*}
- */
function removeMoments() {
- let response = null;
+ let r = null;
try {
- let obj = JSON.parse(
+ let e = 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_remove_stream = $.data.read(
- "zhihu_settings_moments_stream",
- false
- );
- const settings_remove_recommend = $.data.read(
- "zhihu_settings_moments_recommend",
- false
- );
- const settings_remove_activity = $.data.read(
- "zhihu_settings_moments_activity",
- false
- );
- const settings_blocked_users = $.data.read(
- "zhihu_settings_blocked_users",
- false
- );
-
- data = obj.data.filter((item) => {
- // 转发的想法是否含有黑名单用户
- const isBlackUserPin =
- settings_blocked_users &&
- item.target &&
- item.target["origin_pin"] &&
- item.target["origin_pin"].author &&
- typeof customBlockedUsers[item.target["origin_pin"].author.name] !=
- "undefined";
- // 是否为流媒体
- const isStream =
- settings_remove_stream && item["target_type"] === "zvideo";
- // 是否为推荐关注用户
- const isRecommend =
- settings_remove_recommend && item.type === "recommend_user_card_list";
- // 是否为关注的问题有新动态
- const isActivity =
- settings_remove_activity && item.type === "message_activity_card";
- return !(isBlackUserPin || isStream || isRecommend || isActivity);
+ const n = getUserInfo();
+ let i = $.data.read(blockedUsersKey, "", n.id);
+ i = !!i ? i : {};
+ let t;
+ const s = $.data.read("zhihu_settings_moments_stream", false);
+ const a = $.data.read("zhihu_settings_moments_recommend", false);
+ const l = $.data.read("zhihu_settings_moments_activity", false);
+ const c = $.data.read("zhihu_settings_blocked_users", false);
+ t = e.data.filter((e) => {
+ const t =
+ c &&
+ e.target &&
+ e.target["origin_pin"] &&
+ e.target["origin_pin"].author &&
+ typeof i[e.target["origin_pin"].author.name] != "undefined";
+ const r = s && e["target_type"] === "zvideo";
+ const n = a && e.type === "recommend_user_card_list";
+ const o = l && e.type === "message_activity_card";
+ return !(t || r || n || o);
});
- obj["data"] = data;
- response = { body: JSON.stringify(obj) };
- } catch (err) {
- $.logger.error(`关注列表去广告出现异常:${err}`);
+ e["data"] = t;
+ r = { body: JSON.stringify(e) };
+ } catch (e) {
+ $.logger.error(`关注列表去广告出现异常:${e}`);
}
- return response;
+ return r;
}
-
-/**
- * 推荐去广告与黑名单增强
- *
- * @return {*}
- */
-function removeRecommend() {
- let response = null;
+function _setRecommendTag(e, t, r = "GBK02A") {
+ if (!e["common_card"]["footline"]) {
+ e["common_card"]["footline"] = { elements: [] };
+ }
+ e["common_card"]["footline"]["elements"].unshift({
+ tag: { text: t, color: r, type: "MASK_ROUNDED_RECTANGLE" },
+ });
+}
+async function _checkPaidContentByCloud(e, n) {
+ const t = $.data.read(zheyeServerKey);
+ if (!t) {
+ $.notification.post(
+ "未设置服务端地址,无法进行付费/推广内容探测。\n请配置服务端地址,或使用本地探测。"
+ );
+ } else {
+ $.logger.debug(`向云端请求以下链接\n${e.join("\n")}`);
+ const r = `${t}/api/v1/answer/links`;
+ $.logger.debug(`服务端地址\n${r}`);
+ await $.http
+ .post({
+ url: r,
+ headers: { "Content-Type": "application/json" },
+ body: e,
+ })
+ .then((r) => {
+ $.logger.debug(
+ `云端探测结果<${typeof r.body}>\n${JSON.stringify(r.body)}`
+ );
+ for (let t = 0; t < r.body.length; t++) {
+ try {
+ let e = r.body[t];
+ if (e !== "") {
+ _setRecommendTag(n[t], e, "GBK02A");
+ }
+ } catch (e) {
+ $.logger.error(e);
+ }
+ }
+ })
+ .catch((e) => {
+ $.logger.error(`云端请求出现异常\n${JSON.stringify(e)}`);
+ });
+ }
+}
+async function _checkPaidContentByLocal(n, o) {
+ $.logger.debug(`将在本地请求以下链接\n${n.join("\n")}`);
+ let t = [];
+ function r(t) {
+ return new Promise((r) => {
+ const e = n[t];
+ if (
+ !e ||
+ e === "" ||
+ !e.startsWith("https://www.zhihu.com/appview/v2/answer")
+ ) {
+ r("");
+ } else {
+ $.http
+ .get({ url: n[t], timeout: 1e3 })
+ .then((e) => {
+ const t = e.body;
+ if (
+ (t.indexOf("查看完整内容") >= 0 ||
+ t.indexOf("查看全部章节") >= 0) &&
+ t.indexOf("paid") >= 0
+ ) {
+ r("付费内容");
+ } else if (
+ t.indexOf("ad-link-card") >= 0 ||
+ t.indexOf("xg.zhihu.com") >= 0 ||
+ t.indexOf("营销平台") >= 0
+ ) {
+ r("营销推广");
+ } else if (t.indexOf("mcn-link-card") >= 0) {
+ r("购物推广");
+ } else {
+ r("");
+ }
+ })
+ .catch((e) => {
+ $.logger.error(`本地请求出现异常\n${JSON.stringify(e)}`);
+ r("");
+ });
+ }
+ });
+ }
+ for (let e = 0; e < n.length; e++) {
+ t.push(r(e));
+ }
+ await Promise.all(t).then((r) => {
+ $.logger.debug(`本地探测结果<${r.length}>\n${JSON.stringify(r)}`);
+ for (let t = 0; t < r.length; t++) {
+ try {
+ let e = r[t];
+ if (e !== "") {
+ _setRecommendTag(o[t], e, "GBK02A");
+ }
+ } catch (e) {
+ $.logger.error(e);
+ }
+ }
+ });
+}
+async function removeRecommend() {
+ let t = null;
try {
- // 移除推荐列表中的想法
- const settings_remove_pin = $.data.read(
- "zhihu_settings_recommend_pin",
- false
- );
- // 移除推荐列表的流媒体
- const settings_recommend_stream = $.data.read(
- "zhihu_settings_recommend_stream",
- false
- );
- // 移除推荐列表的文章
- const settings_remove_article = $.data.read(
- "zhihu_settings_remove_article",
- false
- );
- // 屏蔽黑名单用户
- const settings_blocked_users = $.data.read(
- "zhihu_settings_blocked_users",
- false
- );
- // 屏蔽关键词内容
- const settings_blocked_keywords = $.data.read(
- "zhihu_settings_blocked_keywords",
- true
- );
- // 获取用户信息
- 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 newData = (element) => {
- const elementStr = JSON.stringify(element);
- // 是否为广告
- const isAd =
- element["card_type"] === "slot_event_card" ||
- element["card_type"] === "slot_video_event_card" ||
- element.hasOwnProperty("ad") ||
- // 非常恶心伪装成普通内容的广告
- (element["brief"] && element["brief"].indexOf("slot_card") >= 0) ||
- // 训练营
- (element["extra"] && element["extra"]["type"] === "Training");
- // 是否为流媒体
- const isStream =
- isAd !== true &&
- elementStr.search(
- /"(type|style)+"\s?:\s?"(drama|zvideo|Video|BIG_IMAGE)+"/i
- ) >= 0;
- const removeStream = isStream && settings_recommend_stream;
- // 是否为想法
- const isPin =
- isStream !== true &&
- elementStr.search(/"(type|style)+"\s?:\s?"pin"/i) >= 0;
- const removePin = isPin && settings_remove_pin;
- // 是否为文章
- const isArticle =
- elementStr.search(/"(type|style)+"\s?:\s?"article"/i) >= 0;
- const 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) {
+ const g = $.data.read("zhihu_settings_recommend_pin", false);
+ const p = $.data.read("zhihu_settings_recommend_stream", false);
+ const h = $.data.read("zhihu_settings_remove_article", false);
+ const y = $.data.read("zhihu_settings_blocked_users", false);
+ const m = $.data.read("zhihu_settings_blocked_keywords", true);
+ const r = $.data.read("zhihu_settings_check_paid_content", false);
+ const o = $.data.read("zhihu_settings_request_content", "local");
+ const i = getUserInfo();
+ let u = $.data.read(keywordBlockKey, "", i.id);
+ u = m && !!u ? u : [];
+ let f = $.data.read(blockedUsersKey, "", i.id);
+ f = y && !!f ? f : {};
+ const s = (o) => {
+ const e = JSON.stringify(o);
+ const t =
+ o["card_type"] === "slot_event_card" ||
+ o["card_type"] === "slot_video_event_card" ||
+ o.hasOwnProperty("ad") ||
+ (o["brief"] && o["brief"].indexOf("slot_card") >= 0) ||
+ (o["extra"] && o["extra"]["type"] === "Training");
+ const r =
+ t !== true &&
+ e.search(/"(type|style)+"\s?:\s?"(drama|zvideo|Video|BIG_IMAGE)+"/i) >=
+ 0;
+ const n = r && p;
+ const i = r !== true && e.search(/"(type|style)+"\s?:\s?"pin"/i) >= 0;
+ const s = i && g;
+ const a = e.search(/"(type|style)+"\s?:\s?"article"/i) >= 0;
+ const l = a && h;
+ let c = false;
+ if (r !== true && m) {
+ for (let n = 0; n < u.length; n++) {
+ if (e.search(u[n]) >= 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 = "";
+ let e = o["common_card"]["feed_content"]["title"]["panel_text"];
+ let t = o["common_card"]["feed_content"]["content"]["panel_text"];
+ let r = "";
try {
- actionUrl =
- element["common_card"]["feed_content"]["title"]["action"][
+ r =
+ o["common_card"]["feed_content"]["title"]["action"][
"intent_url"
];
} catch {}
$.logger.debug(
- `匹配关键字:\n${keywords[i]}\n标题:\n${elementTitle}\n内容:\n${elementContent}`
+ `匹配关键字:\n${u[n]}\n标题:\n${e}\n内容:\n${t}`
);
$.notification.debug(
scriptName,
- `关键字:${keywords[i]}`,
- `${elementTitle}\n${elementContent}`,
- actionUrl
+ `关键字:${u[n]}`,
+ `${e}\n${t}`,
+ r
);
}
- matchKeyword = true;
+ c = true;
break;
}
}
}
- // 是否为黑名单用户
- let isBlockedUser;
+ let d;
try {
- isBlockedUser =
- matchKeyword !== true &&
- settings_blocked_users &&
- customBlockedUsers &&
- element["common_card"]["feed_content"]["source_line"]["elements"][1][
+ d =
+ c !== true &&
+ y &&
+ f &&
+ o["common_card"]["feed_content"]["source_line"]["elements"][1][
"text"
- ]["panel_text"] in customBlockedUsers;
+ ]["panel_text"] in f;
} catch {
- isBlockedUser = false;
+ d = false;
}
- return !(
- isAd ||
- removePin ||
- removeArticle ||
- removeStream ||
- matchKeyword ||
- isBlockedUser
- );
+ return !(t || s || l || n || c || d);
};
-
- // 修复number类型精度丢失
- let obj = JSON.parse(
+ let e = JSON.parse(
$.response.body.replace(/(\w+"+\s?):\s?(\d{15,})/g, '$1:"$2"')
);
-
- if (obj["data"].length > 0 && newData.length === 0) {
- $.notification.post("所有推荐内容都已被过滤,建议调整脚本过滤配置。");
- }
- obj["data"] = obj["data"].filter(newData);
- response = { body: JSON.stringify(obj) };
- } catch (err) {
- $.logger.error(`推荐列表去广告出现异常:${err}`);
- }
- return response;
-}
-
-/**
- * 回答列表去广告与黑名单增强
- *
- * @return {*}
- */
-function removeQuestions() {
- let response = null;
- try {
- const userInfo = getUserInfo();
- let customBlockedUsers = $.data.read(blockedUsersKey, "", userInfo.id);
- customBlockedUsers = !!customBlockedUsers ? customBlockedUsers : {};
- let obj = JSON.parse($.response.body);
- const settingsBlockedUsers = $.data.read(
- "zhihu_settings_blocked_users",
- false
- );
- $.logger.debug(`当前黑名单列表: ${JSON.stringify(customBlockedUsers)}`);
- // 黑名单用户的回答Id
- let blackUserAnswersId = $.data.read(blackAnswersIdKey, []);
- // 去除广告
- delete obj["ad_info"];
- // 去除回答列表中的黑名单用户
- if (obj["data"]) {
- let newData = [];
- for (let element of obj.data) {
- let blackUserName = "";
- const answerId = element.target.id.toString();
- try {
- if ("target" in element) {
- blackUserName = element["target"]["author"]["name"];
+ let n = e["data"].filter(s);
+ if (r === true) {
+ let r = [];
+ for (let t = 0; t < n.length; t++) {
+ if (n[t]) {
+ try {
+ let e =
+ n[t]["common_card"]["feed_content"]["title"]["action"][
+ "intent_url"
+ ];
+ e = e.replace(
+ /^https:\/\/zhihu\.com\/question\/\d+\/answer\//,
+ "https://www.zhihu.com/appview/v2/answer/"
+ );
+ r.push(e);
+ } catch {
+ r.push("");
}
- } catch (ex) {
- $.logger.error(`获取回答列表用户名出现异常:${ex}`);
- }
- const isBlackUser =
- typeof customBlockedUsers[blackUserName] != "undefined";
- const removeBlackUserAnswer = settingsBlockedUsers && isBlackUser;
- // 显示仅作者自己可见的回答,允许复制
- if ("target" in element) {
- element["target"]["visible_only_to_author"] = false;
- element["target"]["is_visible"] = true;
- element["target"]["is_copyable"] = true;
- }
- if (!removeBlackUserAnswer) {
- newData.push(element);
- } else if (
- removeBlackUserAnswer === true &&
- blackUserAnswersId.includes(answerId) === false
- ) {
- blackUserAnswersId.push(answerId);
- $.notification.debug(
- `记录黑名单用户${blackUserName}的回答Id:${answerId}`
- );
}
}
- obj.data = newData;
+ if (r.length > 0 && o === "cloud") {
+ await _checkPaidContentByCloud(r, n);
+ } else if (r.length > 0 && o === "local") {
+ await _checkPaidContentByLocal(r, n);
+ }
}
- $.data.write(blackAnswersIdKey, blackUserAnswersId);
- const body = JSON.stringify(obj);
- $.logger.debug(`修改后的回答列表数据:${body}`);
- response = { body: body };
- } catch (err) {
- $.logger.error(`回答列表去广告出现异常:${err}`);
+ e["data"] = n;
+ t = { body: JSON.stringify(e) };
+ } catch (e) {
+ $.logger.error(`推荐列表去广告出现异常:${e}`);
}
- return response;
+ return t;
}
-
-/**
- * 回答内容优化
- *
- * @return {*}
- */
-function modifyAnswer() {
- let response = null;
+function removeQuestions() {
+ let t = null;
try {
- let html = $.response.body;
- let insertText = "";
-
- // 付费内容提醒
+ const r = getUserInfo();
+ let n = $.data.read(blockedUsersKey, "", r.id);
+ n = !!n ? n : {};
+ let e = JSON.parse($.response.body);
+ const i = $.data.read("zhihu_settings_blocked_users", false);
+ $.logger.debug(`当前黑名单列表: ${JSON.stringify(n)}`);
+ let o = $.data.read(blackAnswersIdKey, []);
+ delete e["ad_info"];
+ if (e["data"]) {
+ let r = [];
+ for (let t of e.data) {
+ let e = "";
+ const a = t.target.id.toString();
+ try {
+ if ("target" in t) {
+ e = t["target"]["author"]["name"];
+ }
+ } catch (e) {
+ $.logger.error(`获取回答列表用户名出现异常:${e}`);
+ }
+ const l = typeof n[e] != "undefined";
+ const c = i && l;
+ if ("target" in t) {
+ t["target"]["visible_only_to_author"] = false;
+ t["target"]["is_visible"] = true;
+ t["target"]["is_copyable"] = true;
+ }
+ if (!c) {
+ r.push(t);
+ } else if (c === true && o.includes(a) === false) {
+ o.push(a);
+ $.notification.debug(`记录黑名单用户${e}的回答Id:${a}`);
+ }
+ }
+ e.data = r;
+ }
+ $.data.write(blackAnswersIdKey, o);
+ const s = JSON.stringify(e);
+ $.logger.debug(`修改后的回答列表数据:${s}`);
+ t = { body: s };
+ } catch (e) {
+ $.logger.error(`回答列表去广告出现异常:${e}`);
+ }
+ return t;
+}
+function modifyAnswer() {
+ let r = null;
+ try {
+ let e = $.response.body;
+ let t = "";
if (
- (html.indexOf("查看完整内容") >= 0 ||
- html.indexOf("查看全部章节") >= 0) &&
- html.indexOf("paid") >= 0
+ (e.indexOf("查看完整内容") >= 0 || e.indexOf("查看全部章节") >= 0) &&
+ e.indexOf("paid") >= 0
) {
- insertText =
+ t =
'';
- }
-
- // 营销推广提醒
- else if (
- html.indexOf("ad-link-card") >= 0 ||
- html.indexOf("xg.zhihu.com") >= 0 ||
- html.indexOf("营销平台") >= 0
+ } else if (
+ e.indexOf("ad-link-card") >= 0 ||
+ e.indexOf("xg.zhihu.com") >= 0 ||
+ e.indexOf("营销平台") >= 0
) {
- insertText =
+ t =
'';
- }
-
- // 购物推广提醒
- else if (html.indexOf("mcn-link-card") >= 0) {
- insertText =
+ } else if (e.indexOf("mcn-link-card") >= 0) {
+ t =
'';
- }
-
- // 彩蛋
- else if (Math.floor(Math.random() * 200) === 7) {
- insertText =
+ } else if (Math.floor(Math.random() * 200) === 7) {
+ t =
'';
}
-
- if (insertText !== "") {
- const matchStr = html.match(/(richText[^<]*>)(.)/)[1];
- const start = html.lastIndexOf(matchStr) + matchStr.length;
- response = {
- body: html.slice(0, start) + insertText + html.slice(start),
- };
+ if (t !== "") {
+ const n = e.match(/(richText[^<]*>)(.)/)[1];
+ const o = e.lastIndexOf(n) + n.length;
+ r = { body: e.slice(0, o) + t + e.slice(o) };
}
- } catch (err) {
- $.logger.error(`付费内容提醒出现异常:${err}`);
+ } catch (e) {
+ $.logger.error(`付费内容提醒出现异常:${e}`);
}
- return response;
+ return r;
}
-
-/**
- * 评论去广告及黑名单增强
- *
- * @return {*}
- */
function removeComment() {
- let response = null;
+ let e = null;
try {
if (!!$.response.body) {
- let obj = JSON.parse($.response.body);
- obj["ad_info"] = {};
- // 屏蔽黑名单用户
+ let t = JSON.parse($.response.body);
+ t["ad_info"] = {};
if ($.data.read("zhihu_settings_blocked_users", false) === true) {
- let user_info = getUserInfo();
- let customBlockedUsers = $.data.read(blockedUsersKey, "", user_info.id);
- customBlockedUsers = !!customBlockedUsers ? customBlockedUsers : {};
- let newComments = [];
- let blockCommentIdObj = {};
- if (typeof obj.root != "undefined") {
- // 屏蔽黑名单用户的评论
- const rootUserName = obj.root.author.name;
- const isBlackRootUser =
- typeof customBlockedUsers[rootUserName] != "undefined";
- if (isBlackRootUser === true) {
- obj.root.is_delete = true;
- obj.root.can_reply = false;
- obj.root.can_like = false;
- obj.root.author.name = "黑名单用户";
- obj.root.author.avatar_url =
+ let e = getUserInfo();
+ let s = $.data.read(blockedUsersKey, "", e.id);
+ s = !!s ? s : {};
+ let a = [];
+ let l = {};
+ if (typeof t.root != "undefined") {
+ const n = t.root.author.name;
+ const o = typeof s[n] != "undefined";
+ if (o === true) {
+ t.root.is_delete = true;
+ t.root.can_reply = false;
+ t.root.can_like = false;
+ t.root.author.name = "黑名单用户";
+ t.root.author.avatar_url =
"https://picx.zhimg.com/v2-abed1a8c04700ba7d72b45195223e0ff_xll.jpg";
}
}
-
- if (typeof obj.data != "undefined") {
- obj.data.forEach((comment) => {
- // 屏蔽黑名单用户的评论
- // 评论人昵称
- const commentUserName = comment.author.name;
- // 回复哪个人的评论(仅适用于独立子评论页面请求)
- let replyUserName = "";
- if (comment["reply_to_author"] && comment["reply_to_author"].name) {
- replyUserName = comment["reply_to_author"].name;
+ if (typeof t.data != "undefined") {
+ t.data.forEach((e) => {
+ const t = e.author.name;
+ let r = "";
+ if (e["reply_to_author"] && e["reply_to_author"].name) {
+ r = e["reply_to_author"].name;
}
- const isSubComment = replyUserName !== "";
- const isBlackCommentUser =
- typeof customBlockedUsers[commentUserName] != "undefined";
- const isBlackReplyUser =
- typeof customBlockedUsers[replyUserName] != "undefined";
- if (isBlackCommentUser === true || isBlackReplyUser === true) {
- if (
- isBlackCommentUser &&
- !isSubComment &&
- $.request.url.indexOf("root_comment") > 0
- ) {
- $.notification.debug(
- `屏蔽黑名单用户“${commentUserName}”的主评论。`
- );
+ const n = r !== "";
+ const o = typeof s[t] != "undefined";
+ const i = typeof s[r] != "undefined";
+ if (o === true || i === true) {
+ if (o && !n && $.request.url.indexOf("root_comment") > 0) {
+ $.notification.debug(`屏蔽黑名单用户“${t}”的主评论。`);
} else if (
- !isBlackCommentUser &&
- isSubComment &&
- !isBlackReplyUser &&
+ !o &&
+ n &&
+ !i &&
+ $.request.url.indexOf("child_comment") > 0
+ ) {
+ $.notification.debug(`屏蔽黑名单用户“${t}”的子评论。`);
+ } else if (
+ o &&
+ !i &&
$.request.url.indexOf("child_comment") > 0
) {
$.notification.debug(
- `屏蔽黑名单用户“${commentUserName}”的子评论。`
+ `屏蔽黑名单用户“${t}”回复“${r}”的子评论。`
);
- } else if (
- isBlackCommentUser &&
- !isBlackReplyUser &&
- $.request.url.indexOf("child_comment") > 0
- ) {
+ } else if (o && i && $.request.url.indexOf("child_comment") > 0) {
$.notification.debug(
- `屏蔽黑名单用户“${commentUserName}”回复“${replyUserName}”的子评论。`
- );
- } else if (
- isBlackCommentUser &&
- isBlackReplyUser &&
- $.request.url.indexOf("child_comment") > 0
- ) {
- $.notification.debug(
- `屏蔽黑名单用户“${commentUserName}”回复黑名单用户“${replyUserName}”的子评论。`
+ `屏蔽黑名单用户“${t}”回复黑名单用户“${r}”的子评论。`
);
}
- blockCommentIdObj[comment.id] = commentUserName;
- if (isBlackCommentUser) {
- comment.is_delete = true;
- comment.can_reply = false;
- comment.can_like = false;
- comment.author.exposed_medal = {};
- comment.author.name = "[黑名单用户]";
- comment.author.avatar_url =
+ l[e.id] = t;
+ if (o) {
+ e.is_delete = true;
+ e.can_reply = false;
+ e.can_like = false;
+ e.author.exposed_medal = {};
+ e.author.name = "[黑名单用户]";
+ e.author.avatar_url =
"https://picx.zhimg.com/v2-abed1a8c04700ba7d72b45195223e0ff_xll.jpg";
}
- if (isBlackReplyUser) {
- comment["reply_to_author"].name = "[黑名单用户]";
- comment["reply_to_author"].exposed_medal = {};
- comment["reply_to_author"].avatar_url =
+ if (i) {
+ e["reply_to_author"].name = "[黑名单用户]";
+ e["reply_to_author"].exposed_medal = {};
+ e["reply_to_author"].avatar_url =
"https://picx.zhimg.com/v2-abed1a8c04700ba7d72b45195223e0ff_xll.jpg";
}
}
- if (comment.child_comments) {
- let newChildComments = [];
- comment.child_comments.forEach((childComment) => {
- // 屏蔽黑名单用户的评论
- const childCommentUserName = childComment.author.name;
- const childCommentReplyUserName =
- typeof childComment["reply_to_author"] != "undefined"
- ? childComment["reply_to_author"].name
+ if (e.child_comments) {
+ let i = [];
+ e.child_comments.forEach((e) => {
+ const t = e.author.name;
+ const r =
+ typeof e["reply_to_author"] != "undefined"
+ ? e["reply_to_author"].name
: "";
- const isChildBlackCommentUser =
- typeof customBlockedUsers[childCommentUserName] !=
- "undefined";
- const isChildBlackReplyUser =
- typeof customBlockedUsers[childCommentReplyUserName] !=
- "undefined";
- if (isChildBlackCommentUser || isChildBlackReplyUser) {
- if (isChildBlackCommentUser === true) {
- $.notification.debug(
- `屏蔽黑名单用户“${childCommentUserName}”的子评论。`
- );
- blockCommentIdObj[childComment.id] = childCommentUserName;
- childComment.is_delete = true;
- childComment.can_reply = false;
- childComment.can_like = false;
- childComment.author.name = "[黑名单用户]";
- childComment.author.exposed_medal = {};
- childComment.author.avatar_url =
+ const n = typeof s[t] != "undefined";
+ const o = typeof s[r] != "undefined";
+ if (n || o) {
+ if (n === true) {
+ $.notification.debug(`屏蔽黑名单用户“${t}”的子评论。`);
+ l[e.id] = t;
+ e.is_delete = true;
+ e.can_reply = false;
+ e.can_like = false;
+ e.author.name = "[黑名单用户]";
+ e.author.exposed_medal = {};
+ e.author.avatar_url =
"https://picx.zhimg.com/v2-abed1a8c04700ba7d72b45195223e0ff_xll.jpg";
}
-
- if (isChildBlackReplyUser === true) {
- $.logger.debug(
- `修改前的子评论数据:\n${JSON.stringify(childComment)}`
- );
- childComment["reply_to_author"].name = "[黑名单用户]";
- childComment["reply_to_author"].exposed_medal = {};
- childComment["reply_to_author"].avatar_url =
+ if (o === true) {
+ $.logger.debug(`修改前的子评论数据:\n${JSON.stringify(e)}`);
+ e["reply_to_author"].name = "[黑名单用户]";
+ e["reply_to_author"].exposed_medal = {};
+ e["reply_to_author"].avatar_url =
"https://picx.zhimg.com/v2-abed1a8c04700ba7d72b45195223e0ff_xll.jpg";
$.notification.debug(
- `隐藏“${childCommentUserName}”回复黑名单用户“${childCommentReplyUserName}”的名称与头像。`
- );
- $.logger.debug(
- `修改后的子评论数据:\n${JSON.stringify(childComment)}`
+ `隐藏“${t}”回复黑名单用户“${r}”的名称与头像。`
);
+ $.logger.debug(`修改后的子评论数据:\n${JSON.stringify(e)}`);
}
}
- newChildComments.push(childComment);
+ i.push(e);
});
- comment.child_comments = newChildComments;
+ e.child_comments = i;
}
- newComments.push(comment);
+ a.push(e);
});
}
- obj.data = newComments;
+ t.data = a;
}
- const body = JSON.stringify(obj);
- $.logger.debug(`过滤后的评论数据:\n${body}`);
- response = { body: body };
+ const r = JSON.stringify(t);
+ $.logger.debug(`过滤后的评论数据:\n${r}`);
+ e = { body: r };
}
- } catch (err) {
- $.logger.error(`去除评论广告出现异常:${err}`);
+ } catch (e) {
+ $.logger.error(`去除评论广告出现异常:${e}`);
}
- return response;
+ return e;
}
-
-/**
- * 移除文章页面的广告
- * @return {*}
- */
function removeArticleAd() {
- let response = null;
+ let t = null;
try {
if (!!$.response.body) {
- let obj = JSON.parse($.response.body);
- obj["ad_info"] = {};
- const body = JSON.stringify(obj);
- $.logger.debug(`过滤后的文章数据:\n${body}`);
- response = { body: body };
+ let e = JSON.parse($.response.body);
+ e["ad_info"] = {};
+ const r = JSON.stringify(e);
+ $.logger.debug(`过滤后的文章数据:\n${r}`);
+ t = { body: r };
}
- } catch (err) {
- $.logger.error(`去除文章广告出现异常:${err}`);
+ } catch (e) {
+ $.logger.error(`去除文章广告出现异常:${e}`);
}
- return response;
+ return t;
}
-
-/**
- * 屏蔽官方营销消息
- *
- * @return {*}
- */
function removeMarketingMsg() {
- let response = null;
+ let t = 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 + "条";
+ let e = JSON.parse($.response.body);
+ let r = [];
+ for (let t of e["data"]) {
+ if (t["detail_title"] === "官方帐号消息") {
+ let e = t["unread_count"];
+ if (e > 0) {
+ t["content"]["text"] = "未读消息" + e + "条";
} else {
- item["content"]["text"] = "全部消息已读";
+ t["content"]["text"] = "全部消息已读";
}
- item["is_read"] = true;
- item["unread_count"] = 0;
- newItems.push(item);
- } else if (item["detail_title"] !== "活动助手") {
- newItems.push(item);
+ t["is_read"] = true;
+ t["unread_count"] = 0;
+ r.push(t);
+ } else if (t["detail_title"] !== "活动助手") {
+ r.push(t);
}
}
- obj["data"] = newItems;
- response = { body: JSON.stringify(obj) };
- } catch (err) {
- $.logger.error(`屏蔽官方营销消息出现异常:${err}`);
+ e["data"] = r;
+ t = { body: JSON.stringify(e) };
+ } catch (e) {
+ $.logger.error(`屏蔽官方营销消息出现异常:${e}`);
}
- return response;
+ return t;
}
-
-/**
- * 热榜去广告
- *
- * @return {*}
- */
function removeHotListAds() {
- let response = null;
+ let t = null;
try {
if (!!$.response.body) {
- let obj = JSON.parse($.response.body);
- if ("data" in obj) {
- obj["data"] = obj["data"].filter((e) => {
+ let e = JSON.parse($.response.body);
+ if ("data" in e) {
+ e["data"] = e["data"].filter((e) => {
return (
e["type"] === "hot_list_feed" || e["type"] === "hot_list_feed_video"
);
});
}
- response = { body: JSON.stringify(obj) };
+ t = { body: JSON.stringify(e) };
}
- } catch (err) {
- $.logger.error(`去除热榜广告出现异常:${err}`);
+ } catch (e) {
+ $.logger.error(`去除热榜广告出现异常:${e}`);
}
- return response;
+ return t;
}
-
-/**
- * 去除预置关键字广告
- *
- * @return {*}
- */
function removeKeywordAds() {
- let response = null;
+ let t = null;
try {
if (!!$.response.body) {
$.logger.debug(`预置关键字返回:${$.response.body}`);
- let obj = JSON.parse($.response.body);
- if (obj.hasOwnProperty("preset_words") && obj["preset_words"]["words"]) {
- obj["preset_words"]["words"] = obj["preset_words"]["words"].filter(
- (element) => {
- return element["type"] !== "ad";
- }
- );
- response = { body: JSON.stringify(obj) };
+ let e = JSON.parse($.response.body);
+ if (e.hasOwnProperty("preset_words") && e["preset_words"]["words"]) {
+ e["preset_words"]["words"] = e["preset_words"]["words"].filter((e) => {
+ return e["type"] !== "ad";
+ });
+ t = { body: JSON.stringify(e) };
}
}
- } catch (err) {
- $.logger.error(`去除预置关键字广告出现异常:${err}`);
+ } catch (e) {
+ $.logger.error(`去除预置关键字广告出现异常:${e}`);
}
- return response;
+ return t;
}
-
-/**
- * 移除回答翻页时出现的黑名单用户的回答
- * 小概率会移除失败
- * @return {*}
- */
function removeNextBlackUserAnswer() {
- let response = null;
+ let t = null;
try {
if (!!$.response.body) {
- let obj = JSON.parse($.response.body);
- const blackUserAnswersId = $.data.read(blackAnswersIdKey, []);
- if (blackUserAnswersId.length > 0) {
- let newData = [];
- obj.data.forEach((element) => {
- const tag = blackUserAnswersId.includes(element.id.toString());
- if (tag === false) {
- // 去除可能的广告
- element.ad_info = { data: "" };
- newData.push(element);
+ let e = JSON.parse($.response.body);
+ const n = $.data.read(blackAnswersIdKey, []);
+ if (n.length > 0) {
+ let r = [];
+ e.data.forEach((e) => {
+ const t = n.includes(e.id.toString());
+ if (t === false) {
+ e.ad_info = { data: "" };
+ r.push(e);
} else {
$.notification.debug(
- `屏蔽翻页过程中出现的黑名单用户回答Id:${element.id}`
+ `屏蔽翻页过程中出现的黑名单用户回答Id:${e.id}`
);
}
});
- // 重新为答案排序
- for (let i = 0; i < newData.length; i++) {
- if (newData[i]["extra"] && newData[i]["extra"]["question_index"]) {
- newData[i]["extra"]["question_index"] = i + 1;
+ for (let e = 0; e < r.length; e++) {
+ if (r[e]["extra"] && r[e]["extra"]["question_index"]) {
+ r[e]["extra"]["question_index"] = e + 1;
}
- if (newData[i]["strategy_info"]) {
- newData[i]["strategy_info"]["global_index"] = i + 1;
- newData[i]["strategy_info"]["strategy_index"] = i + 1;
+ if (r[e]["strategy_info"]) {
+ r[e]["strategy_info"]["global_index"] = e + 1;
+ r[e]["strategy_info"]["strategy_index"] = e + 1;
}
}
- obj.data = newData;
+ e.data = r;
}
- response = { body: JSON.stringify(obj) };
+ t = { body: JSON.stringify(e) };
}
- } catch (err) {
- $.logger.error(`屏蔽下翻黑名单用户的回答出现异常:${err}`);
+ } catch (e) {
+ $.logger.error(`屏蔽下翻黑名单用户的回答出现异常:${e}`);
}
- return response;
+ return t;
}
-
function modifyAnswersNextData() {
- let response = null;
+ let o = null;
try {
if (!!$.response.body) {
- let obj = JSON.parse($.response.body);
- let user_info = getUserInfo();
- let customBlockedUsers = $.data.read(blockedUsersKey, {}, user_info.id);
- $.logger.debug(`脚本黑名单用户:\n${JSON.stringify(customBlockedUsers)}`);
- let newData = [];
- obj.data.data.forEach((element) => {
- element["ad_info"] = { data: "" };
- const isBlackUser =
- typeof customBlockedUsers[element.data.author.name] != "undefined";
- $.logger.debug(
- `用户${element.data.author.name}是否在黑名单中:${isBlackUser}`
- );
+ let e = JSON.parse($.response.body);
+ let t = getUserInfo();
+ let r = $.data.read(blockedUsersKey, {}, t.id);
+ $.logger.debug(`脚本黑名单用户:\n${JSON.stringify(r)}`);
+ let n = [];
+ e.data.data.forEach((e) => {
+ e["ad_info"] = { data: "" };
+ const t = typeof r[e.data.author.name] != "undefined";
+ $.logger.debug(`用户${e.data.author.name}是否在黑名单中:${t}`);
if (
$.data.read("zhihu_settings_blocked_users", false) === false ||
- isBlackUser === false
+ t === false
) {
- newData.push(element);
+ n.push(e);
}
});
- obj.data.data = newData;
- response = { body: JSON.stringify(obj) };
+ e.data.data = n;
+ o = { body: JSON.stringify(e) };
}
- } catch (err) {
- $.logger.error(`屏蔽回答信息流黑名单用户及广告:${err}`);
+ } catch (e) {
+ $.logger.error(`屏蔽回答信息流黑名单用户及广告:${e}`);
}
- return response;
+ return o;
}
-
-/**
- * 修改盐值
- *
- * @return {*}
- */
function changeUserCredit() {
$.notification.debug("开始修改用户盐值");
- let response = null;
+ let t = null;
try {
if (!!$.response.body) {
- // 自定义盐值
- const score = parseInt($.data.read(userCreditScore, 780));
- $.logger.debug(`准备修改用户盐值为${score}`);
- let obj = JSON.parse($.response.body);
- if (obj["credit_basis"].total_score < score) {
- obj["credit_basis"].total_score = score;
- $.logger.debug(`已修改用户盐值为:${score}`);
+ const r = parseInt($.data.read(userCreditScoreKey, 780));
+ $.logger.debug(`准备修改用户盐值为${r}`);
+ let e = JSON.parse($.response.body);
+ if (e["credit_basis"].total_score < r) {
+ e["credit_basis"].total_score = r;
+ $.logger.debug(`已修改用户盐值为:${r}`);
}
- response = { body: JSON.stringify(obj) };
+ t = { body: JSON.stringify(e) };
}
- } catch (err) {
- $.logger.error(`修改用户盐值出现异常:${err}`);
+ } catch (e) {
+ $.logger.error(`修改用户盐值出现异常:${e}`);
}
- return response;
+ return t;
}
-
-(() => {
- let response = null;
+(async () => {
+ let e = null;
if ($.isResponse) {
switch (true) {
- // 获取用户信息 - 隔离用户数据,开启本地盐选会员等
case /^https:\/\/api\.zhihu\.com\/people\/self$/.test($.request.url):
- response = processUserInfo();
+ e = processUserInfo();
break;
- // 优化软件配置 - 优化下发的配置文件来实现某些效果
case $.data.read("zhihu_settings_app_conf", false) === true &&
/^https?:\/\/appcloud2\.zhihu\.com\/v\d+\/config/.test($.request.url):
- response = modifyAppConfig();
+ e = modifyAppConfig();
break;
case $.data.read("zhihu_settings_app_conf", false) === true &&
/^https?:\/\/m-cloud\.zhihu\.com\/api\/cloud\/config\/all\?/.test(
$.request.url
):
- response = modifyMCloudConfig();
+ e = modifyMCloudConfig();
break;
- // 修改用户盐值 - 仅当自定义盐值大于真实盐值时生效
case /^https?:\/\/api\.zhihu\.com\/user-credit\/basis/.test(
$.request.url
):
- $.notification.debug("准备修改用户盐值");
- response = changeUserCredit();
+ e = changeUserCredit();
break;
- // 推荐页 - 移除黑名单用户发布的文章、去除广告,及自定义一些屏蔽项目
case /^https:\/\/api\.zhihu\.com\/topstory\/recommend/.test(
$.request.url
):
- response = removeRecommend();
+ e = await removeRecommend();
break;
- // 问题的回答列表 - 移除黑名单用户的回答、去除广告
case /^https?:\/\/api\.zhihu\.com\/(v4\/)?questions\/\d+/.test(
$.request.url
):
- response = removeQuestions();
+ e = removeQuestions();
break;
- // 回答信息流 - 移除黑名单用户的回答、去除广告
case /^https?:\/\/api\.zhihu\.com\/next-data\?/.test($.request.url):
- response = modifyAnswersNextData();
+ e = modifyAnswersNextData();
break;
- // 消息页 - 折叠官方消息、屏蔽营销消息
case $.data.read("zhihu_settings_sys_msg", true) !== false &&
/^https?:\/\/api\.zhihu\.com\/notifications\/v3\/message/.test(
$.request.url
):
- response = removeMarketingMsg();
+ e = removeMarketingMsg();
break;
- // 评论页及子页面 - 去除黑名单用户发表的评论
case /^https?:\/\/api\.zhihu\.com\/comment_v5\/(answers|pins|comments?|articles)\/\d+\/(root|child)_comment/.test(
$.request.url
):
- response = removeComment();
+ e = removeComment();
break;
- // 文章页 - 去除底部卡片广告
case /^https?:\/\/www\.zhihu\.com\/api\/v\d\/articles\/\d+\/recommendation\?/.test(
$.request.url
):
- response = removeArticleAd();
+ e = removeArticleAd();
break;
- // 回答页底部评论摘要 - 移除黑名单用户发表的评论
case /^https?:\/\/www\.zhihu\.com\/api\/v4\/comment_v5\/answers\/\d+\/abstract_comment\?/.test(
$.request.url
):
- response = removeComment();
+ e = removeComment();
break;
- // 回答内容优化 - 付费、营销、推广内容文首提醒
case $.data.read("zhihu_settings_answer_tip", true) === true &&
/^https?:\/\/www\.zhihu\.com\/appview\/v2\/answer\/.*(entry=(?!(preload-topstory|preload-search|preload-subscription)))?/.test(
$.request.url
):
- response = modifyAnswer();
+ e = modifyAnswer();
break;
- // 回答页 - 屏蔽下翻出现的黑名单用户
case $.data.read("zhihu_settings_blocked_users", false) !== false &&
/^https?:\/\/api\.zhihu\.com\/next\?/.test($.request.url):
- response = removeNextBlackUserAnswer();
+ e = removeNextBlackUserAnswer();
break;
- // 黑名单增强 - 浏览黑名单用户信息时自动加入脚本黑名单
case $.data.read("zhihu_settings_blocked_users", true) === true &&
/^https?:\/\/api\.zhihu\.com\/people\/((?!self).)*$/.test(
$.request.url
):
- response = autoInsertBlackList();
+ e = autoInsertBlackList();
break;
- // 关注页 - 去广告
case /^https?:\/\/api\.zhihu\.com\/moments_v3\?/.test($.request.url):
- response = removeMoments();
+ e = removeMoments();
break;
- // 热榜页 - 去广告
case $.data.read("zhihu_settings_hot_list", true) === true &&
/^https?:\/\/api\.zhihu\.com\/topstory\/hot-lists(\?|\/)/.test(
$.request.url
):
- response = removeHotListAds();
+ e = removeHotListAds();
break;
- // 搜索页 - 去除预置广告
case $.data.read("zhihu_settings_preset_words", true) === true &&
/^https?:\/\/api\.zhihu\.com\/search\/preset_words\?/.test(
$.request.url
):
- response = removeKeywordAds();
+ e = removeKeywordAds();
break;
- // 黑名单页 - 同步黑名单数据
case $.data.read("zhihu_settings_blocked_users", false) !== false &&
/^https?:\/\/api\.zhihu\.com\/settings\/blocked_users/.test(
$.request.url
@@ -1350,13 +1156,12 @@ function changeUserCredit() {
break;
}
} else if ($.isRequest) {
- // 屏蔽关键词解锁
if (
$.data.read("zhihu_settings_blocked_keywords", false) !== false &&
/^https?:\/\/api\.zhihu\.com\/feed-root\/block/.test($.request.url) ===
true
) {
- response = unlockBlockedKeywords(response);
+ e = unlockBlockedKeywords(e);
}
} else {
$.data.del(currentUserInfoKey);
@@ -1364,431 +1169,952 @@ function changeUserCredit() {
$.data.del(keywordBlockKey);
$.notification.post("哲也同学数据清理完毕");
}
- if (response) {
- $.done(response);
+ if (e) {
+ $.done(e);
} else {
$.done();
}
})();
-
-// prettier-ignore
-/**
- *
- * $$\ $$\ $$\ $$$$$\ $$$$$$\ $$$$$$\
- * $$$\ $$$ | \__| \__$$ |$$ __$$\ $$ ___$$\
- * $$$$\ $$$$ | $$$$$$\ $$$$$$\ $$\ $$$$$$$\ $$ |$$ / \__| \_/ $$ |
- * $$\$$\$$ $$ | \____$$\ $$ __$$\ $$ |$$ _____| $$ |\$$$$$$\ $$$$$ /
- * $$ \$$$ $$ | $$$$$$$ |$$ / $$ |$$ |$$ / $$\ $$ | \____$$\ \___$$\
- * $$ |\$ /$$ |$$ __$$ |$$ | $$ |$$ |$$ | $$ | $$ |$$\ $$ | $$\ $$ |
- * $$ | \_/ $$ |\$$$$$$$ |\$$$$$$$ |$$ |\$$$$$$$\\$$$$$$ |\$$$$$$ | \$$$$$$ |
- * \__| \__| \_______| \____$$ |\__| \_______|\______/ \______/ \______/
- * $$\ $$ |
- * \$$$$$$ |
- * \______/
- *
- */
-// @formatter:off
-function MagicJS(scriptName="MagicJS",logLevel="INFO"){const MagicEnvironment=()=>{const isLoon=typeof $loon!=="undefined";const isQuanX=typeof $task!=="undefined";const isNode=typeof module!=="undefined";const isSurge=typeof $httpClient!=="undefined"&&!isLoon;const isStorm=typeof $storm!=="undefined";const isStash=typeof $environment!=="undefined"&&typeof $environment["stash-build"]!=="undefined";const isSurgeLike=isSurge||isLoon||isStorm||isStash;const isScriptable=typeof importModule!=="undefined";return{isLoon:isLoon,isQuanX:isQuanX,isNode:isNode,isSurge:isSurge,isStorm:isStorm,isStash:isStash,isSurgeLike:isSurgeLike,isScriptable:isScriptable,get name(){if(isLoon){return"Loon"}else if(isQuanX){return"QuantumultX"}else if(isNode){return"NodeJS"}else if(isSurge){return"Surge"}else if(isScriptable){return"Scriptable"}else{return"unknown"}},get build(){if(isSurge){return $environment["surge-build"]}else if(isStash){return $environment["stash-build"]}else if(isStorm){return $storm.buildVersion}},get language(){if(isSurge||isStash){return $environment["language"]}},get version(){if(isSurge){return $environment["surge-version"]}else if(isStash){return $environment["stash-version"]}else if(isStorm){return $storm.appVersion}else if(isNode){return process.version}},get system(){if(isSurge){return $environment["system"]}else if(isNode){return process.platform}},get systemVersion(){if(isStorm){return $storm.systemVersion}},get deviceName(){if(isStorm){return $storm.deviceName}}}};const MagicLogger=(scriptName,logLevel="INFO")=>{let _level=logLevel;const logLevels={SNIFFER:6,DEBUG:5,INFO:4,NOTIFY:3,WARNING:2,ERROR:1,CRITICAL:0,NONE:-1};const logEmoji={SNIFFER:"",DEBUG:"",INFO:"",NOTIFY:"",WARNING:"❗ ",ERROR:"❌ ",CRITICAL:"❌ ",NONE:""};const _log=(msg,level="INFO")=>{if(!(logLevels[_level]{_level=logLevel};return{getLevel:()=>{return _level},setLevel:setLevel,sniffer:msg=>{_log(msg,"SNIFFER")},debug:msg=>{_log(msg,"DEBUG")},info:msg=>{_log(msg,"INFO")},notify:msg=>{_log(msg,"NOTIFY")},warning:msg=>{_log(msg,"WARNING")},error:msg=>{_log(msg,"ERROR")},retry:msg=>{_log(msg,"RETRY")}}};return new class{constructor(scriptName,logLevel){this._startTime=Date.now();this.version="3.0.0";this.scriptName=scriptName;this.env=MagicEnvironment();this.logger=MagicLogger(scriptName,logLevel);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 magicLoglevel=this.data.read("magic_loglevel");const barkUrl=this.data.read("magic_bark_url");if(magicLoglevel){this.logger.setLevel(magicLoglevel.toUpperCase())}if(barkUrl){this.notification.setBark(barkUrl)}}}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=(value={})=>{this._endTime=Date.now();let span=(this._endTime-this._startTime)/1e3;this.logger.debug(`SCRIPT COMPLETED: ${span} S.`);if(typeof $done!=="undefined"){$done(value)}}}(scriptName,logLevel)}
-function MagicNotification(scriptName, env, logger, http) {
- let _barkUrl = null;
- let _barkKey = null;
- const setBark = (url) => {
- try {
- let _url = url.replace(/\/+$/g, "");
- _barkUrl = `${/^https?:\/\/([^/]*)/.exec(_url)[0]}/push`;
- _barkKey = /\/([^\/]+)\/?$/.exec(_url)[1];
- } catch (ex) {
- logger.error(`Bark url error: ${ex}.`);
- }
- };
- function post(title = scriptName, subTitle = "", body = "", opts = "") {
- const _adaptOpts = (_opts) => {
- try {
- let newOpts = {};
- if (typeof _opts === "string") {
- if (env.isLoon) newOpts = { openUrl: _opts };
- else if (env.isQuanX) newOpts = { "open-url": _opts };
- else if (env.isSurge) newOpts = { url: _opts };
- } else if (typeof _opts === "object") {
- if (env.isLoon) {
- newOpts["openUrl"] = !!_opts["open-url"] ? _opts["open-url"] : "";
- newOpts["mediaUrl"] = !!_opts["media-url"]
- ? _opts["media-url"]
- : "";
- } else if (env.isQuanX) {
- newOpts = !!_opts["open-url"] || !!_opts["media-url"] ? _opts : {};
- } else if (env.isSurge) {
- let openUrl = _opts["open-url"] || _opts["openUrl"];
- newOpts = openUrl ? { url: openUrl } : {};
- }
+function MagicJS(e = "MagicJS", t = "INFO") {
+ const n = () => {
+ const e = typeof $loon !== "undefined";
+ const t = typeof $task !== "undefined";
+ const r = typeof module !== "undefined";
+ const n = typeof $httpClient !== "undefined" && !e;
+ const o = typeof $storm !== "undefined";
+ const i =
+ typeof $environment !== "undefined" &&
+ typeof $environment["stash-build"] !== "undefined";
+ const s = n || e || o || i;
+ const a = typeof importModule !== "undefined";
+ return {
+ isLoon: e,
+ isQuanX: t,
+ isNode: r,
+ isSurge: n,
+ isStorm: o,
+ isStash: i,
+ isSurgeLike: s,
+ isScriptable: a,
+ get name() {
+ if (e) {
+ return "Loon";
+ } else if (t) {
+ return "QuantumultX";
+ } else if (r) {
+ return "NodeJS";
+ } else if (n) {
+ return "Surge";
+ } else if (a) {
+ return "Scriptable";
+ } else {
+ return "unknown";
+ }
+ },
+ get build() {
+ if (n) {
+ return $environment["surge-build"];
+ } else if (i) {
+ return $environment["stash-build"];
+ } else if (o) {
+ return $storm.buildVersion;
+ }
+ },
+ get language() {
+ if (n || i) {
+ return $environment["language"];
+ }
+ },
+ get version() {
+ if (n) {
+ return $environment["surge-version"];
+ } else if (i) {
+ return $environment["stash-version"];
+ } else if (o) {
+ return $storm.appVersion;
+ } else if (r) {
+ return process.version;
+ }
+ },
+ get system() {
+ if (n) {
+ return $environment["system"];
+ } else if (r) {
+ return process.platform;
+ }
+ },
+ get systemVersion() {
+ if (o) {
+ return $storm.systemVersion;
+ }
+ },
+ get deviceName() {
+ if (o) {
+ return $storm.deviceName;
}
- return newOpts;
- } catch (err) {
- logger.error(`通知选项转换失败${err}`);
- }
- return _opts;
- };
- opts = _adaptOpts(opts);
- if (arguments.length === 1) {
- title = scriptName;
- (subTitle = ""), (body = arguments[0]);
- }
- logger.notify(
- `title:${title}\nsubTitle:${subTitle}\nbody:${body}\noptions:${
- typeof opts === "object" ? JSON.stringify(opts) : opts
- }`
- );
- if (env.isSurge) {
- $notification.post(title, subTitle, body, opts);
- } else if (env.isLoon) {
- if (!!opts) $notification.post(title, subTitle, body, opts);
- else $notification.post(title, subTitle, body);
- } else if (env.isQuanX) {
- $notify(title, subTitle, body, opts);
- }
- if (_barkUrl && _barkKey) {
- bark(title, subTitle, body);
- }
- }
- function debug(title = scriptName, subTitle = "", body = "", opts = "") {
- if (logger.getLevel() === "DEBUG") {
- if (arguments.length === 1) {
- title = scriptName;
- subTitle = "";
- body = arguments[0];
- }
- this.post(title, subTitle, body, opts);
- }
- }
- function bark(title = scriptName, subTitle = "", body = "", opts = "") {
- if (typeof http === "undefined" || typeof http.post === "undefined") {
- throw "Bark notification needs to import MagicHttp module.";
- }
- let options = {
- url: _barkUrl,
- headers: { "content-type": "application/json; charset=utf-8" },
- body: {
- title: title,
- body: subTitle ? `${subTitle}\n${body}` : body,
- device_key: _barkKey,
},
};
- http.post(options).catch((ex) => {
- logger.error(`Bark notify error: ${ex}`);
- });
- }
- return { post: post, debug: debug, bark: bark, setBark: setBark };
-}
-function MagicData(env, logger) {
- let node = { fs: undefined, data: {} };
- if (env.isNode) {
- node.fs = require("fs");
- try {
- node.fs.accessSync(
- "./magic.json",
- node.fs.constants.R_OK | node.fs.constants.W_OK
- );
- } catch (err) {
- node.fs.writeFileSync("./magic.json", "{}", { encoding: "utf8" });
- }
- node.data = require("./magic.json");
- }
- const defaultValueComparator = (oldVal, newVal) => {
- if (typeof newVal === "object") {
- return false;
- } else {
- return oldVal === newVal;
- }
};
- const _typeConvertor = (val) => {
- if (val === "true") {
- return true;
- } else if (val === "false") {
- return false;
- } else if (typeof val === "undefined") {
- return null;
- } else {
- return val;
- }
+ const o = (r, e = "INFO") => {
+ let n = e;
+ const o = {
+ SNIFFER: 6,
+ DEBUG: 5,
+ INFO: 4,
+ NOTIFY: 3,
+ WARNING: 2,
+ ERROR: 1,
+ CRITICAL: 0,
+ NONE: -1,
+ };
+ const i = {
+ SNIFFER: "",
+ DEBUG: "",
+ INFO: "",
+ NOTIFY: "",
+ WARNING: "❗ ",
+ ERROR: "❌ ",
+ CRITICAL: "❌ ",
+ NONE: "",
+ };
+ const t = (e, t = "INFO") => {
+ if (!(o[n] < o[t.toUpperCase()]))
+ console.log(`[${t}] [${r}]\n${i[t.toUpperCase()]}${e}\n`);
+ };
+ const s = (e) => {
+ n = e;
+ };
+ return {
+ getLevel: () => {
+ return n;
+ },
+ 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");
+ },
+ };
};
- const _valConvertor = (val, default_, session, read_no_session) => {
- if (session) {
- try {
- if (typeof val === "string") val = JSON.parse(val);
- if (val["magic_session"] === true) {
- val = val[session];
- } else {
- val = null;
+ return new (class {
+ constructor(e, t) {
+ this._startTime = Date.now();
+ this.version = "3.0.0";
+ this.scriptName = e;
+ this.env = n();
+ this.logger = o(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 r = this.data.read("magic_bark_url");
+ if (e) {
+ this.logger.setLevel(e.toUpperCase());
+ }
+ if (r) {
+ this.notification.setBark(r);
}
- } catch {
- val = null;
}
}
- if (typeof val === "string" && val !== "null") {
+ 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 MagicNotification(i, s, a, l) {
+ let c = null;
+ let d = null;
+ const e = (t) => {
+ try {
+ let e = t.replace(/\/+$/g, "");
+ c = `${/^https?:\/\/([^/]*)/.exec(e)[0]}/push`;
+ d = /\/([^\/]+)\/?$/.exec(e)[1];
+ } catch (e) {
+ a.error(`Bark url error: ${e}.`);
+ }
+ };
+ function t(e = i, t = "", r = "", n = "") {
+ const o = (r) => {
try {
- val = JSON.parse(val);
+ let t = {};
+ if (typeof r === "string") {
+ if (s.isLoon) t = { openUrl: r };
+ else if (s.isQuanX) t = { "open-url": r };
+ else if (s.isSurge) t = { url: r };
+ } else if (typeof r === "object") {
+ if (s.isLoon) {
+ t["openUrl"] = !!r["open-url"] ? r["open-url"] : "";
+ t["mediaUrl"] = !!r["media-url"] ? r["media-url"] : "";
+ } else if (s.isQuanX) {
+ t = !!r["open-url"] || !!r["media-url"] ? r : {};
+ } else if (s.isSurge) {
+ let e = r["open-url"] || r["openUrl"];
+ t = e ? { url: e } : {};
+ }
+ }
+ return t;
+ } catch (e) {
+ a.error(`通知选项转换失败${e}`);
+ }
+ return r;
+ };
+ n = o(n);
+ if (arguments.length === 1) {
+ e = i;
+ (t = ""), (r = arguments[0]);
+ }
+ a.notify(
+ `title:${e}\nsubTitle:${t}\nbody:${r}\noptions:${
+ typeof n === "object" ? JSON.stringify(n) : n
+ }`
+ );
+ if (s.isSurge) {
+ $notification.post(e, t, r, n);
+ } else if (s.isLoon) {
+ if (!!n) $notification.post(e, t, r, n);
+ else $notification.post(e, t, r);
+ } else if (s.isQuanX) {
+ $notify(e, t, r, n);
+ }
+ if (c && d) {
+ u(e, t, r);
+ }
+ }
+ function r(e = i, t = "", r = "", n = "") {
+ if (a.getLevel() === "DEBUG") {
+ if (arguments.length === 1) {
+ e = i;
+ t = "";
+ r = arguments[0];
+ }
+ this.post(e, t, r, n);
+ }
+ }
+ function u(e = i, t = "", r = "", n = "") {
+ if (typeof l === "undefined" || typeof l.post === "undefined") {
+ throw "Bark notification needs to import MagicHttp module.";
+ }
+ let o = {
+ url: c,
+ headers: { "content-type": "application/json; charset=utf-8" },
+ body: { title: e, body: t ? `${t}\n${r}` : r, device_key: d },
+ };
+ l.post(o).catch((e) => {
+ a.error(`Bark notify error: ${e}`);
+ });
+ }
+ return { post: t, debug: r, bark: u, 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 c = (e, t) => {
+ if (typeof t === "object") {
+ return false;
+ } else {
+ return e === t;
+ }
+ };
+ const d = (e) => {
+ if (e === "true") {
+ return true;
+ } else if (e === "false") {
+ return false;
+ } else if (typeof e === "undefined") {
+ return null;
+ } else {
+ return e;
+ }
+ };
+ const u = (e, t, r, n) => {
+ 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 (read_no_session === false && !!val && val["magic_session"] === true) {
- val = null;
+ if (n === false && !!e && e["magic_session"] === true) {
+ e = null;
}
if (
- (val === null || typeof val === "undefined") &&
- default_ !== null &&
- typeof default_ !== "undefined"
+ (e === null || typeof e === "undefined") &&
+ t !== null &&
+ typeof t !== "undefined"
) {
- val = default_;
+ e = t;
}
- val = _typeConvertor(val);
- return val;
+ e = d(e);
+ return e;
};
- const convertToObject = (obj) => {
- if (typeof obj === "string") {
- let data = {};
+ const i = (t) => {
+ if (typeof t === "string") {
+ let e = {};
try {
- data = JSON.parse(obj);
- const type = typeof data;
+ e = JSON.parse(t);
+ const r = typeof e;
if (
- type !== "object" ||
- data instanceof Array ||
- type === "bool" ||
- data === null
+ r !== "object" ||
+ e instanceof Array ||
+ r === "bool" ||
+ e === null
) {
- data = {};
+ e = {};
}
} catch {}
- return data;
+ return e;
} else if (
- obj instanceof Array ||
- obj === null ||
- typeof obj === "undefined" ||
- obj !== obj ||
- typeof obj === "boolean"
+ t instanceof Array ||
+ t === null ||
+ typeof t === "undefined" ||
+ t !== t ||
+ typeof t === "boolean"
) {
return {};
} else {
- return obj;
+ return t;
}
};
- const readForNode = (
- key,
- default_ = null,
- session = "",
- read_no_session = false,
- externalData = null
- ) => {
- let data = externalData || node.data;
- if (!!data && typeof data[key] !== "undefined" && data[key] !== null) {
- val = data[key];
+ const f = (e, t = null, r = "", n = false, o = null) => {
+ let i = o || l.data;
+ if (!!i && typeof i[e] !== "undefined" && i[e] !== null) {
+ val = i[e];
} else {
- val = !!session ? {} : null;
+ val = !!r ? {} : null;
}
- val = _valConvertor(val, default_, session, read_no_session);
+ val = u(val, t, r, n);
return val;
};
- const read = (
- key,
- default_ = null,
- session = "",
- read_no_session = false,
- externalData = null
- ) => {
- let val = "";
- if (externalData || env.isNode) {
- val = readForNode(key, default_, session, read_no_session, externalData);
+ const g = (e, t = null, r = "", n = false, o = null) => {
+ let i = "";
+ if (o || s.isNode) {
+ i = f(e, t, r, n, o);
} else {
- if (env.isSurgeLike) {
- val = $persistentStore.read(key);
- } else if (env.isQuanX) {
- val = $prefs.valueForKey(key);
+ if (s.isSurgeLike) {
+ i = $persistentStore.read(e);
+ } else if (s.isQuanX) {
+ i = $prefs.valueForKey(e);
}
- val = _valConvertor(val, default_, session, read_no_session);
+ i = u(i, t, r, n);
}
- logger.debug(
- `READ DATA [${key}]${
- !!session ? `[${session}]` : ""
- } <${typeof val}>\n${JSON.stringify(val)}`
+ a.debug(
+ `READ DATA [${e}]${!!r ? `[${r}]` : ""} <${typeof i}>\n${JSON.stringify(
+ i
+ )}`
);
- return val;
+ return i;
};
- const writeForNode = (key, val, session = "", externalData = null) => {
- let data = externalData || node.data;
- data = convertToObject(data);
- if (!!session) {
- let obj = convertToObject(data[key]);
- obj["magic_session"] = true;
- obj[session] = val;
- data[key] = obj;
+ const p = (t, r, n = "", e = null) => {
+ let o = e || l.data;
+ o = i(o);
+ if (!!n) {
+ let e = i(o[t]);
+ e["magic_session"] = true;
+ e[n] = r;
+ o[t] = e;
} else {
- data[key] = val;
+ o[t] = r;
}
- if (externalData !== null) {
- externalData = data;
+ if (e !== null) {
+ e = o;
}
- return data;
+ return o;
};
- const write = (key, val, session = "", externalData = null) => {
- if (typeof val === "undefined" || val !== val) {
+ const h = (e, t, r = "", n = null) => {
+ if (typeof t === "undefined" || t !== t) {
return false;
}
- if (!env.isNode && (typeof val === "boolean" || typeof val === "number")) {
- val = String(val);
+ if (!s.isNode && (typeof t === "boolean" || typeof t === "number")) {
+ t = String(t);
}
- let data = "";
- if (externalData || env.isNode) {
- data = writeForNode(key, val, session, externalData);
+ let o = "";
+ if (n || s.isNode) {
+ o = p(e, t, r, n);
} else {
- if (!session) {
- data = val;
+ if (!r) {
+ o = t;
} else {
- if (env.isSurgeLike) {
- data = !!$persistentStore.read(key)
- ? $persistentStore.read(key)
- : data;
- } else if (env.isQuanX) {
- data = !!$prefs.valueForKey(key) ? $prefs.valueForKey(key) : data;
+ if (s.isSurgeLike) {
+ o = !!$persistentStore.read(e) ? $persistentStore.read(e) : o;
+ } else if (s.isQuanX) {
+ o = !!$prefs.valueForKey(e) ? $prefs.valueForKey(e) : o;
}
- data = convertToObject(data);
- data["magic_session"] = true;
- data[session] = val;
+ o = i(o);
+ o["magic_session"] = true;
+ o[r] = t;
}
}
- if (!!data && typeof data === "object") {
- data = JSON.stringify(data, null, 4);
+ if (!!o && typeof o === "object") {
+ o = JSON.stringify(o, null, 4);
}
- logger.debug(
- `WRITE DATA [${key}]${
- session ? `[${session}]` : ""
- } <${typeof val}>\n${JSON.stringify(val)}`
+ a.debug(
+ `WRITE DATA [${e}]${r ? `[${r}]` : ""} <${typeof t}>\n${JSON.stringify(
+ t
+ )}`
);
- if (!externalData) {
- if (env.isSurgeLike) {
- return $persistentStore.write(data, key);
- } else if (env.isQuanX) {
- return $prefs.setValueForKey(data, key);
- } else if (env.isNode) {
+ if (!n) {
+ if (s.isSurgeLike) {
+ return $persistentStore.write(o, e);
+ } else if (s.isQuanX) {
+ return $prefs.setValueForKey(o, e);
+ } else if (s.isNode) {
try {
- node.fs.writeFileSync("./magic.json", data);
+ l.fs.writeFileSync("./magic.json", o);
return true;
- } catch (err) {
- logger.error(err);
+ } catch (e) {
+ a.error(e);
return false;
}
}
}
return true;
};
- const update = (
- key,
- val,
- session,
- comparator = defaultValueComparator,
- externalData = null
- ) => {
- val = _typeConvertor(val);
- const oldValue = read(key, null, session, false, externalData);
- if (comparator(oldValue, val) === true) {
+ const e = (t, r, n, o = c, i = null) => {
+ r = d(r);
+ const e = g(t, null, n, false, i);
+ if (o(e, r) === true) {
return false;
} else {
- const result = write(key, val, session, externalData);
- let newVal = read(key, null, session, false, externalData);
- if (comparator === defaultValueComparator && typeof newVal === "object") {
- return result;
+ const s = h(t, r, n, i);
+ let e = g(t, null, n, false, i);
+ if (o === c && typeof e === "object") {
+ return s;
}
- return comparator(val, newVal);
+ return o(r, e);
}
};
- const delForNode = (key, session, externalData) => {
- let data = externalData || node.data;
- data = convertToObject(data);
- if (!!session) {
- obj = convertToObject(data[key]);
- delete obj[session];
- data[key] = obj;
+ const y = (e, t, r) => {
+ let n = r || l.data;
+ n = i(n);
+ if (!!t) {
+ obj = i(n[e]);
+ delete obj[t];
+ n[e] = obj;
} else {
- delete data[key];
+ delete n[e];
}
- if (!!externalData) {
- externalData = data;
+ if (!!r) {
+ r = n;
}
- return data;
+ return n;
};
- const del = (key, session = "", externalData = null) => {
- let data = {};
- if (externalData || env.isNode) {
- data = delForNode(key, session, externalData);
- if (!externalData) {
- node.fs.writeFileSync("./magic.json", JSON.stringify(data, null, 4));
+ const t = (e, t = "", r = null) => {
+ let n = {};
+ if (r || s.isNode) {
+ n = y(e, t, r);
+ if (!r) {
+ l.fs.writeFileSync("./magic.json", JSON.stringify(n, null, 4));
} else {
- externalData = data;
+ r = n;
}
} else {
- if (!session) {
- if (env.isStorm) {
- return $persistentStore.remove(key);
- } else if (env.isSurgeLike) {
- return $persistentStore.write(null, key);
- } else if (env.isQuanX) {
- return $prefs.removeValueForKey(key);
+ 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 (env.isSurgeLike) {
- data = $persistentStore.read(key);
- } else if (env.isQuanX) {
- data = $prefs.valueForKey(key);
+ if (s.isSurgeLike) {
+ n = $persistentStore.read(e);
+ } else if (s.isQuanX) {
+ n = $prefs.valueForKey(e);
}
- data = convertToObject(data);
- delete data[session];
- const json = JSON.stringify(data, null, 4);
- write(key, json);
+ n = i(n);
+ delete n[t];
+ const o = JSON.stringify(n, null, 4);
+ h(e, o);
}
}
- logger.debug(`DELETE KEY [${key}]${!!session ? `[${session}]` : ""}`);
+ a.debug(`DELETE KEY [${e}]${!!t ? `[${t}]` : ""}`);
};
- const allSessionNames = (key, externalData = null) => {
- let _sessions = [];
- let data = read(key, null, null, true, externalData);
- data = convertToObject(data);
- if (data["magic_session"] !== true) {
- _sessions = [];
+ const r = (e, t = null) => {
+ let r = [];
+ let n = g(e, null, null, true, t);
+ n = i(n);
+ if (n["magic_session"] !== true) {
+ r = [];
} else {
- _sessions = Object.keys(data).filter((key) => key !== "magic_session");
+ r = Object.keys(n).filter((e) => e !== "magic_session");
}
- logger.debug(
- `READ ALL SESSIONS [${key}] <${typeof _sessions}>\n${JSON.stringify(
- _sessions,
- null,
- 4
- )}`
+ a.debug(
+ `READ ALL SESSIONS [${e}] <${typeof r}>\n${JSON.stringify(r, null, 4)}`
);
- return _sessions;
+ return r;
};
- const allSessions = (key, externalData = null) => {
- let _sessions = {};
- let data = read(key, null, null, true, externalData);
- data = convertToObject(data);
- if (data["magic_session"] === true) {
- _sessions = { ...data };
- delete _sessions["magic_session"];
+ const n = (e, t = null) => {
+ let r = {};
+ let n = g(e, null, null, true, t);
+ n = i(n);
+ if (n["magic_session"] === true) {
+ r = { ...n };
+ delete r["magic_session"];
}
- logger.debug(
- `READ ALL SESSIONS [${key}] <${typeof _sessions}>\n${JSON.stringify(
- _sessions,
- null,
- 4
- )}`
+ a.debug(
+ `READ ALL SESSIONS [${e}] <${typeof r}>\n${JSON.stringify(r, null, 4)}`
);
- return _sessions;
+ return r;
};
return {
- read: read,
- write: write,
- del: del,
- update: update,
- allSessions: allSessions,
- allSessionNames: allSessionNames,
- defaultValueComparator: defaultValueComparator,
- convertToObject: convertToObject,
+ read: g,
+ write: h,
+ del: t,
+ update: e,
+ allSessions: n,
+ allSessionNames: r,
+ defaultValueComparator: c,
+ convertToObject: i,
+ };
+}
+function MagicHttp(c, d) {
+ let r;
+ if (c.isNode) {
+ const a = require("axios");
+ r = a.create();
+ }
+ class e {
+ constructor(e = true) {
+ this.handlers = [];
+ this.isRequest = e;
+ }
+ use(e, t, r) {
+ if (typeof e === "function") {
+ d.debug(`Register fulfilled ${e.name}`);
+ }
+ if (typeof t === "function") {
+ d.debug(`Register rejected ${t.name}`);
+ }
+ this.handlers.push({
+ fulfilled: e,
+ rejected: t,
+ synchronous:
+ r && typeof r.synchronous === "boolean" ? 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 o(e) {
+ let r = { ...e };
+ if (!!r.params) {
+ if (!c.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;
+ d.debug(`Params to QueryString: ${r.url}`);
+ }
+ }
+ return r;
+ }
+ const u = (e, t) => {
+ let r =
+ typeof t === "object" ? { headers: {}, ...t } : { url: t, headers: {} };
+ if (!r.method) {
+ r["method"] = e;
+ }
+ r = o(r);
+ if (r["rewrite"] === true) {
+ if (c.isSurge) {
+ r.headers["X-Surge-Skip-Scripting"] = false;
+ delete r["rewrite"];
+ } else if (c.isQuanX) {
+ r["hints"] = false;
+ delete r["rewrite"];
+ }
+ }
+ if (c.isSurgeLike) {
+ const n = r.headers["content-type"] || r.headers["Content-Type"];
+ if (
+ r["method"] !== "GET" &&
+ n &&
+ n.indexOf("application/json") >= 0 &&
+ r.body instanceof Array
+ ) {
+ r.body = JSON.stringify(r.body);
+ d.debug(`Convert Array object to String: ${r.body}`);
+ }
+ } else if (c.isQuanX) {
+ if (r.hasOwnProperty("body") && typeof r["body"] !== "string")
+ r["body"] = JSON.stringify(r["body"]);
+ r["method"] = e;
+ } else if (c.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 f = (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 e.data;
+ return e;
+ } else {
+ return t;
+ }
+ };
+ const t = (r) => {
+ return Object.keys(r).reduce((e, t) => {
+ e[t.toLowerCase()] = r[t];
+ return e;
+ }, {});
+ };
+ const n = (n) => {
+ return Object.keys(n).reduce((e, t) => {
+ const r = t
+ .split("-")
+ .map((e) => e[0].toUpperCase() + e.slice(1))
+ .join("-");
+ e[r] = n[t];
+ return e;
+ }, {});
+ };
+ const g = (e, t = null) => {
+ if (!!e && e.status >= 400) {
+ d.debug(`Raise exception when status code is ${e.status}`);
+ return {
+ name: "RequestException",
+ message: `Request failed with status code ${e.status}`,
+ config: t || e.config,
+ response: e,
+ };
+ }
+ };
+ const i = { request: new e(), response: new e(false) };
+ let p = [];
+ let h = [];
+ let y = true;
+ function $(e) {
+ e = o(e);
+ d.debug(`HTTP ${e["method"].toUpperCase()}:\n${JSON.stringify(e)}`);
+ return e;
+ }
+ function m(e) {
+ try {
+ e = !!e ? f(e) : e;
+ d.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) {
+ d.error(t);
+ return e;
+ }
+ }
+ const _ = (t) => {
+ try {
+ p = [];
+ h = [];
+ i.request.forEach((e) => {
+ if (typeof e.runWhen === "function" && e.runWhen(t) === false) {
+ return;
+ }
+ y = y && e.synchronous;
+ p.unshift(e.fulfilled, e.rejected);
+ });
+ i.response.forEach((e) => {
+ h.push(e.fulfilled, e.rejected);
+ });
+ } catch (e) {
+ d.error(`Failed to register interceptors: ${e}.`);
+ }
+ };
+ const s = (e, n) => {
+ let o;
+ const t = e.toUpperCase();
+ n = u(t, n);
+ if (c.isNode) {
+ o = r;
+ } else {
+ if (c.isSurgeLike) {
+ o = (i) => {
+ return new Promise((n, o) => {
+ $httpClient[e.toLowerCase()](i, (t, r, e) => {
+ if (t) {
+ let e = {
+ name: t.name || t,
+ message: t.message || t,
+ stack: t.stack || t,
+ config: i,
+ response: f(r),
+ };
+ o(e);
+ } else {
+ r.config = i;
+ r.body = e;
+ n(r);
+ }
+ });
+ });
+ };
+ } else {
+ o = (o) => {
+ return new Promise((r, n) => {
+ $task
+ .fetch(o)
+ .then((e) => {
+ e = f(e, o);
+ const t = g(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 ? f(e.response) : null,
+ };
+ n(t);
+ });
+ });
+ };
+ }
+ }
+ let i;
+ _(n);
+ const s = [$, undefined];
+ const a = [m, undefined];
+ if (!y) {
+ d.debug("Interceptors are executed in asynchronous mode");
+ let r = [o, undefined];
+ Array.prototype.unshift.apply(r, s);
+ Array.prototype.unshift.apply(r, p);
+ r = r.concat(a);
+ r = r.concat(h);
+ i = Promise.resolve(n);
+ while (r.length) {
+ try {
+ let e = r.shift();
+ let t = r.shift();
+ if (!c.isNode && n["timeout"] && e === o) {
+ e = l;
+ }
+ if (typeof e === "function") {
+ d.debug(`Executing request fulfilled ${e.name}`);
+ }
+ if (typeof t === "function") {
+ d.debug(`Executing request rejected ${t.name}`);
+ }
+ i = i.then(e, t);
+ } catch (e) {
+ d.error(`request exception: ${e}`);
+ }
+ }
+ return i;
+ } else {
+ d.debug("Interceptors are executed in synchronous mode");
+ Array.prototype.unshift.apply(p, s);
+ p = p.concat([$, undefined]);
+ while (p.length) {
+ let e = p.shift();
+ let t = p.shift();
+ try {
+ if (typeof e === "function") {
+ d.debug(`Executing request fulfilled ${e.name}`);
+ }
+ n = e(n);
+ } catch (e) {
+ if (typeof t === "function") {
+ d.debug(`Executing request rejected ${t.name}`);
+ }
+ t(e);
+ break;
+ }
+ }
+ try {
+ if (!c.isNode && n["timeout"]) {
+ i = l(n);
+ } else {
+ i = o(n);
+ }
+ } catch (e) {
+ return Promise.reject(e);
+ }
+ Array.prototype.unshift.apply(h, a);
+ while (h.length) {
+ i = i.then(h.shift(), h.shift());
+ }
+ return i;
+ }
+ function l(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) {
+ d.error(`Request Timeout exception: ${e}.`);
+ }
+ }
+ };
+ return {
+ request: s,
+ interceptors: i,
+ convertHeadersToLowerCase: t,
+ convertHeadersToCamelCase: n,
+ modifyResponse: f,
+ 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);
+ },
};
}
-// @formatter:on
diff --git a/Scripts/AdBlock/Zhihu/Zhihu.min.js b/Scripts/AdBlock/Zhihu/Zhihu.min.js
new file mode 100644
index 0000000..8fa1c48
--- /dev/null
+++ b/Scripts/AdBlock/Zhihu/Zhihu.min.js
@@ -0,0 +1 @@
+const scriptName="哲也同学";const blockedUsersKey="zhihu_blocked_users";const currentUserInfoKey="zhihu_current_userinfo";const keywordBlockKey="zhihu_keyword_block";const blackAnswersIdKey="zhihu_black_answers";const userCreditScoreKey="zhihu_credit_score";const zheyeServerKey="zheye_server_url";const defaultAnswerBlockedUsers=["会员推荐","盐选推荐"];const keywordMaxCount=1e3;const $=MagicJS(scriptName,"INFO");function getUserInfo(){let t={id:"default",is_vip:false};try{let e=$.data.read(currentUserInfoKey);if(typeof e==="string")e=JSON.parse(e);if(!!e&&e.hasOwnProperty("id")){return e}else{return t}}catch(e){$.logger.error(`获取用户信息出现异常:${e}`);return t}}function modifyAppConfig(){let t=null;try{if(!!$.response.body){let e=JSON.parse($.response.body);e["config"]["homepage_feed_tab"]["tab_infos"]=e["config"]["homepage_feed_tab"]["tab_infos"].filter(e=>{if(e["tab_type"]==="activity_tab"){e["end_time"]=(new Date-12e4).toString().slice(0,10);return true}else{return false}});e["config"]["zvideo_max_number"]=1;e["config"]["is_show_followguide_alert"]=false;delete e["config"]["hp_channel_tab"];if(e["config"]["zombie_conf"]){e["config"]["zombie_conf"]["zombieEnable"]=false}if(e["config"]["gray_mode"]){e["config"]["gray_mode"]["enable"]=false;e["config"]["gray_mode"]["start_time"]="4092566400";e["config"]["gray_mode"]["end_time"]="4092566400"}if(e["config"].hasOwnProperty("zhcnh_thread_sync")){$.logger.debug(JSON.stringify(e["config"]["zhcnh_thread_sync"]));e["config"]["zhcnh_thread_sync"]["LocalDNSSetHostWhiteList"]=[];e["config"]["zhcnh_thread_sync"]["isOpenLocalDNS"]="0";e["config"]["zhcnh_thread_sync"]["ZHBackUpIP_Switch_Open"]="0";e["config"]["zhcnh_thread_sync"]["dns_ip_detector_operation_lock"]="1";e["config"]["zhcnh_thread_sync"]["ZHHTTPSessionManager_setupZHHTTPHeaderField"]="1"}t={body:JSON.stringify(e)}}}catch(e){$.logger.error(`优化软件配置出现异常:${e}`)}return t}function modifyMCloudConfig(){let t=null;try{if(!!$.response.body){let e=JSON.parse($.response.body);if(e.data&&e.data["configs"]){e.data["configs"].forEach(e=>{if(e["configKey"]==="feed_gray_theme"){e["configValue"].start_time="1669824000";e["configValue"].end_time="1669824001";e.status=false}})}const r=JSON.stringify(e);$.logger.debug(r);t={body:r}}}catch(e){$.logger.error(`优化软件配置出现异常:${e}`)}return t}function unlockBlockedKeywords(){let i=null;try{const s=getUserInfo();if($.request.method==="GET"){let e=$.data.read(keywordBlockKey,null,s.id);if(!e){e=[]}let t={"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 r=JSON.stringify({success:true,is_vip:true,kw_min_length:2,kw_max_length:100,kw_max_count:keywordMaxCount,data:e});if($.env.isQuanX){i={body:r,headers:t,status:"HTTP/1.1 200 OK"}}else{i={response:{body:r,headers:t,status:200}}}$.logger.debug(`获取本地脚本屏蔽关键词:\n${e.join("、")}`)}else if($.request.method==="POST"){if(!!$.request.body){let t={"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 r=decodeURIComponent($.request.body).match(/keyword=(.*)/)[1];let n=$.data.read(keywordBlockKey,null,s.id);if(!n){n=[]}let o=false;for(let e=0;e{return e!==t});$.data.write(keywordBlockKey,e,s.id);let r={"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 n=JSON.stringify({success:true});if($.env.isQuanX){i={body:n,headers:r,status:"HTTP/1.1 200 OK"}}else{i={response:{body:n,headers:r,status:200}}}$.logger.debug(`删除本地脚本屏蔽关键词:“${t}”`)}}catch(e){$.logger.debug(`关键词屏蔽操作出现异常:${e}`)}return i}function processUserInfo(){let t=null;try{let e=JSON.parse($.response.body);$.data.write(blackAnswersIdKey,[]);$.logger.debug(`用户登录用户信息,接口响应:${$.response.body}`);if(e&&e["id"]&&e.hasOwnProperty("vip_info")&&e["vip_info"].hasOwnProperty("is_vip")){const r={id:e["id"],is_vip:e["vip_info"]["is_vip"]?e["vip_info"]["is_vip"]!==undefined:false};$.logger.debug(`当前用户id:${e["id"]},是否为VIP:${e["vip_info"]["is_vip"]}`);$.data.write(currentUserInfoKey,r);if($.data.read("zhihu_settings_fake_vip")!==false&&e["vip_info"]["is_vip"]===false){e["vip_info"]["is_vip"]=true;e["vip_info"]["vip_type"]=2;e["vip_info"]["vip_icon"]={url:"https://picx.zhimg.com/v2-aa8a1823abfc46f14136f01d55224925.jpg?source=88ceefae",night_mode_url:"https://picx.zhimg.com/v2-aa8a1823abfc46f14136f01d55224925.jpg?source=88ceefae"};e["vip_info"]["vip_icon_v2"]={url:"https://picx.zhimg.com/v2-aa8a1823abfc46f14136f01d55224925.jpg?source=88ceefae",night_mode_url:"https://picx.zhimg.com/v2-aa8a1823abfc46f14136f01d55224925.jpg?source=88ceefae"};e["vip_info"]["entrance"]={icon:{url:"https://pic3.zhimg.com/v2-5b7012c8c22fd520f5677305e1e551bf.png",night_mode_url:"https://pic4.zhimg.com/v2-e51e3252d7a2cb016a70879defd5da0b.png"},title:"盐选会员 为你严选好内容",expires_day:"2099-12-31",sub_title:null,button_text:"首月 9 元",jump_url:"zhihu://vip/purchase",button_jump_url:"zhihu://vip/purchase",sub_title_new:null,identity:"super_svip"};e["vip_info"]["entrance_new"]={left_button:{title:"精选会员内容",description:"为您严选好内容",jump_url:"zhihu://market/home"},right_button:{title:"开通盐选会员",description:"畅享 10w+ 场优质内容等特权",jump_url:"zhihu://vip/purchase"}};e["vip_info"]["entrance_v2"]={title:"我的超级盐选会员",sub_title:"畅享 5000W+ 优质内容",jump_url:"zhihu://market/home",button_text:"查看会员",sub_title_color:"#F8E2C4",sub_title_list:["畅享 5000W+ 优质内容"],card_jump_url:"zhihu://market/home"};$.logger.debug("设置用户为本地盐选会员");t={body:JSON.stringify(e)}}}else{$.logger.warning(`没有获取到本次登录用户信息,如未对功能造成影响,请忽略此日志。`)}}catch(e){$.logger.error(`获取当前用户信息出现异常:${e}`)}return t}function manageBlackUser(){const r=getUserInfo();let t={};let n=$.data.read(blockedUsersKey,"",r.id);n=typeof n==="object"&&!!n?n:{};defaultAnswerBlockedUsers.forEach(e=>{n[e]="00000000000000000000000000000000";t[e]="00000000000000000000000000000000"});$.logger.debug(`当前用户id:${r.id},脚本黑名单:${JSON.stringify(n)}`);if($.request.method==="GET"){try{if($.request.url.indexOf("offset")<0){n=t;$.logger.debug("脚本黑名单已清空,请滑动至黑名单末尾保证重新获取完成。");$.notification.post("开始同步黑名单数据,请滑动至黑名单末尾,直至弹出“同步成功”的通知。")}let e=JSON.parse($.response.body);if(!!e["data"]){$.logger.debug(`本次滑动获取的黑名单信息:${JSON.stringify(e["data"])}`);e["data"].forEach(e=>{if(e["name"]!=="[已重置]"){n[e["name"]]=e["id"]}});$.data.write(blockedUsersKey,n,r.id);if(e["paging"]["is_end"]===true){$.notification.post(`同步黑名单数据成功!当前黑名单共${Object.keys(n).length-defaultAnswerBlockedUsers.length}人。\n脚本内置黑名单${defaultAnswerBlockedUsers.length}人。`);$.logger.debug(`脚本黑名单内容:${JSON.stringify(n)}。`)}}else{$.logger.warning(`获取黑名单失败,接口响应不合法:${$.response.body}`)}}catch(e){$.data.del(blockedUsersKey);$.logger.error(`获取黑名单失败,异常信息:${e}`);$.notification.post("获取黑名单失败,执行异常,已清空黑名单。")}}else if($.request.method==="POST"){try{let e=JSON.parse($.response.body);if(e.hasOwnProperty("name")&&e.hasOwnProperty("id")){$.logger.debug(`当前需要加入黑名单的用户Id:${e["id"]},用户名:${e["name"]}`);if(e["id"]){n[e["name"]]=e["id"];$.data.write(blockedUsersKey,n,r.id);$.logger.debug(`${e["name"]}写入脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify(n)}`);$.notification.post(`已将用户“${e["name"]}”写入脚本黑名单。`)}else{$.logger.error(`${e["name"]}写入脚本黑名单失败,没有获取到用户Id。`);$.notification.post(`将用户“${e["name"]}”写入脚本黑名单失败!`)}}else{$.logger.warning(`写入黑名单失败,接口响应不合法:${$.response.body}`);$.notification.post("写入脚本黑名单失败,接口返回不合法。")}}catch(e){$.logger.error(`写入黑名单失败,异常信息:${e}`);$.notification.post("写入脚本黑名单失败,执行异常,请查阅日志。")}}else if($.request.method==="DELETE"){try{let e=JSON.parse($.response.body);if(e.success){let t=$.request.url.match(/^https?:\/\/api\.zhihu\.com\/settings\/blocked_users\/([0-9a-zA-Z]*)/)[1];if(t){$.logger.debug(`当前需要移出黑名单的用户Id:${t}`);for(let e in n){if(n[e]===t){delete n[e];$.data.write(blockedUsersKey,n,r.id);$.logger.debug(`${e}移出脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify(n)}`);$.notification.post(`已将用户“${e}”移出脚本黑名单!`);break}}}else{$.logger.error("将用户移出脚本黑名单失败!\n建议从设置中刷新黑名单数据。");$.notification.post(`将用户移出脚本黑名单失败,没有获取到用户Id。\n建议从设置中刷新黑名单数据。`)}}else{$.logger.warning(`移出黑名单失败,接口响应不合法:${$.response.body}`);$.notification.post("移出脚本黑名单失败,接口返回不合法。")}}catch(e){$.logger.error(`移出黑名单失败,异常信息:${e}`);$.notification.post("移出脚本黑名单失败,执行异常,请查阅日志。")}}}function autoInsertBlackList(){let e=null;try{let t=JSON.parse($.response.body);delete t["mcn_user_info"];e={body:JSON.stringify(t)};if(t.name&&t.id&&t["is_blocking"]===true){const r=getUserInfo();let e=$.data.read(blockedUsersKey,"",r.id);e=typeof e==="object"&&!!e?e:{};if(!e[t.name]){$.logger.debug(`当前需要加入黑名单的用户Id:${t["id"]},用户名:${t["name"]}`);e[t["name"]]=t["id"];$.data.write(blockedUsersKey,e,r.id);$.logger.debug(`${t["name"]}写入脚本黑名单成功,当前脚本黑名单数据:${JSON.stringify(e)}`);$.notification.post(`已自动将用户“${t["name"]}”写入脚本黑名单。`)}}}catch(e){$.logger.error(`去除MCN信息出现异常:${e}`)}return e}function removeMoments(){let r=null;try{let e=JSON.parse($.response.body.replace(/(\w+"+\s?):\s?(\d{15,})/g,'$1:"$2"'));const n=getUserInfo();let i=$.data.read(blockedUsersKey,"",n.id);i=!!i?i:{};let t;const s=$.data.read("zhihu_settings_moments_stream",false);const a=$.data.read("zhihu_settings_moments_recommend",false);const l=$.data.read("zhihu_settings_moments_activity",false);const c=$.data.read("zhihu_settings_blocked_users",false);t=e.data.filter(e=>{const t=c&&e.target&&e.target["origin_pin"]&&e.target["origin_pin"].author&&typeof i[e.target["origin_pin"].author.name]!="undefined";const r=s&&e["target_type"]==="zvideo";const n=a&&e.type==="recommend_user_card_list";const o=l&&e.type==="message_activity_card";return!(t||r||n||o)});e["data"]=t;r={body:JSON.stringify(e)}}catch(e){$.logger.error(`关注列表去广告出现异常:${e}`)}return r}function _setRecommendTag(e,t,r="GBK02A"){if(!e["common_card"]["footline"]){e["common_card"]["footline"]={elements:[]}}e["common_card"]["footline"]["elements"].unshift({tag:{text:t,color:r,type:"MASK_ROUNDED_RECTANGLE"}})}async function _checkPaidContentByCloud(e,n){const t=$.data.read(zheyeServerKey);if(!t){$.notification.post("未设置服务端地址,无法进行付费/推广内容探测。\n请配置服务端地址,或使用本地探测。")}else{$.logger.debug(`向云端请求以下链接\n${e.join("\n")}`);const r=`${t}/api/v1/answer/links`;$.logger.debug(`服务端地址\n${r}`);await $.http.post({url:r,headers:{"Content-Type":"application/json"},body:e}).then(r=>{$.logger.debug(`云端探测结果<${typeof r.body}>\n${JSON.stringify(r.body)}`);for(let t=0;t{$.logger.error(`云端请求出现异常\n${JSON.stringify(e)}`)})}}async function _checkPaidContentByLocal(n,o){$.logger.debug(`将在本地请求以下链接\n${n.join("\n")}`);let t=[];function r(t){return new Promise(r=>{const e=n[t];if(!e||e===""||!e.startsWith("https://www.zhihu.com/appview/v2/answer")){r("")}else{$.http.get({url:n[t],timeout:1e3}).then(e=>{const t=e.body;if((t.indexOf("查看完整内容")>=0||t.indexOf("查看全部章节")>=0)&&t.indexOf("paid")>=0){r("付费内容")}else if(t.indexOf("ad-link-card")>=0||t.indexOf("xg.zhihu.com")>=0||t.indexOf("营销平台")>=0){r("营销推广")}else if(t.indexOf("mcn-link-card")>=0){r("购物推广")}else{r("")}}).catch(e=>{$.logger.error(`本地请求出现异常\n${JSON.stringify(e)}`);r("")})}})}for(let e=0;e{$.logger.debug(`本地探测结果<${r.length}>\n${JSON.stringify(r)}`);for(let t=0;t{const e=JSON.stringify(o);const t=o["card_type"]==="slot_event_card"||o["card_type"]==="slot_video_event_card"||o.hasOwnProperty("ad")||o["brief"]&&o["brief"].indexOf("slot_card")>=0||o["extra"]&&o["extra"]["type"]==="Training";const r=t!==true&&e.search(/"(type|style)+"\s?:\s?"(drama|zvideo|Video|BIG_IMAGE)+"/i)>=0;const n=r&&p;const i=r!==true&&e.search(/"(type|style)+"\s?:\s?"pin"/i)>=0;const s=i&&g;const a=e.search(/"(type|style)+"\s?:\s?"article"/i)>=0;const l=a&&h;let c=false;if(r!==true&&m){for(let n=0;n=0){if($.isDebug){let e=o["common_card"]["feed_content"]["title"]["panel_text"];let t=o["common_card"]["feed_content"]["content"]["panel_text"];let r="";try{r=o["common_card"]["feed_content"]["title"]["action"]["intent_url"]}catch{}$.logger.debug(`匹配关键字:\n${u[n]}\n标题:\n${e}\n内容:\n${t}`);$.notification.debug(scriptName,`关键字:${u[n]}`,`${e}\n${t}`,r)}c=true;break}}}let d;try{d=c!==true&&y&&f&&o["common_card"]["feed_content"]["source_line"]["elements"][1]["text"]["panel_text"]in f}catch{d=false}return!(t||s||l||n||c||d)};let e=JSON.parse($.response.body.replace(/(\w+"+\s?):\s?(\d{15,})/g,'$1:"$2"'));let n=e["data"].filter(s);if(r===true){let r=[];for(let t=0;t0&&o==="cloud"){await _checkPaidContentByCloud(r,n)}else if(r.length>0&&o==="local"){await _checkPaidContentByLocal(r,n)}}e["data"]=n;t={body:JSON.stringify(e)}}catch(e){$.logger.error(`推荐列表去广告出现异常:${e}`)}return t}function removeQuestions(){let t=null;try{const r=getUserInfo();let n=$.data.read(blockedUsersKey,"",r.id);n=!!n?n:{};let e=JSON.parse($.response.body);const i=$.data.read("zhihu_settings_blocked_users",false);$.logger.debug(`当前黑名单列表: ${JSON.stringify(n)}`);let o=$.data.read(blackAnswersIdKey,[]);delete e["ad_info"];if(e["data"]){let r=[];for(let t of e.data){let e="";const a=t.target.id.toString();try{if("target"in t){e=t["target"]["author"]["name"]}}catch(e){$.logger.error(`获取回答列表用户名出现异常:${e}`)}const l=typeof n[e]!="undefined";const c=i&&l;if("target"in t){t["target"]["visible_only_to_author"]=false;t["target"]["is_visible"]=true;t["target"]["is_copyable"]=true}if(!c){r.push(t)}else if(c===true&&o.includes(a)===false){o.push(a);$.notification.debug(`记录黑名单用户${e}的回答Id:${a}`)}}e.data=r}$.data.write(blackAnswersIdKey,o);const s=JSON.stringify(e);$.logger.debug(`修改后的回答列表数据:${s}`);t={body:s}}catch(e){$.logger.error(`回答列表去广告出现异常:${e}`)}return t}function modifyAnswer(){let r=null;try{let e=$.response.body;let t="";if((e.indexOf("查看完整内容")>=0||e.indexOf("查看全部章节")>=0)&&e.indexOf("paid")>=0){t=''}else if(e.indexOf("ad-link-card")>=0||e.indexOf("xg.zhihu.com")>=0||e.indexOf("营销平台")>=0){t=''}else if(e.indexOf("mcn-link-card")>=0){t=''}else if(Math.floor(Math.random()*200)===7){t=''}if(t!==""){const n=e.match(/(richText[^<]*>)(.)/)[1];const o=e.lastIndexOf(n)+n.length;r={body:e.slice(0,o)+t+e.slice(o)}}}catch(e){$.logger.error(`付费内容提醒出现异常:${e}`)}return r}function removeComment(){let e=null;try{if(!!$.response.body){let t=JSON.parse($.response.body);t["ad_info"]={};if($.data.read("zhihu_settings_blocked_users",false)===true){let e=getUserInfo();let s=$.data.read(blockedUsersKey,"",e.id);s=!!s?s:{};let a=[];let l={};if(typeof t.root!="undefined"){const n=t.root.author.name;const o=typeof s[n]!="undefined";if(o===true){t.root.is_delete=true;t.root.can_reply=false;t.root.can_like=false;t.root.author.name="黑名单用户";t.root.author.avatar_url="https://picx.zhimg.com/v2-abed1a8c04700ba7d72b45195223e0ff_xll.jpg"}}if(typeof t.data!="undefined"){t.data.forEach(e=>{const t=e.author.name;let r="";if(e["reply_to_author"]&&e["reply_to_author"].name){r=e["reply_to_author"].name}const n=r!=="";const o=typeof s[t]!="undefined";const i=typeof s[r]!="undefined";if(o===true||i===true){if(o&&!n&&$.request.url.indexOf("root_comment")>0){$.notification.debug(`屏蔽黑名单用户“${t}”的主评论。`)}else if(!o&&n&&!i&&$.request.url.indexOf("child_comment")>0){$.notification.debug(`屏蔽黑名单用户“${t}”的子评论。`)}else if(o&&!i&&$.request.url.indexOf("child_comment")>0){$.notification.debug(`屏蔽黑名单用户“${t}”回复“${r}”的子评论。`)}else if(o&&i&&$.request.url.indexOf("child_comment")>0){$.notification.debug(`屏蔽黑名单用户“${t}”回复黑名单用户“${r}”的子评论。`)}l[e.id]=t;if(o){e.is_delete=true;e.can_reply=false;e.can_like=false;e.author.exposed_medal={};e.author.name="[黑名单用户]";e.author.avatar_url="https://picx.zhimg.com/v2-abed1a8c04700ba7d72b45195223e0ff_xll.jpg"}if(i){e["reply_to_author"].name="[黑名单用户]";e["reply_to_author"].exposed_medal={};e["reply_to_author"].avatar_url="https://picx.zhimg.com/v2-abed1a8c04700ba7d72b45195223e0ff_xll.jpg"}}if(e.child_comments){let i=[];e.child_comments.forEach(e=>{const t=e.author.name;const r=typeof e["reply_to_author"]!="undefined"?e["reply_to_author"].name:"";const n=typeof s[t]!="undefined";const o=typeof s[r]!="undefined";if(n||o){if(n===true){$.notification.debug(`屏蔽黑名单用户“${t}”的子评论。`);l[e.id]=t;e.is_delete=true;e.can_reply=false;e.can_like=false;e.author.name="[黑名单用户]";e.author.exposed_medal={};e.author.avatar_url="https://picx.zhimg.com/v2-abed1a8c04700ba7d72b45195223e0ff_xll.jpg"}if(o===true){$.logger.debug(`修改前的子评论数据:\n${JSON.stringify(e)}`);e["reply_to_author"].name="[黑名单用户]";e["reply_to_author"].exposed_medal={};e["reply_to_author"].avatar_url="https://picx.zhimg.com/v2-abed1a8c04700ba7d72b45195223e0ff_xll.jpg";$.notification.debug(`隐藏“${t}”回复黑名单用户“${r}”的名称与头像。`);$.logger.debug(`修改后的子评论数据:\n${JSON.stringify(e)}`)}}i.push(e)});e.child_comments=i}a.push(e)})}t.data=a}const r=JSON.stringify(t);$.logger.debug(`过滤后的评论数据:\n${r}`);e={body:r}}}catch(e){$.logger.error(`去除评论广告出现异常:${e}`)}return e}function removeArticleAd(){let t=null;try{if(!!$.response.body){let e=JSON.parse($.response.body);e["ad_info"]={};const r=JSON.stringify(e);$.logger.debug(`过滤后的文章数据:\n${r}`);t={body:r}}}catch(e){$.logger.error(`去除文章广告出现异常:${e}`)}return t}function removeMarketingMsg(){let t=null;try{let e=JSON.parse($.response.body);let r=[];for(let t of e["data"]){if(t["detail_title"]==="官方帐号消息"){let e=t["unread_count"];if(e>0){t["content"]["text"]="未读消息"+e+"条"}else{t["content"]["text"]="全部消息已读"}t["is_read"]=true;t["unread_count"]=0;r.push(t)}else if(t["detail_title"]!=="活动助手"){r.push(t)}}e["data"]=r;t={body:JSON.stringify(e)}}catch(e){$.logger.error(`屏蔽官方营销消息出现异常:${e}`)}return t}function removeHotListAds(){let t=null;try{if(!!$.response.body){let e=JSON.parse($.response.body);if("data"in e){e["data"]=e["data"].filter(e=>{return e["type"]==="hot_list_feed"||e["type"]==="hot_list_feed_video"})}t={body:JSON.stringify(e)}}}catch(e){$.logger.error(`去除热榜广告出现异常:${e}`)}return t}function removeKeywordAds(){let t=null;try{if(!!$.response.body){$.logger.debug(`预置关键字返回:${$.response.body}`);let e=JSON.parse($.response.body);if(e.hasOwnProperty("preset_words")&&e["preset_words"]["words"]){e["preset_words"]["words"]=e["preset_words"]["words"].filter(e=>{return e["type"]!=="ad"});t={body:JSON.stringify(e)}}}}catch(e){$.logger.error(`去除预置关键字广告出现异常:${e}`)}return t}function removeNextBlackUserAnswer(){let t=null;try{if(!!$.response.body){let e=JSON.parse($.response.body);const n=$.data.read(blackAnswersIdKey,[]);if(n.length>0){let r=[];e.data.forEach(e=>{const t=n.includes(e.id.toString());if(t===false){e.ad_info={data:""};r.push(e)}else{$.notification.debug(`屏蔽翻页过程中出现的黑名单用户回答Id:${e.id}`)}});for(let e=0;e{e["ad_info"]={data:""};const t=typeof r[e.data.author.name]!="undefined";$.logger.debug(`用户${e.data.author.name}是否在黑名单中:${t}`);if($.data.read("zhihu_settings_blocked_users",false)===false||t===false){n.push(e)}});e.data.data=n;o={body:JSON.stringify(e)}}}catch(e){$.logger.error(`屏蔽回答信息流黑名单用户及广告:${e}`)}return o}function changeUserCredit(){$.notification.debug("开始修改用户盐值");let t=null;try{if(!!$.response.body){const r=parseInt($.data.read(userCreditScoreKey,780));$.logger.debug(`准备修改用户盐值为${r}`);let e=JSON.parse($.response.body);if(e["credit_basis"].total_score{let e=null;if($.isResponse){switch(true){case/^https:\/\/api\.zhihu\.com\/people\/self$/.test($.request.url):e=processUserInfo();break;case $.data.read("zhihu_settings_app_conf",false)===true&&/^https?:\/\/appcloud2\.zhihu\.com\/v\d+\/config/.test($.request.url):e=modifyAppConfig();break;case $.data.read("zhihu_settings_app_conf",false)===true&&/^https?:\/\/m-cloud\.zhihu\.com\/api\/cloud\/config\/all\?/.test($.request.url):e=modifyMCloudConfig();break;case/^https?:\/\/api\.zhihu\.com\/user-credit\/basis/.test($.request.url):e=changeUserCredit();break;case/^https:\/\/api\.zhihu\.com\/topstory\/recommend/.test($.request.url):e=await removeRecommend();break;case/^https?:\/\/api\.zhihu\.com\/(v4\/)?questions\/\d+/.test($.request.url):e=removeQuestions();break;case/^https?:\/\/api\.zhihu\.com\/next-data\?/.test($.request.url):e=modifyAnswersNextData();break;case $.data.read("zhihu_settings_sys_msg",true)!==false&&/^https?:\/\/api\.zhihu\.com\/notifications\/v3\/message/.test($.request.url):e=removeMarketingMsg();break;case/^https?:\/\/api\.zhihu\.com\/comment_v5\/(answers|pins|comments?|articles)\/\d+\/(root|child)_comment/.test($.request.url):e=removeComment();break;case/^https?:\/\/www\.zhihu\.com\/api\/v\d\/articles\/\d+\/recommendation\?/.test($.request.url):e=removeArticleAd();break;case/^https?:\/\/www\.zhihu\.com\/api\/v4\/comment_v5\/answers\/\d+\/abstract_comment\?/.test($.request.url):e=removeComment();break;case $.data.read("zhihu_settings_answer_tip",true)===true&&/^https?:\/\/www\.zhihu\.com\/appview\/v2\/answer\/.*(entry=(?!(preload-topstory|preload-search|preload-subscription)))?/.test($.request.url):e=modifyAnswer();break;case $.data.read("zhihu_settings_blocked_users",false)!==false&&/^https?:\/\/api\.zhihu\.com\/next\?/.test($.request.url):e=removeNextBlackUserAnswer();break;case $.data.read("zhihu_settings_blocked_users",true)===true&&/^https?:\/\/api\.zhihu\.com\/people\/((?!self).)*$/.test($.request.url):e=autoInsertBlackList();break;case/^https?:\/\/api\.zhihu\.com\/moments_v3\?/.test($.request.url):e=removeMoments();break;case $.data.read("zhihu_settings_hot_list",true)===true&&/^https?:\/\/api\.zhihu\.com\/topstory\/hot-lists(\?|\/)/.test($.request.url):e=removeHotListAds();break;case $.data.read("zhihu_settings_preset_words",true)===true&&/^https?:\/\/api\.zhihu\.com\/search\/preset_words\?/.test($.request.url):e=removeKeywordAds();break;case $.data.read("zhihu_settings_blocked_users",false)!==false&&/^https?:\/\/api\.zhihu\.com\/settings\/blocked_users/.test($.request.url):manageBlackUser();break;default:$.logger.debug("没有匹配到任何请求,请确认配置正确。");break}}else if($.isRequest){if($.data.read("zhihu_settings_blocked_keywords",false)!==false&&/^https?:\/\/api\.zhihu\.com\/feed-root\/block/.test($.request.url)===true){e=unlockBlockedKeywords(e)}}else{$.data.del(currentUserInfoKey);$.data.del(blockedUsersKey);$.data.del(keywordBlockKey);$.notification.post("哲也同学数据清理完毕")}if(e){$.done(e)}else{$.done()}})();function MagicJS(e="MagicJS",t="INFO"){const n=()=>{const e=typeof $loon!=="undefined";const t=typeof $task!=="undefined";const r=typeof module!=="undefined";const n=typeof $httpClient!=="undefined"&&!e;const o=typeof $storm!=="undefined";const i=typeof $environment!=="undefined"&&typeof $environment["stash-build"]!=="undefined";const s=n||e||o||i;const a=typeof importModule!=="undefined";return{isLoon:e,isQuanX:t,isNode:r,isSurge:n,isStorm:o,isStash:i,isSurgeLike:s,isScriptable:a,get name(){if(e){return"Loon"}else if(t){return"QuantumultX"}else if(r){return"NodeJS"}else if(n){return"Surge"}else if(a){return"Scriptable"}else{return"unknown"}},get build(){if(n){return $environment["surge-build"]}else if(i){return $environment["stash-build"]}else if(o){return $storm.buildVersion}},get language(){if(n||i){return $environment["language"]}},get version(){if(n){return $environment["surge-version"]}else if(i){return $environment["stash-version"]}else if(o){return $storm.appVersion}else if(r){return process.version}},get system(){if(n){return $environment["system"]}else if(r){return process.platform}},get systemVersion(){if(o){return $storm.systemVersion}},get deviceName(){if(o){return $storm.deviceName}}}};const o=(r,e="INFO")=>{let n=e;const o={SNIFFER:6,DEBUG:5,INFO:4,NOTIFY:3,WARNING:2,ERROR:1,CRITICAL:0,NONE:-1};const i={SNIFFER:"",DEBUG:"",INFO:"",NOTIFY:"",WARNING:"❗ ",ERROR:"❌ ",CRITICAL:"❌ ",NONE:""};const t=(e,t="INFO")=>{if(!(o[n]{n=e};return{getLevel:()=>{return n},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=n();this.logger=o(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 r=this.data.read("magic_bark_url");if(e){this.logger.setLevel(e.toUpperCase())}if(r){this.notification.setBark(r)}}}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 MagicNotification(i,s,a,l){let c=null;let d=null;const e=t=>{try{let e=t.replace(/\/+$/g,"");c=`${/^https?:\/\/([^/]*)/.exec(e)[0]}/push`;d=/\/([^\/]+)\/?$/.exec(e)[1]}catch(e){a.error(`Bark url error: ${e}.`)}};function t(e=i,t="",r="",n=""){const o=r=>{try{let t={};if(typeof r==="string"){if(s.isLoon)t={openUrl:r};else if(s.isQuanX)t={"open-url":r};else if(s.isSurge)t={url:r}}else if(typeof r==="object"){if(s.isLoon){t["openUrl"]=!!r["open-url"]?r["open-url"]:"";t["mediaUrl"]=!!r["media-url"]?r["media-url"]:""}else if(s.isQuanX){t=!!r["open-url"]||!!r["media-url"]?r:{}}else if(s.isSurge){let e=r["open-url"]||r["openUrl"];t=e?{url:e}:{}}}return t}catch(e){a.error(`通知选项转换失败${e}`)}return r};n=o(n);if(arguments.length===1){e=i;t="",r=arguments[0]}a.notify(`title:${e}\nsubTitle:${t}\nbody:${r}\noptions:${typeof n==="object"?JSON.stringify(n):n}`);if(s.isSurge){$notification.post(e,t,r,n)}else if(s.isLoon){if(!!n)$notification.post(e,t,r,n);else $notification.post(e,t,r)}else if(s.isQuanX){$notify(e,t,r,n)}if(c&&d){u(e,t,r)}}function r(e=i,t="",r="",n=""){if(a.getLevel()==="DEBUG"){if(arguments.length===1){e=i;t="";r=arguments[0]}this.post(e,t,r,n)}}function u(e=i,t="",r="",n=""){if(typeof l==="undefined"||typeof l.post==="undefined"){throw"Bark notification needs to import MagicHttp module."}let o={url:c,headers:{"content-type":"application/json; charset=utf-8"},body:{title:e,body:t?`${t}\n${r}`:r,device_key:d}};l.post(o).catch(e=>{a.error(`Bark notify error: ${e}`)})}return{post:t,debug:r,bark:u,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 c=(e,t)=>{if(typeof t==="object"){return false}else{return e===t}};const d=e=>{if(e==="true"){return true}else if(e==="false"){return false}else if(typeof e==="undefined"){return null}else{return e}};const u=(e,t,r,n)=>{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(n===false&&!!e&&e["magic_session"]===true){e=null}if((e===null||typeof e==="undefined")&&t!==null&&typeof t!=="undefined"){e=t}e=d(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 f=(e,t=null,r="",n=false,o=null)=>{let i=o||l.data;if(!!i&&typeof i[e]!=="undefined"&&i[e]!==null){val=i[e]}else{val=!!r?{}:null}val=u(val,t,r,n);return val};const g=(e,t=null,r="",n=false,o=null)=>{let i="";if(o||s.isNode){i=f(e,t,r,n,o)}else{if(s.isSurgeLike){i=$persistentStore.read(e)}else if(s.isQuanX){i=$prefs.valueForKey(e)}i=u(i,t,r,n)}a.debug(`READ DATA [${e}]${!!r?`[${r}]`:""} <${typeof i}>\n${JSON.stringify(i)}`);return i};const p=(t,r,n="",e=null)=>{let o=e||l.data;o=i(o);if(!!n){let e=i(o[t]);e["magic_session"]=true;e[n]=r;o[t]=e}else{o[t]=r}if(e!==null){e=o}return o};const h=(e,t,r="",n=null)=>{if(typeof t==="undefined"||t!==t){return false}if(!s.isNode&&(typeof t==="boolean"||typeof t==="number")){t=String(t)}let o="";if(n||s.isNode){o=p(e,t,r,n)}else{if(!r){o=t}else{if(s.isSurgeLike){o=!!$persistentStore.read(e)?$persistentStore.read(e):o}else if(s.isQuanX){o=!!$prefs.valueForKey(e)?$prefs.valueForKey(e):o}o=i(o);o["magic_session"]=true;o[r]=t}}if(!!o&&typeof o==="object"){o=JSON.stringify(o,null,4)}a.debug(`WRITE DATA [${e}]${r?`[${r}]`:""} <${typeof t}>\n${JSON.stringify(t)}`);if(!n){if(s.isSurgeLike){return $persistentStore.write(o,e)}else if(s.isQuanX){return $prefs.setValueForKey(o,e)}else if(s.isNode){try{l.fs.writeFileSync("./magic.json",o);return true}catch(e){a.error(e);return false}}}return true};const e=(t,r,n,o=c,i=null)=>{r=d(r);const e=g(t,null,n,false,i);if(o(e,r)===true){return false}else{const s=h(t,r,n,i);let e=g(t,null,n,false,i);if(o===c&&typeof e==="object"){return s}return o(r,e)}};const y=(e,t,r)=>{let n=r||l.data;n=i(n);if(!!t){obj=i(n[e]);delete obj[t];n[e]=obj}else{delete n[e]}if(!!r){r=n}return n};const t=(e,t="",r=null)=>{let n={};if(r||s.isNode){n=y(e,t,r);if(!r){l.fs.writeFileSync("./magic.json",JSON.stringify(n,null,4))}else{r=n}}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){n=$persistentStore.read(e)}else if(s.isQuanX){n=$prefs.valueForKey(e)}n=i(n);delete n[t];const o=JSON.stringify(n,null,4);h(e,o)}}a.debug(`DELETE KEY [${e}]${!!t?`[${t}]`:""}`)};const r=(e,t=null)=>{let r=[];let n=g(e,null,null,true,t);n=i(n);if(n["magic_session"]!==true){r=[]}else{r=Object.keys(n).filter(e=>e!=="magic_session")}a.debug(`READ ALL SESSIONS [${e}] <${typeof r}>\n${JSON.stringify(r,null,4)}`);return r};const n=(e,t=null)=>{let r={};let n=g(e,null,null,true,t);n=i(n);if(n["magic_session"]===true){r={...n};delete r["magic_session"]}a.debug(`READ ALL SESSIONS [${e}] <${typeof r}>\n${JSON.stringify(r,null,4)}`);return r};return{read:g,write:h,del:t,update:e,allSessions:n,allSessionNames:r,defaultValueComparator:c,convertToObject:i}}function MagicHttp(c,d){let r;if(c.isNode){const a=require("axios");r=a.create()}class e{constructor(e=true){this.handlers=[];this.isRequest=e}use(e,t,r){if(typeof e==="function"){d.debug(`Register fulfilled ${e.name}`)}if(typeof t==="function"){d.debug(`Register rejected ${t.name}`)}this.handlers.push({fulfilled:e,rejected:t,synchronous:r&&typeof r.synchronous==="boolean"?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 o(e){let r={...e};if(!!r.params){if(!c.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;d.debug(`Params to QueryString: ${r.url}`)}}return r}const u=(e,t)=>{let r=typeof t==="object"?{headers:{},...t}:{url:t,headers:{}};if(!r.method){r["method"]=e}r=o(r);if(r["rewrite"]===true){if(c.isSurge){r.headers["X-Surge-Skip-Scripting"]=false;delete r["rewrite"]}else if(c.isQuanX){r["hints"]=false;delete r["rewrite"]}}if(c.isSurgeLike){const n=r.headers["content-type"]||r.headers["Content-Type"];if(r["method"]!=="GET"&&n&&n.indexOf("application/json")>=0&&r.body instanceof Array){r.body=JSON.stringify(r.body);d.debug(`Convert Array object to String: ${r.body}`)}}else if(c.isQuanX){if(r.hasOwnProperty("body")&&typeof r["body"]!=="string")r["body"]=JSON.stringify(r["body"]);r["method"]=e}else if(c.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 f=(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 e.data;return e}else{return t}};const t=r=>{return Object.keys(r).reduce((e,t)=>{e[t.toLowerCase()]=r[t];return e},{})};const n=n=>{return Object.keys(n).reduce((e,t)=>{const r=t.split("-").map(e=>e[0].toUpperCase()+e.slice(1)).join("-");e[r]=n[t];return e},{})};const g=(e,t=null)=>{if(!!e&&e.status>=400){d.debug(`Raise exception when status code is ${e.status}`);return{name:"RequestException",message:`Request failed with status code ${e.status}`,config:t||e.config,response:e}}};const i={request:new e,response:new e(false)};let p=[];let h=[];let y=true;function $(e){e=o(e);d.debug(`HTTP ${e["method"].toUpperCase()}:\n${JSON.stringify(e)}`);return e}function m(e){try{e=!!e?f(e):e;d.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){d.error(t);return e}}const _=t=>{try{p=[];h=[];i.request.forEach(e=>{if(typeof e.runWhen==="function"&&e.runWhen(t)===false){return}y=y&&e.synchronous;p.unshift(e.fulfilled,e.rejected)});i.response.forEach(e=>{h.push(e.fulfilled,e.rejected)})}catch(e){d.error(`Failed to register interceptors: ${e}.`)}};const s=(e,n)=>{let o;const t=e.toUpperCase();n=u(t,n);if(c.isNode){o=r}else{if(c.isSurgeLike){o=i=>{return new Promise((n,o)=>{$httpClient[e.toLowerCase()](i,(t,r,e)=>{if(t){let e={name:t.name||t,message:t.message||t,stack:t.stack||t,config:i,response:f(r)};o(e)}else{r.config=i;r.body=e;n(r)}})})}}else{o=o=>{return new Promise((r,n)=>{$task.fetch(o).then(e=>{e=f(e,o);const t=g(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?f(e.response):null};n(t)})})}}}let i;_(n);const s=[$,undefined];const a=[m,undefined];if(!y){d.debug("Interceptors are executed in asynchronous mode");let r=[o,undefined];Array.prototype.unshift.apply(r,s);Array.prototype.unshift.apply(r,p);r=r.concat(a);r=r.concat(h);i=Promise.resolve(n);while(r.length){try{let e=r.shift();let t=r.shift();if(!c.isNode&&n["timeout"]&&e===o){e=l}if(typeof e==="function"){d.debug(`Executing request fulfilled ${e.name}`)}if(typeof t==="function"){d.debug(`Executing request rejected ${t.name}`)}i=i.then(e,t)}catch(e){d.error(`request exception: ${e}`)}}return i}else{d.debug("Interceptors are executed in synchronous mode");Array.prototype.unshift.apply(p,s);p=p.concat([$,undefined]);while(p.length){let e=p.shift();let t=p.shift();try{if(typeof e==="function"){d.debug(`Executing request fulfilled ${e.name}`)}n=e(n)}catch(e){if(typeof t==="function"){d.debug(`Executing request rejected ${t.name}`)}t(e);break}}try{if(!c.isNode&&n["timeout"]){i=l(n)}else{i=o(n)}}catch(e){return Promise.reject(e)}Array.prototype.unshift.apply(h,a);while(h.length){i=i.then(h.shift(),h.shift())}return i}function l(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){d.error(`Request Timeout exception: ${e}.`)}}};return{request:s,interceptors:i,convertHeadersToLowerCase:t,convertHeadersToCamelCase:n,modifyResponse:f,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)}}}
\ No newline at end of file
diff --git a/Scripts/AdBlock/Zhihu/Zhihu_dep.js b/Scripts/AdBlock/Zhihu/Zhihu_dep.js
new file mode 100644
index 0000000..16da55c
--- /dev/null
+++ b/Scripts/AdBlock/Zhihu/Zhihu_dep.js
@@ -0,0 +1,1794 @@
+const scriptName = "哲也同学";
+const blockedUsersKey = "zhihu_blocked_users";
+const currentUserInfoKey = "zhihu_current_userinfo";
+const keywordBlockKey = "zhihu_keyword_block";
+const blackAnswersIdKey = "zhihu_black_answers";
+const userCreditScore = "zhihu_credit_score";
+// 默认屏蔽推荐列表的用户,通常不是真实用户,无法通过加入黑名单屏蔽
+const defaultAnswerBlockedUsers = ["会员推荐", "盐选推荐"];
+const keywordMaxCount = 1000; // 允许设置的关键词数量
+const $ = MagicJS(scriptName, "INFO");
+
+/**
+ * @description: 获取用户信息
+ * @return {*}
+ */
+function getUserInfo() {
+ let defaultUserInfo = { id: "default", is_vip: false };
+ try {
+ let 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;
+ }
+}
+
+/**
+ * 优化软件配置
+ * @return {*}
+ */
+function modifyAppConfig() {
+ let response = null;
+ try {
+ if (!!$.response.body) {
+ let obj = JSON.parse($.response.body);
+ obj["config"]["homepage_feed_tab"]["tab_infos"] = obj["config"][
+ "homepage_feed_tab"
+ ]["tab_infos"].filter((e) => {
+ // 将活动标签设置为已过期
+ if (e["tab_type"] === "activity_tab") {
+ e["end_time"] = (new Date() - 120000).toString().slice(0, 10);
+ return true;
+ } else {
+ return false;
+ }
+ });
+ obj["config"]["zvideo_max_number"] = 1;
+ // 似乎是控制内部弹窗
+ obj["config"]["is_show_followguide_alert"] = false;
+ // 似乎是某个地方的标签,待定
+ delete obj["config"]["hp_channel_tab"];
+ // 灰色模式
+ if (obj["config"]["zombie_conf"]) {
+ obj["config"]["zombie_conf"]["zombieEnable"] = false;
+ }
+ if (obj["config"]["gray_mode"]) {
+ obj["config"]["gray_mode"]["enable"] = false;
+ obj["config"]["gray_mode"]["start_time"] = "4092566400";
+ obj["config"]["gray_mode"]["end_time"] = "4092566400";
+ }
+ // 屏蔽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;
+}
+
+/**
+ * 修改云端下发的配置
+ * @return {*}
+ */
+function modifyMCloudConfig() {
+ let response = null;
+ try {
+ if (!!$.response.body) {
+ let obj = JSON.parse($.response.body);
+ if (obj.data && obj.data["configs"]) {
+ // 去除灰色主题
+ obj.data["configs"].forEach((element) => {
+ if (element["configKey"] === "feed_gray_theme") {
+ element["configValue"].start_time = "1669824000";
+ element["configValue"].end_time = "1669824001";
+ element.status = false;
+ }
+ });
+ }
+ const body = JSON.stringify(obj);
+ $.logger.debug(body);
+ response = { body: body };
+ }
+ } catch (err) {
+ $.logger.error(`优化软件配置出现异常:${err}`);
+ }
+ return response;
+}
+
+/**
+ * 屏蔽关键词解锁
+ * @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;
+}
+
+/**
+ * 处理登录用户信息
+ *
+ * @return {*}
+ */
+function processUserInfo() {
+ let response = null;
+ try {
+ let obj = JSON.parse($.response.body);
+ $.data.write(blackAnswersIdKey, []);
+ $.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_type"] = 2;
+ obj["vip_info"]["vip_icon"] = {
+ url: "https://picx.zhimg.com/v2-aa8a1823abfc46f14136f01d55224925.jpg?source=88ceefae",
+ night_mode_url:
+ "https://picx.zhimg.com/v2-aa8a1823abfc46f14136f01d55224925.jpg?source=88ceefae",
+ };
+ obj["vip_info"]["vip_icon_v2"] = {
+ url: "https://picx.zhimg.com/v2-aa8a1823abfc46f14136f01d55224925.jpg?source=88ceefae",
+ night_mode_url:
+ "https://picx.zhimg.com/v2-aa8a1823abfc46f14136f01d55224925.jpg?source=88ceefae",
+ };
+ obj["vip_info"]["entrance"] = {
+ icon: {
+ url: "https://pic3.zhimg.com/v2-5b7012c8c22fd520f5677305e1e551bf.png",
+ night_mode_url:
+ "https://pic4.zhimg.com/v2-e51e3252d7a2cb016a70879defd5da0b.png",
+ },
+ title: "盐选会员 为你严选好内容",
+ expires_day: "2099-12-31",
+ sub_title: null,
+ button_text: "首月 9 元",
+ jump_url: "zhihu://vip/purchase",
+ button_jump_url: "zhihu://vip/purchase",
+ sub_title_new: null,
+ identity: "super_svip",
+ };
+ obj["vip_info"]["entrance_new"] = {
+ left_button: {
+ title: "精选会员内容",
+ description: "为您严选好内容",
+ jump_url: "zhihu://market/home",
+ },
+ right_button: {
+ title: "开通盐选会员",
+ description: "畅享 10w+ 场优质内容等特权",
+ jump_url: "zhihu://vip/purchase",
+ },
+ };
+ obj["vip_info"]["entrance_v2"] = {
+ title: "我的超级盐选会员",
+ sub_title: "畅享 5000W+ 优质内容",
+ jump_url: "zhihu://market/home",
+ button_text: "查看会员",
+ sub_title_color: "#F8E2C4",
+ sub_title_list: ["畅享 5000W+ 优质内容"],
+ card_jump_url: "zhihu://market/home",
+ };
+ $.logger.debug("设置用户为本地盐选会员");
+ response = { body: JSON.stringify(obj) };
+ }
+ } else {
+ $.logger.warning(
+ `没有获取到本次登录用户信息,如未对功能造成影响,请忽略此日志。`
+ );
+ }
+ } catch (err) {
+ $.logger.error(`获取当前用户信息出现异常:${err}`);
+ }
+ return response;
+}
+
+/**
+ * @description: 黑名单管理
+ * @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\/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("移出脚本黑名单失败,执行异常,请查阅日志。");
+ }
+ }
+}
+
+/**
+ * 黑名单增强 - 浏览黑名单用户信息时自动加入脚本黑名单
+ * @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;
+}
+
+/**
+ * 关注列表去广告
+ *
+ * @return {*}
+ */
+function removeMoments() {
+ 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_remove_stream = $.data.read(
+ "zhihu_settings_moments_stream",
+ false
+ );
+ const settings_remove_recommend = $.data.read(
+ "zhihu_settings_moments_recommend",
+ false
+ );
+ const settings_remove_activity = $.data.read(
+ "zhihu_settings_moments_activity",
+ false
+ );
+ const settings_blocked_users = $.data.read(
+ "zhihu_settings_blocked_users",
+ false
+ );
+
+ data = obj.data.filter((item) => {
+ // 转发的想法是否含有黑名单用户
+ const isBlackUserPin =
+ settings_blocked_users &&
+ item.target &&
+ item.target["origin_pin"] &&
+ item.target["origin_pin"].author &&
+ typeof customBlockedUsers[item.target["origin_pin"].author.name] !=
+ "undefined";
+ // 是否为流媒体
+ const isStream =
+ settings_remove_stream && item["target_type"] === "zvideo";
+ // 是否为推荐关注用户
+ const isRecommend =
+ settings_remove_recommend && item.type === "recommend_user_card_list";
+ // 是否为关注的问题有新动态
+ const isActivity =
+ settings_remove_activity && item.type === "message_activity_card";
+ return !(isBlackUserPin || isStream || isRecommend || isActivity);
+ });
+ obj["data"] = data;
+ response = { body: JSON.stringify(obj) };
+ } catch (err) {
+ $.logger.error(`关注列表去广告出现异常:${err}`);
+ }
+ return response;
+}
+
+/**
+ * 推荐去广告与黑名单增强
+ *
+ * @return {*}
+ */
+function removeRecommend() {
+ let response = null;
+ try {
+ // 移除推荐列表中的想法
+ const settings_remove_pin = $.data.read(
+ "zhihu_settings_recommend_pin",
+ false
+ );
+ // 移除推荐列表的流媒体
+ const settings_recommend_stream = $.data.read(
+ "zhihu_settings_recommend_stream",
+ false
+ );
+ // 移除推荐列表的文章
+ const settings_remove_article = $.data.read(
+ "zhihu_settings_remove_article",
+ false
+ );
+ // 屏蔽黑名单用户
+ const settings_blocked_users = $.data.read(
+ "zhihu_settings_blocked_users",
+ false
+ );
+ // 屏蔽关键词内容
+ const settings_blocked_keywords = $.data.read(
+ "zhihu_settings_blocked_keywords",
+ true
+ );
+ // 获取用户信息
+ 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 newData = (element) => {
+ const elementStr = JSON.stringify(element);
+ // 是否为广告
+ const isAd =
+ element["card_type"] === "slot_event_card" ||
+ element["card_type"] === "slot_video_event_card" ||
+ element.hasOwnProperty("ad") ||
+ // 非常恶心伪装成普通内容的广告
+ (element["brief"] && element["brief"].indexOf("slot_card") >= 0) ||
+ // 训练营
+ (element["extra"] && element["extra"]["type"] === "Training");
+ // 是否为流媒体
+ const isStream =
+ isAd !== true &&
+ elementStr.search(
+ /"(type|style)+"\s?:\s?"(drama|zvideo|Video|BIG_IMAGE)+"/i
+ ) >= 0;
+ const removeStream = isStream && settings_recommend_stream;
+ // 是否为想法
+ const isPin =
+ isStream !== true &&
+ elementStr.search(/"(type|style)+"\s?:\s?"pin"/i) >= 0;
+ const removePin = isPin && settings_remove_pin;
+ // 是否为文章
+ const isArticle =
+ elementStr.search(/"(type|style)+"\s?:\s?"article"/i) >= 0;
+ const 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;
+ 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 ||
+ removePin ||
+ removeArticle ||
+ removeStream ||
+ matchKeyword ||
+ isBlockedUser
+ );
+ };
+
+ // 修复number类型精度丢失
+ let obj = JSON.parse(
+ $.response.body.replace(/(\w+"+\s?):\s?(\d{15,})/g, '$1:"$2"')
+ );
+
+ if (obj["data"].length > 0 && newData.length === 0) {
+ $.notification.post("所有推荐内容都已被过滤,建议调整脚本过滤配置。");
+ }
+ obj["data"] = obj["data"].filter(newData);
+ response = { body: JSON.stringify(obj) };
+ } catch (err) {
+ $.logger.error(`推荐列表去广告出现异常:${err}`);
+ }
+ return response;
+}
+
+/**
+ * 回答列表去广告与黑名单增强
+ *
+ * @return {*}
+ */
+function removeQuestions() {
+ let response = null;
+ try {
+ const userInfo = getUserInfo();
+ let customBlockedUsers = $.data.read(blockedUsersKey, "", userInfo.id);
+ customBlockedUsers = !!customBlockedUsers ? customBlockedUsers : {};
+ let obj = JSON.parse($.response.body);
+ const settingsBlockedUsers = $.data.read(
+ "zhihu_settings_blocked_users",
+ false
+ );
+ $.logger.debug(`当前黑名单列表: ${JSON.stringify(customBlockedUsers)}`);
+ // 黑名单用户的回答Id
+ let blackUserAnswersId = $.data.read(blackAnswersIdKey, []);
+ // 去除广告
+ delete obj["ad_info"];
+ // 去除回答列表中的黑名单用户
+ if (obj["data"]) {
+ let newData = [];
+ for (let element of obj.data) {
+ let blackUserName = "";
+ const answerId = element.target.id.toString();
+ try {
+ if ("target" in element) {
+ blackUserName = element["target"]["author"]["name"];
+ }
+ } catch (ex) {
+ $.logger.error(`获取回答列表用户名出现异常:${ex}`);
+ }
+ const isBlackUser =
+ typeof customBlockedUsers[blackUserName] != "undefined";
+ const removeBlackUserAnswer = settingsBlockedUsers && isBlackUser;
+ // 显示仅作者自己可见的回答,允许复制
+ if ("target" in element) {
+ element["target"]["visible_only_to_author"] = false;
+ element["target"]["is_visible"] = true;
+ element["target"]["is_copyable"] = true;
+ }
+ if (!removeBlackUserAnswer) {
+ newData.push(element);
+ } else if (
+ removeBlackUserAnswer === true &&
+ blackUserAnswersId.includes(answerId) === false
+ ) {
+ blackUserAnswersId.push(answerId);
+ $.notification.debug(
+ `记录黑名单用户${blackUserName}的回答Id:${answerId}`
+ );
+ }
+ }
+ obj.data = newData;
+ }
+ $.data.write(blackAnswersIdKey, blackUserAnswersId);
+ const body = JSON.stringify(obj);
+ $.logger.debug(`修改后的回答列表数据:${body}`);
+ response = { body: body };
+ } catch (err) {
+ $.logger.error(`回答列表去广告出现异常:${err}`);
+ }
+ return response;
+}
+
+/**
+ * 回答内容优化
+ *
+ * @return {*}
+ */
+function modifyAnswer() {
+ let response = null;
+ try {
+ let html = $.response.body;
+ let insertText = "";
+
+ // 付费内容提醒
+ if (
+ (html.indexOf("查看完整内容") >= 0 ||
+ html.indexOf("查看全部章节") >= 0) &&
+ html.indexOf("paid") >= 0
+ ) {
+ insertText =
+ '';
+ }
+
+ // 营销推广提醒
+ else if (
+ html.indexOf("ad-link-card") >= 0 ||
+ html.indexOf("xg.zhihu.com") >= 0 ||
+ html.indexOf("营销平台") >= 0
+ ) {
+ insertText =
+ '';
+ }
+
+ // 购物推广提醒
+ else if (html.indexOf("mcn-link-card") >= 0) {
+ insertText =
+ '';
+ }
+
+ // 彩蛋
+ else if (Math.floor(Math.random() * 200) === 7) {
+ insertText =
+ '';
+ }
+
+ if (insertText !== "") {
+ const matchStr = html.match(/(richText[^<]*>)(.)/)[1];
+ const start = html.lastIndexOf(matchStr) + matchStr.length;
+ response = {
+ body: html.slice(0, start) + insertText + html.slice(start),
+ };
+ }
+ } catch (err) {
+ $.logger.error(`付费内容提醒出现异常:${err}`);
+ }
+ return response;
+}
+
+/**
+ * 评论去广告及黑名单增强
+ *
+ * @return {*}
+ */
+function removeComment() {
+ let response = null;
+ try {
+ if (!!$.response.body) {
+ let obj = JSON.parse($.response.body);
+ obj["ad_info"] = {};
+ // 屏蔽黑名单用户
+ if ($.data.read("zhihu_settings_blocked_users", false) === true) {
+ let user_info = getUserInfo();
+ let customBlockedUsers = $.data.read(blockedUsersKey, "", user_info.id);
+ customBlockedUsers = !!customBlockedUsers ? customBlockedUsers : {};
+ let newComments = [];
+ let blockCommentIdObj = {};
+ if (typeof obj.root != "undefined") {
+ // 屏蔽黑名单用户的评论
+ const rootUserName = obj.root.author.name;
+ const isBlackRootUser =
+ typeof customBlockedUsers[rootUserName] != "undefined";
+ if (isBlackRootUser === true) {
+ obj.root.is_delete = true;
+ obj.root.can_reply = false;
+ obj.root.can_like = false;
+ obj.root.author.name = "黑名单用户";
+ obj.root.author.avatar_url =
+ "https://picx.zhimg.com/v2-abed1a8c04700ba7d72b45195223e0ff_xll.jpg";
+ }
+ }
+
+ if (typeof obj.data != "undefined") {
+ obj.data.forEach((comment) => {
+ // 屏蔽黑名单用户的评论
+ // 评论人昵称
+ const commentUserName = comment.author.name;
+ // 回复哪个人的评论(仅适用于独立子评论页面请求)
+ let replyUserName = "";
+ if (comment["reply_to_author"] && comment["reply_to_author"].name) {
+ replyUserName = comment["reply_to_author"].name;
+ }
+ const isSubComment = replyUserName !== "";
+ const isBlackCommentUser =
+ typeof customBlockedUsers[commentUserName] != "undefined";
+ const isBlackReplyUser =
+ typeof customBlockedUsers[replyUserName] != "undefined";
+ if (isBlackCommentUser === true || isBlackReplyUser === true) {
+ if (
+ isBlackCommentUser &&
+ !isSubComment &&
+ $.request.url.indexOf("root_comment") > 0
+ ) {
+ $.notification.debug(
+ `屏蔽黑名单用户“${commentUserName}”的主评论。`
+ );
+ } else if (
+ !isBlackCommentUser &&
+ isSubComment &&
+ !isBlackReplyUser &&
+ $.request.url.indexOf("child_comment") > 0
+ ) {
+ $.notification.debug(
+ `屏蔽黑名单用户“${commentUserName}”的子评论。`
+ );
+ } else if (
+ isBlackCommentUser &&
+ !isBlackReplyUser &&
+ $.request.url.indexOf("child_comment") > 0
+ ) {
+ $.notification.debug(
+ `屏蔽黑名单用户“${commentUserName}”回复“${replyUserName}”的子评论。`
+ );
+ } else if (
+ isBlackCommentUser &&
+ isBlackReplyUser &&
+ $.request.url.indexOf("child_comment") > 0
+ ) {
+ $.notification.debug(
+ `屏蔽黑名单用户“${commentUserName}”回复黑名单用户“${replyUserName}”的子评论。`
+ );
+ }
+ blockCommentIdObj[comment.id] = commentUserName;
+ if (isBlackCommentUser) {
+ comment.is_delete = true;
+ comment.can_reply = false;
+ comment.can_like = false;
+ comment.author.exposed_medal = {};
+ comment.author.name = "[黑名单用户]";
+ comment.author.avatar_url =
+ "https://picx.zhimg.com/v2-abed1a8c04700ba7d72b45195223e0ff_xll.jpg";
+ }
+ if (isBlackReplyUser) {
+ comment["reply_to_author"].name = "[黑名单用户]";
+ comment["reply_to_author"].exposed_medal = {};
+ comment["reply_to_author"].avatar_url =
+ "https://picx.zhimg.com/v2-abed1a8c04700ba7d72b45195223e0ff_xll.jpg";
+ }
+ }
+ if (comment.child_comments) {
+ let newChildComments = [];
+ comment.child_comments.forEach((childComment) => {
+ // 屏蔽黑名单用户的评论
+ const childCommentUserName = childComment.author.name;
+ const childCommentReplyUserName =
+ typeof childComment["reply_to_author"] != "undefined"
+ ? childComment["reply_to_author"].name
+ : "";
+ const isChildBlackCommentUser =
+ typeof customBlockedUsers[childCommentUserName] !=
+ "undefined";
+ const isChildBlackReplyUser =
+ typeof customBlockedUsers[childCommentReplyUserName] !=
+ "undefined";
+ if (isChildBlackCommentUser || isChildBlackReplyUser) {
+ if (isChildBlackCommentUser === true) {
+ $.notification.debug(
+ `屏蔽黑名单用户“${childCommentUserName}”的子评论。`
+ );
+ blockCommentIdObj[childComment.id] = childCommentUserName;
+ childComment.is_delete = true;
+ childComment.can_reply = false;
+ childComment.can_like = false;
+ childComment.author.name = "[黑名单用户]";
+ childComment.author.exposed_medal = {};
+ childComment.author.avatar_url =
+ "https://picx.zhimg.com/v2-abed1a8c04700ba7d72b45195223e0ff_xll.jpg";
+ }
+
+ if (isChildBlackReplyUser === true) {
+ $.logger.debug(
+ `修改前的子评论数据:\n${JSON.stringify(childComment)}`
+ );
+ childComment["reply_to_author"].name = "[黑名单用户]";
+ childComment["reply_to_author"].exposed_medal = {};
+ childComment["reply_to_author"].avatar_url =
+ "https://picx.zhimg.com/v2-abed1a8c04700ba7d72b45195223e0ff_xll.jpg";
+ $.notification.debug(
+ `隐藏“${childCommentUserName}”回复黑名单用户“${childCommentReplyUserName}”的名称与头像。`
+ );
+ $.logger.debug(
+ `修改后的子评论数据:\n${JSON.stringify(childComment)}`
+ );
+ }
+ }
+ newChildComments.push(childComment);
+ });
+ comment.child_comments = newChildComments;
+ }
+ newComments.push(comment);
+ });
+ }
+ obj.data = newComments;
+ }
+ const body = JSON.stringify(obj);
+ $.logger.debug(`过滤后的评论数据:\n${body}`);
+ response = { body: body };
+ }
+ } catch (err) {
+ $.logger.error(`去除评论广告出现异常:${err}`);
+ }
+ return response;
+}
+
+/**
+ * 移除文章页面的广告
+ * @return {*}
+ */
+function removeArticleAd() {
+ let response = null;
+ try {
+ if (!!$.response.body) {
+ let obj = JSON.parse($.response.body);
+ obj["ad_info"] = {};
+ const body = JSON.stringify(obj);
+ $.logger.debug(`过滤后的文章数据:\n${body}`);
+ response = { body: body };
+ }
+ } catch (err) {
+ $.logger.error(`去除文章广告出现异常:${err}`);
+ }
+ return response;
+}
+
+/**
+ * 屏蔽官方营销消息
+ *
+ * @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;
+}
+
+/**
+ * 热榜去广告
+ *
+ * @return {*}
+ */
+function removeHotListAds() {
+ let response = null;
+ try {
+ if (!!$.response.body) {
+ let obj = JSON.parse($.response.body);
+ if ("data" in obj) {
+ obj["data"] = obj["data"].filter((e) => {
+ return (
+ e["type"] === "hot_list_feed" || e["type"] === "hot_list_feed_video"
+ );
+ });
+ }
+ response = { body: JSON.stringify(obj) };
+ }
+ } catch (err) {
+ $.logger.error(`去除热榜广告出现异常:${err}`);
+ }
+ return response;
+}
+
+/**
+ * 去除预置关键字广告
+ *
+ * @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"]) {
+ obj["preset_words"]["words"] = obj["preset_words"]["words"].filter(
+ (element) => {
+ return element["type"] !== "ad";
+ }
+ );
+ response = { body: JSON.stringify(obj) };
+ }
+ }
+ } catch (err) {
+ $.logger.error(`去除预置关键字广告出现异常:${err}`);
+ }
+ return response;
+}
+
+/**
+ * 移除回答翻页时出现的黑名单用户的回答
+ * 小概率会移除失败
+ * @return {*}
+ */
+function removeNextBlackUserAnswer() {
+ let response = null;
+ try {
+ if (!!$.response.body) {
+ let obj = JSON.parse($.response.body);
+ const blackUserAnswersId = $.data.read(blackAnswersIdKey, []);
+ if (blackUserAnswersId.length > 0) {
+ let newData = [];
+ obj.data.forEach((element) => {
+ const tag = blackUserAnswersId.includes(element.id.toString());
+ if (tag === false) {
+ // 去除可能的广告
+ element.ad_info = { data: "" };
+ newData.push(element);
+ } else {
+ $.notification.debug(
+ `屏蔽翻页过程中出现的黑名单用户回答Id:${element.id}`
+ );
+ }
+ });
+ // 重新为答案排序
+ for (let i = 0; i < newData.length; i++) {
+ if (newData[i]["extra"] && newData[i]["extra"]["question_index"]) {
+ newData[i]["extra"]["question_index"] = i + 1;
+ }
+ if (newData[i]["strategy_info"]) {
+ newData[i]["strategy_info"]["global_index"] = i + 1;
+ newData[i]["strategy_info"]["strategy_index"] = i + 1;
+ }
+ }
+ obj.data = newData;
+ }
+ response = { body: JSON.stringify(obj) };
+ }
+ } catch (err) {
+ $.logger.error(`屏蔽下翻黑名单用户的回答出现异常:${err}`);
+ }
+ return response;
+}
+
+function modifyAnswersNextData() {
+ let response = null;
+ try {
+ if (!!$.response.body) {
+ let obj = JSON.parse($.response.body);
+ let user_info = getUserInfo();
+ let customBlockedUsers = $.data.read(blockedUsersKey, {}, user_info.id);
+ $.logger.debug(`脚本黑名单用户:\n${JSON.stringify(customBlockedUsers)}`);
+ let newData = [];
+ obj.data.data.forEach((element) => {
+ element["ad_info"] = { data: "" };
+ const isBlackUser =
+ typeof customBlockedUsers[element.data.author.name] != "undefined";
+ $.logger.debug(
+ `用户${element.data.author.name}是否在黑名单中:${isBlackUser}`
+ );
+ if (
+ $.data.read("zhihu_settings_blocked_users", false) === false ||
+ isBlackUser === false
+ ) {
+ newData.push(element);
+ }
+ });
+ obj.data.data = newData;
+ response = { body: JSON.stringify(obj) };
+ }
+ } catch (err) {
+ $.logger.error(`屏蔽回答信息流黑名单用户及广告:${err}`);
+ }
+ return response;
+}
+
+/**
+ * 修改盐值
+ *
+ * @return {*}
+ */
+function changeUserCredit() {
+ $.notification.debug("开始修改用户盐值");
+ let response = null;
+ try {
+ if (!!$.response.body) {
+ // 自定义盐值
+ const score = parseInt($.data.read(userCreditScore, 780));
+ $.logger.debug(`准备修改用户盐值为${score}`);
+ let obj = JSON.parse($.response.body);
+ if (obj["credit_basis"].total_score < score) {
+ obj["credit_basis"].total_score = score;
+ $.logger.debug(`已修改用户盐值为:${score}`);
+ }
+ response = { body: JSON.stringify(obj) };
+ }
+ } catch (err) {
+ $.logger.error(`修改用户盐值出现异常:${err}`);
+ }
+ return response;
+}
+
+(() => {
+ let response = null;
+ if ($.isResponse) {
+ switch (true) {
+ // 获取用户信息 - 隔离用户数据,开启本地盐选会员等
+ case /^https:\/\/api\.zhihu\.com\/people\/self$/.test($.request.url):
+ response = processUserInfo();
+ break;
+ // 优化软件配置 - 优化下发的配置文件来实现某些效果
+ case $.data.read("zhihu_settings_app_conf", false) === true &&
+ /^https?:\/\/appcloud2\.zhihu\.com\/v\d+\/config/.test($.request.url):
+ response = modifyAppConfig();
+ break;
+ case $.data.read("zhihu_settings_app_conf", false) === true &&
+ /^https?:\/\/m-cloud\.zhihu\.com\/api\/cloud\/config\/all\?/.test(
+ $.request.url
+ ):
+ response = modifyMCloudConfig();
+ break;
+ // 修改用户盐值 - 仅当自定义盐值大于真实盐值时生效
+ case /^https?:\/\/api\.zhihu\.com\/user-credit\/basis/.test(
+ $.request.url
+ ):
+ $.notification.debug("准备修改用户盐值");
+ response = changeUserCredit();
+ break;
+ // 推荐页 - 移除黑名单用户发布的文章、去除广告,及自定义一些屏蔽项目
+ case /^https:\/\/api\.zhihu\.com\/topstory\/recommend/.test(
+ $.request.url
+ ):
+ response = removeRecommend();
+ break;
+ // 问题的回答列表 - 移除黑名单用户的回答、去除广告
+ case /^https?:\/\/api\.zhihu\.com\/(v4\/)?questions\/\d+/.test(
+ $.request.url
+ ):
+ response = removeQuestions();
+ break;
+ // 回答信息流 - 移除黑名单用户的回答、去除广告
+ case /^https?:\/\/api\.zhihu\.com\/next-data\?/.test($.request.url):
+ response = modifyAnswersNextData();
+ break;
+ // 消息页 - 折叠官方消息、屏蔽营销消息
+ case $.data.read("zhihu_settings_sys_msg", true) !== false &&
+ /^https?:\/\/api\.zhihu\.com\/notifications\/v3\/message/.test(
+ $.request.url
+ ):
+ response = removeMarketingMsg();
+ break;
+ // 评论页及子页面 - 去除黑名单用户发表的评论
+ case /^https?:\/\/api\.zhihu\.com\/comment_v5\/(answers|pins|comments?|articles)\/\d+\/(root|child)_comment/.test(
+ $.request.url
+ ):
+ response = removeComment();
+ break;
+ // 文章页 - 去除底部卡片广告
+ case /^https?:\/\/www\.zhihu\.com\/api\/v\d\/articles\/\d+\/recommendation\?/.test(
+ $.request.url
+ ):
+ response = removeArticleAd();
+ break;
+ // 回答页底部评论摘要 - 移除黑名单用户发表的评论
+ case /^https?:\/\/www\.zhihu\.com\/api\/v4\/comment_v5\/answers\/\d+\/abstract_comment\?/.test(
+ $.request.url
+ ):
+ response = removeComment();
+ break;
+ // 回答内容优化 - 付费、营销、推广内容文首提醒
+ case $.data.read("zhihu_settings_answer_tip", true) === true &&
+ /^https?:\/\/www\.zhihu\.com\/appview\/v2\/answer\/.*(entry=(?!(preload-topstory|preload-search|preload-subscription)))?/.test(
+ $.request.url
+ ):
+ response = modifyAnswer();
+ break;
+ // 回答页 - 屏蔽下翻出现的黑名单用户
+ case $.data.read("zhihu_settings_blocked_users", false) !== false &&
+ /^https?:\/\/api\.zhihu\.com\/next\?/.test($.request.url):
+ response = removeNextBlackUserAnswer();
+ break;
+ // 黑名单增强 - 浏览黑名单用户信息时自动加入脚本黑名单
+ case $.data.read("zhihu_settings_blocked_users", true) === true &&
+ /^https?:\/\/api\.zhihu\.com\/people\/((?!self).)*$/.test(
+ $.request.url
+ ):
+ response = autoInsertBlackList();
+ break;
+ // 关注页 - 去广告
+ case /^https?:\/\/api\.zhihu\.com\/moments_v3\?/.test($.request.url):
+ response = removeMoments();
+ break;
+ // 热榜页 - 去广告
+ case $.data.read("zhihu_settings_hot_list", true) === true &&
+ /^https?:\/\/api\.zhihu\.com\/topstory\/hot-lists(\?|\/)/.test(
+ $.request.url
+ ):
+ response = removeHotListAds();
+ break;
+ // 搜索页 - 去除预置广告
+ case $.data.read("zhihu_settings_preset_words", true) === true &&
+ /^https?:\/\/api\.zhihu\.com\/search\/preset_words\?/.test(
+ $.request.url
+ ):
+ response = removeKeywordAds();
+ break;
+ // 黑名单页 - 同步黑名单数据
+ case $.data.read("zhihu_settings_blocked_users", false) !== false &&
+ /^https?:\/\/api\.zhihu\.com\/settings\/blocked_users/.test(
+ $.request.url
+ ):
+ manageBlackUser();
+ break;
+ default:
+ $.logger.debug("没有匹配到任何请求,请确认配置正确。");
+ break;
+ }
+ } else if ($.isRequest) {
+ // 屏蔽关键词解锁
+ if (
+ $.data.read("zhihu_settings_blocked_keywords", false) !== false &&
+ /^https?:\/\/api\.zhihu\.com\/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();
+ }
+})();
+
+// prettier-ignore
+/**
+ *
+ * $$\ $$\ $$\ $$$$$\ $$$$$$\ $$$$$$\
+ * $$$\ $$$ | \__| \__$$ |$$ __$$\ $$ ___$$\
+ * $$$$\ $$$$ | $$$$$$\ $$$$$$\ $$\ $$$$$$$\ $$ |$$ / \__| \_/ $$ |
+ * $$\$$\$$ $$ | \____$$\ $$ __$$\ $$ |$$ _____| $$ |\$$$$$$\ $$$$$ /
+ * $$ \$$$ $$ | $$$$$$$ |$$ / $$ |$$ |$$ / $$\ $$ | \____$$\ \___$$\
+ * $$ |\$ /$$ |$$ __$$ |$$ | $$ |$$ |$$ | $$ | $$ |$$\ $$ | $$\ $$ |
+ * $$ | \_/ $$ |\$$$$$$$ |\$$$$$$$ |$$ |\$$$$$$$\\$$$$$$ |\$$$$$$ | \$$$$$$ |
+ * \__| \__| \_______| \____$$ |\__| \_______|\______/ \______/ \______/
+ * $$\ $$ |
+ * \$$$$$$ |
+ * \______/
+ *
+ */
+// @formatter:off
+function MagicJS(scriptName="MagicJS",logLevel="INFO"){const MagicEnvironment=()=>{const isLoon=typeof $loon!=="undefined";const isQuanX=typeof $task!=="undefined";const isNode=typeof module!=="undefined";const isSurge=typeof $httpClient!=="undefined"&&!isLoon;const isStorm=typeof $storm!=="undefined";const isStash=typeof $environment!=="undefined"&&typeof $environment["stash-build"]!=="undefined";const isSurgeLike=isSurge||isLoon||isStorm||isStash;const isScriptable=typeof importModule!=="undefined";return{isLoon:isLoon,isQuanX:isQuanX,isNode:isNode,isSurge:isSurge,isStorm:isStorm,isStash:isStash,isSurgeLike:isSurgeLike,isScriptable:isScriptable,get name(){if(isLoon){return"Loon"}else if(isQuanX){return"QuantumultX"}else if(isNode){return"NodeJS"}else if(isSurge){return"Surge"}else if(isScriptable){return"Scriptable"}else{return"unknown"}},get build(){if(isSurge){return $environment["surge-build"]}else if(isStash){return $environment["stash-build"]}else if(isStorm){return $storm.buildVersion}},get language(){if(isSurge||isStash){return $environment["language"]}},get version(){if(isSurge){return $environment["surge-version"]}else if(isStash){return $environment["stash-version"]}else if(isStorm){return $storm.appVersion}else if(isNode){return process.version}},get system(){if(isSurge){return $environment["system"]}else if(isNode){return process.platform}},get systemVersion(){if(isStorm){return $storm.systemVersion}},get deviceName(){if(isStorm){return $storm.deviceName}}}};const MagicLogger=(scriptName,logLevel="INFO")=>{let _level=logLevel;const logLevels={SNIFFER:6,DEBUG:5,INFO:4,NOTIFY:3,WARNING:2,ERROR:1,CRITICAL:0,NONE:-1};const logEmoji={SNIFFER:"",DEBUG:"",INFO:"",NOTIFY:"",WARNING:"❗ ",ERROR:"❌ ",CRITICAL:"❌ ",NONE:""};const _log=(msg,level="INFO")=>{if(!(logLevels[_level]{_level=logLevel};return{getLevel:()=>{return _level},setLevel:setLevel,sniffer:msg=>{_log(msg,"SNIFFER")},debug:msg=>{_log(msg,"DEBUG")},info:msg=>{_log(msg,"INFO")},notify:msg=>{_log(msg,"NOTIFY")},warning:msg=>{_log(msg,"WARNING")},error:msg=>{_log(msg,"ERROR")},retry:msg=>{_log(msg,"RETRY")}}};return new class{constructor(scriptName,logLevel){this._startTime=Date.now();this.version="3.0.0";this.scriptName=scriptName;this.env=MagicEnvironment();this.logger=MagicLogger(scriptName,logLevel);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 magicLoglevel=this.data.read("magic_loglevel");const barkUrl=this.data.read("magic_bark_url");if(magicLoglevel){this.logger.setLevel(magicLoglevel.toUpperCase())}if(barkUrl){this.notification.setBark(barkUrl)}}}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=(value={})=>{this._endTime=Date.now();let span=(this._endTime-this._startTime)/1e3;this.logger.debug(`SCRIPT COMPLETED: ${span} S.`);if(typeof $done!=="undefined"){$done(value)}}}(scriptName,logLevel)}
+function MagicNotification(scriptName, env, logger, http) {
+ let _barkUrl = null;
+ let _barkKey = null;
+ const setBark = (url) => {
+ try {
+ let _url = url.replace(/\/+$/g, "");
+ _barkUrl = `${/^https?:\/\/([^/]*)/.exec(_url)[0]}/push`;
+ _barkKey = /\/([^\/]+)\/?$/.exec(_url)[1];
+ } catch (ex) {
+ logger.error(`Bark url error: ${ex}.`);
+ }
+ };
+ function post(title = scriptName, subTitle = "", body = "", opts = "") {
+ const _adaptOpts = (_opts) => {
+ try {
+ let newOpts = {};
+ if (typeof _opts === "string") {
+ if (env.isLoon) newOpts = { openUrl: _opts };
+ else if (env.isQuanX) newOpts = { "open-url": _opts };
+ else if (env.isSurge) newOpts = { url: _opts };
+ } else if (typeof _opts === "object") {
+ if (env.isLoon) {
+ newOpts["openUrl"] = !!_opts["open-url"] ? _opts["open-url"] : "";
+ newOpts["mediaUrl"] = !!_opts["media-url"]
+ ? _opts["media-url"]
+ : "";
+ } else if (env.isQuanX) {
+ newOpts = !!_opts["open-url"] || !!_opts["media-url"] ? _opts : {};
+ } else if (env.isSurge) {
+ let openUrl = _opts["open-url"] || _opts["openUrl"];
+ newOpts = openUrl ? { url: openUrl } : {};
+ }
+ }
+ return newOpts;
+ } catch (err) {
+ logger.error(`通知选项转换失败${err}`);
+ }
+ return _opts;
+ };
+ opts = _adaptOpts(opts);
+ if (arguments.length === 1) {
+ title = scriptName;
+ (subTitle = ""), (body = arguments[0]);
+ }
+ logger.notify(
+ `title:${title}\nsubTitle:${subTitle}\nbody:${body}\noptions:${
+ typeof opts === "object" ? JSON.stringify(opts) : opts
+ }`
+ );
+ if (env.isSurge) {
+ $notification.post(title, subTitle, body, opts);
+ } else if (env.isLoon) {
+ if (!!opts) $notification.post(title, subTitle, body, opts);
+ else $notification.post(title, subTitle, body);
+ } else if (env.isQuanX) {
+ $notify(title, subTitle, body, opts);
+ }
+ if (_barkUrl && _barkKey) {
+ bark(title, subTitle, body);
+ }
+ }
+ function debug(title = scriptName, subTitle = "", body = "", opts = "") {
+ if (logger.getLevel() === "DEBUG") {
+ if (arguments.length === 1) {
+ title = scriptName;
+ subTitle = "";
+ body = arguments[0];
+ }
+ this.post(title, subTitle, body, opts);
+ }
+ }
+ function bark(title = scriptName, subTitle = "", body = "", opts = "") {
+ if (typeof http === "undefined" || typeof http.post === "undefined") {
+ throw "Bark notification needs to import MagicHttp module.";
+ }
+ let options = {
+ url: _barkUrl,
+ headers: { "content-type": "application/json; charset=utf-8" },
+ body: {
+ title: title,
+ body: subTitle ? `${subTitle}\n${body}` : body,
+ device_key: _barkKey,
+ },
+ };
+ http.post(options).catch((ex) => {
+ logger.error(`Bark notify error: ${ex}`);
+ });
+ }
+ return { post: post, debug: debug, bark: bark, setBark: setBark };
+}
+function MagicData(env, logger) {
+ let node = { fs: undefined, data: {} };
+ if (env.isNode) {
+ node.fs = require("fs");
+ try {
+ node.fs.accessSync(
+ "./magic.json",
+ node.fs.constants.R_OK | node.fs.constants.W_OK
+ );
+ } catch (err) {
+ node.fs.writeFileSync("./magic.json", "{}", { encoding: "utf8" });
+ }
+ node.data = require("./magic.json");
+ }
+ const defaultValueComparator = (oldVal, newVal) => {
+ if (typeof newVal === "object") {
+ return false;
+ } else {
+ return oldVal === newVal;
+ }
+ };
+ const _typeConvertor = (val) => {
+ if (val === "true") {
+ return true;
+ } else if (val === "false") {
+ return false;
+ } else if (typeof val === "undefined") {
+ return null;
+ } else {
+ return val;
+ }
+ };
+ const _valConvertor = (val, default_, session, read_no_session) => {
+ if (session) {
+ try {
+ if (typeof val === "string") val = JSON.parse(val);
+ if (val["magic_session"] === true) {
+ val = val[session];
+ } else {
+ val = null;
+ }
+ } catch {
+ val = null;
+ }
+ }
+ if (typeof val === "string" && val !== "null") {
+ try {
+ val = JSON.parse(val);
+ } catch {}
+ }
+ if (read_no_session === false && !!val && val["magic_session"] === true) {
+ val = null;
+ }
+ if (
+ (val === null || typeof val === "undefined") &&
+ default_ !== null &&
+ typeof default_ !== "undefined"
+ ) {
+ val = default_;
+ }
+ val = _typeConvertor(val);
+ return val;
+ };
+ const convertToObject = (obj) => {
+ if (typeof obj === "string") {
+ let data = {};
+ try {
+ data = JSON.parse(obj);
+ const type = typeof data;
+ if (
+ type !== "object" ||
+ data instanceof Array ||
+ type === "bool" ||
+ data === null
+ ) {
+ data = {};
+ }
+ } catch {}
+ return data;
+ } else if (
+ obj instanceof Array ||
+ obj === null ||
+ typeof obj === "undefined" ||
+ obj !== obj ||
+ typeof obj === "boolean"
+ ) {
+ return {};
+ } else {
+ return obj;
+ }
+ };
+ const readForNode = (
+ key,
+ default_ = null,
+ session = "",
+ read_no_session = false,
+ externalData = null
+ ) => {
+ let data = externalData || node.data;
+ if (!!data && typeof data[key] !== "undefined" && data[key] !== null) {
+ val = data[key];
+ } else {
+ val = !!session ? {} : null;
+ }
+ val = _valConvertor(val, default_, session, read_no_session);
+ return val;
+ };
+ const read = (
+ key,
+ default_ = null,
+ session = "",
+ read_no_session = false,
+ externalData = null
+ ) => {
+ let val = "";
+ if (externalData || env.isNode) {
+ val = readForNode(key, default_, session, read_no_session, externalData);
+ } else {
+ if (env.isSurgeLike) {
+ val = $persistentStore.read(key);
+ } else if (env.isQuanX) {
+ val = $prefs.valueForKey(key);
+ }
+ val = _valConvertor(val, default_, session, read_no_session);
+ }
+ logger.debug(
+ `READ DATA [${key}]${
+ !!session ? `[${session}]` : ""
+ } <${typeof val}>\n${JSON.stringify(val)}`
+ );
+ return val;
+ };
+ const writeForNode = (key, val, session = "", externalData = null) => {
+ let data = externalData || node.data;
+ data = convertToObject(data);
+ if (!!session) {
+ let obj = convertToObject(data[key]);
+ obj["magic_session"] = true;
+ obj[session] = val;
+ data[key] = obj;
+ } else {
+ data[key] = val;
+ }
+ if (externalData !== null) {
+ externalData = data;
+ }
+ return data;
+ };
+ const write = (key, val, session = "", externalData = null) => {
+ if (typeof val === "undefined" || val !== val) {
+ return false;
+ }
+ if (!env.isNode && (typeof val === "boolean" || typeof val === "number")) {
+ val = String(val);
+ }
+ let data = "";
+ if (externalData || env.isNode) {
+ data = writeForNode(key, val, session, externalData);
+ } else {
+ if (!session) {
+ data = val;
+ } else {
+ if (env.isSurgeLike) {
+ data = !!$persistentStore.read(key)
+ ? $persistentStore.read(key)
+ : data;
+ } else if (env.isQuanX) {
+ data = !!$prefs.valueForKey(key) ? $prefs.valueForKey(key) : data;
+ }
+ data = convertToObject(data);
+ data["magic_session"] = true;
+ data[session] = val;
+ }
+ }
+ if (!!data && typeof data === "object") {
+ data = JSON.stringify(data, null, 4);
+ }
+ logger.debug(
+ `WRITE DATA [${key}]${
+ session ? `[${session}]` : ""
+ } <${typeof val}>\n${JSON.stringify(val)}`
+ );
+ if (!externalData) {
+ if (env.isSurgeLike) {
+ return $persistentStore.write(data, key);
+ } else if (env.isQuanX) {
+ return $prefs.setValueForKey(data, key);
+ } else if (env.isNode) {
+ try {
+ node.fs.writeFileSync("./magic.json", data);
+ return true;
+ } catch (err) {
+ logger.error(err);
+ return false;
+ }
+ }
+ }
+ return true;
+ };
+ const update = (
+ key,
+ val,
+ session,
+ comparator = defaultValueComparator,
+ externalData = null
+ ) => {
+ val = _typeConvertor(val);
+ const oldValue = read(key, null, session, false, externalData);
+ if (comparator(oldValue, val) === true) {
+ return false;
+ } else {
+ const result = write(key, val, session, externalData);
+ let newVal = read(key, null, session, false, externalData);
+ if (comparator === defaultValueComparator && typeof newVal === "object") {
+ return result;
+ }
+ return comparator(val, newVal);
+ }
+ };
+ const delForNode = (key, session, externalData) => {
+ let data = externalData || node.data;
+ data = convertToObject(data);
+ if (!!session) {
+ obj = convertToObject(data[key]);
+ delete obj[session];
+ data[key] = obj;
+ } else {
+ delete data[key];
+ }
+ if (!!externalData) {
+ externalData = data;
+ }
+ return data;
+ };
+ const del = (key, session = "", externalData = null) => {
+ let data = {};
+ if (externalData || env.isNode) {
+ data = delForNode(key, session, externalData);
+ if (!externalData) {
+ node.fs.writeFileSync("./magic.json", JSON.stringify(data, null, 4));
+ } else {
+ externalData = data;
+ }
+ } else {
+ if (!session) {
+ if (env.isStorm) {
+ return $persistentStore.remove(key);
+ } else if (env.isSurgeLike) {
+ return $persistentStore.write(null, key);
+ } else if (env.isQuanX) {
+ return $prefs.removeValueForKey(key);
+ }
+ } else {
+ if (env.isSurgeLike) {
+ data = $persistentStore.read(key);
+ } else if (env.isQuanX) {
+ data = $prefs.valueForKey(key);
+ }
+ data = convertToObject(data);
+ delete data[session];
+ const json = JSON.stringify(data, null, 4);
+ write(key, json);
+ }
+ }
+ logger.debug(`DELETE KEY [${key}]${!!session ? `[${session}]` : ""}`);
+ };
+ const allSessionNames = (key, externalData = null) => {
+ let _sessions = [];
+ let data = read(key, null, null, true, externalData);
+ data = convertToObject(data);
+ if (data["magic_session"] !== true) {
+ _sessions = [];
+ } else {
+ _sessions = Object.keys(data).filter((key) => key !== "magic_session");
+ }
+ logger.debug(
+ `READ ALL SESSIONS [${key}] <${typeof _sessions}>\n${JSON.stringify(
+ _sessions,
+ null,
+ 4
+ )}`
+ );
+ return _sessions;
+ };
+ const allSessions = (key, externalData = null) => {
+ let _sessions = {};
+ let data = read(key, null, null, true, externalData);
+ data = convertToObject(data);
+ if (data["magic_session"] === true) {
+ _sessions = { ...data };
+ delete _sessions["magic_session"];
+ }
+ logger.debug(
+ `READ ALL SESSIONS [${key}] <${typeof _sessions}>\n${JSON.stringify(
+ _sessions,
+ null,
+ 4
+ )}`
+ );
+ return _sessions;
+ };
+ return {
+ read: read,
+ write: write,
+ del: del,
+ update: update,
+ allSessions: allSessions,
+ allSessionNames: allSessionNames,
+ defaultValueComparator: defaultValueComparator,
+ convertToObject: convertToObject,
+ };
+}
+// @formatter:on