// ==UserScript== // @name 知乎-我不感兴趣 // @namespace // @version 4.3.4 // @description 隐藏掉所有不包含你关注话题的主页推送 // @author MQ // @grant GM_setValue // @grant GM_getValue // @grant GM_notification // @grant GM_xmlhttpRequest // @grant window // @require https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.18.2/babel.js // @require https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.16.0/polyfill.js // @connect zhuanlan.zhihu.com // @include /www\.zhihu\.com/(follow)?$/ // @namespace https://greasyfork.org/users/159603 // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/35275/%E7%9F%A5%E4%B9%8E-%E6%88%91%E4%B8%8D%E6%84%9F%E5%85%B4%E8%B6%A3.user.js // @updateURL https://update.greasyfork.icu/scripts/35275/%E7%9F%A5%E4%B9%8E-%E6%88%91%E4%B8%8D%E6%84%9F%E5%85%B4%E8%B6%A3.meta.js // ==/UserScript== /* jshint ignore:start */ var MultiString = function(f) { return f.toString().split('\n').slice(1, -1).join('\n'); } /* jshint ignore:end */ var inline_src = MultiString(function() {/** (async() => { 'use strict'; const MAX_FILTER_COUNT = 100; //最多主动刷新的条目数 const USER_ID_KEY = "user-id"; const USER_TOPICS_KEY = "user-topics"; window.GM_xmlhttpRequest = GM_xmlhttpRequest let GET = (url, headers) => { return new Promise((resolve, reject) => { let req = GM_xmlhttpRequest({ method:"GET", url: url, headers: headers, fetch: true, onerror: ()=>reject(`fetch ${url} failed`), onload: (e)=>resolve(e.responseText) }); }); }; let getUserId = async () => { let raw = await GET("/api/v4/me"); let data = JSON.parse(raw); return data.url_token; }; let userId = GM_getValue(USER_ID_KEY, null); if (!userId) { userId = await getUserId(); GM_setValue(USER_ID_KEY, userId); } else { setTimeout(async () => { let newValue = await getUserId(); if (newValue != userId) { userId = newValue; GM_setValue(USER_ID_KEY, userId); } }, 1000); } let getUserTopics = async (uid) => { //以下部分获取用户关注话题 let isEnd = true; let offset = 0; let topics = []; do { let raw = await GET(`/api/v4/members/${uid}/following-topic-contributions?offset=${offset}&limit=20`); let batch = JSON.parse(raw); isEnd = batch.paging.is_end; topics = topics.concat(batch.data.map(e => e.topic.name)); offset += batch.data.length; } while(!isEnd); console.log("your followed topics", topics); return topics; }; let followedTopics = GM_getValue(USER_TOPICS_KEY, null); if (!followedTopics) { followedTopics = await getUserTopics(userId); GM_setValue(USER_TOPICS_KEY, followedTopics); } else { setTimeout(async ()=> { let newValue = await getUserTopics(userId); if (newValue != followedTopics) { followedTopics = newValue; GM_setValue(USER_TOPICS_KEY, followedTopics); } }, 1000); } //全局中没被隐藏的卡片数 let nonHiddenCards = 0; let allCards = 0; let fillNewCards = () => setTimeout(() => window.dispatchEvent(new Event("resize"))); //发送resize事件来补充新的内容 //检查函数 let checkCards = async (cards) => { if (cards.length == 0) return; await Promise.all(cards.map(async(e) => { try{ if (e.hidden) return; allCards++; let answerUrl = e.querySelector("h2.ContentItem-title a"); if (!answerUrl) { console.log(e, 'is not checked'); return; } e.hidden = true; let realUrl = answerUrl.getAttribute('href'); if (realUrl.startsWith('//')) { //知乎专栏链接特殊处理 realUrl = "https:"+realUrl //GM_xmlhttpRequest不能识别//开头的链接,需要手动加https } let questionPage = await GET(realUrl); let parser = new DOMParser(); let page = parser.parseFromString(questionPage, "text/html"); let topics = page.querySelector("meta[itemProp=keywords]"); if (topics) { //知乎回答通过这里筛选话题 topics = topics.content.split(','); } else if (realUrl.search("zvideo") == -1) { //专栏文章通过这里筛选话题 topics = [...page.querySelectorAll("#root > div > main > div > article > div.Post-topicsAndReviewer > div > div > span > a > div")].map(e=>e.textContent); } else { // 是视频号 topics = [...page.querySelectorAll("#root > div > main > article > div.ZVideo-mainColumn > div.ZVideo-tags > div > a")].map(e=>e.textContent); } topics = topics.filter(e=>e) if (topics.length == 0) { console.warn(answerUrl, "got empty topics"); return; } if (topics.filter(v=>followedTopics.indexOf(v) != -1).length == 0) { //如果里面没有一个话题是用户关注的 console.log(topics, "hide", e); } else { console.log(topics, "not hide"); nonHiddenCards++; e.hidden = false; } } catch(x) { console.log(x, e); e.hidden = false; } finally { if (e.hidden) { setTimeout(()=>e.remove()); } } })); if (nonHiddenCards < 8 && allCards < MAX_FILTER_COUNT) { console.log(`too few cards (${nonHiddenCards}/${allCards}) requesting for more...`); fillNewCards(); } else if (nonHiddenCards < 8 && allCards >= MAX_FILTER_COUNT) { let option = { text: `知乎-我不感兴趣 已为您过滤了 ${allCards-nonHiddenCards} 条推送,仍然没有足够的条目填满您的主页,您可以去喝杯茶,看看别的东西。`, title: "主动刷新已停止", onclick: console.log, ondone: console.log }; GM_notification(option, null); nonHiddenCards = 8; } }; //注册钩子 let registerHook = () => { let firstCard = document.querySelector("div.Card.TopstoryItem"); if (!firstCard) { setTimeout(registerHook, 500); } let mainFrame = firstCard.parentElement; let ob = new MutationObserver((records) => { //console.log("mutation records: ", records); let addedCards = records.reduce((r, e) => r.concat([...e.addedNodes]), []); checkCards(addedCards); }); let config = { childList: true }; ob.observe(mainFrame, config); console.log("hooked"); nonHiddenCards = 0; allCards = 0; checkCards([...mainFrame.children]); }; let parentFrame = document.querySelector("div#TopstoryContent"); let config = { childList: true }; let ob = new MutationObserver((records) => { //console.log("mutation records: ", records); setTimeout(registerHook, 500); console.log("rehook emitted"); }); ob.observe(parentFrame, config); registerHook(); //进行首次检查,这里不DRY })(); /**/}); /* jshint ignore:start */ var c = Babel.transform(inline_src, { presets: [ "es2015", "es2016", "es2017" ] }); console.log(c.code); eval(c.code); //eval(inline_src); /* jshint ignore:end */