// ==UserScript== // @name 让MCN闪耀,让荣誉的勋章更容易看到! // @namespace mcn.is.very.very.good // @version 1.0.0 // @description 发现更大的世界和更多的软广! // @author Dislike soft AD // @match https://www.zhihu.com/* // @license MIT // @grant unsafeWindow // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @downloadURL none // ==/UserScript== (async () => { 'use strict'; // 请不要将这里改为 true,否则将会在机构前增加一个emoji表情,这可能会增加攻击性。 const useIcon = false; const setCache = (name, data) => { const cache = JSON.parse(localStorage.getItem('mcnCache')) || {}; cache[name] = data; localStorage.setItem('mcnCache', JSON.stringify(cache)); updateMenu(); } const getCache = (name) => { const cache = JSON.parse(localStorage.getItem('mcnCache')) || {}; return cache[name]; } const setNoMcn = (name) => { const noMcn = new Set(JSON.parse(localStorage.getItem('noMcn')) || []); noMcn.add(name); localStorage.setItem('noMcn', JSON.stringify(Array.from(noMcn))); } const isNoMcn = (name) => { const noMcn = new Set(JSON.parse(localStorage.getItem('noMcn')) || []); return noMcn.has(name); } const promiseMap = {}; const getAuthorMcn = async (token) => { const cache = getCache(token); if(cache?.mcn) return cache.mcn; if(isNoMcn(token)) return null; if(promiseMap[token]) { return promiseMap[token]; } promiseMap[token] = new Promise(async (resolve) => { const url = `https://www.zhihu.com/people/${token}`; const html = await fetch(url) .then(response => response.text()); const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const initialData = doc.querySelector('#js-initialData'); const json = initialData.textContent; const data = JSON.parse(json); console.log(token); const mcn = data?.initialState?.entities?.users?.[token]?.mcnCompany; if(mcn) { setCache(token, { mcn, nickname: data?.initialState?.entities?.users?.[token]?.name ?? token, }); } else { setNoMcn(token); } resolve(mcn); promiseMap[token] = null; }); return promiseMap[token]; } const addMcnBadge = async (authorDom) => { if(authorDom.querySelector('.mcn-badge')) return; const box = authorDom.querySelector('.AuthorInfo-head'); const mcnBadge = document.createElement('span'); mcnBadge.className = 'mcn-badge'; mcnBadge.textContent = 'Loading...'; mcnBadge.style.marginLeft = '5px'; mcnBadge.style.display = 'inline-block'; mcnBadge.style.color = '#DDD'; mcnBadge.style.fontSize = '12px'; mcnBadge.style.padding = '2px'; box.appendChild(mcnBadge); const userLink = authorDom.querySelector('.UserLink-link'); if(!userLink) return; const link = userLink.getAttribute('href'); const name = link.split('/').pop(); const mcn = await getAuthorMcn(name); console.log("test", mcn, name); if (mcn) { mcnBadge.textContent = mcn; mcnBadge.style.marginLeft = '5px'; mcnBadge.style.display = 'inline-block'; mcnBadge.style.color = '#FFFFFF'; mcnBadge.style.backgroundColor = '#FF0000'; mcnBadge.style.borderRadius = '3px'; mcnBadge.style.fontSize = '12px'; mcnBadge.style.padding = '2px'; if (useIcon) { mcnBadge.textContent = '🐕‍🦺' + mcn; mcnBadge.style.backgroundColor = null; mcnBadge.style.color = "#FF0000"; } mcnBadge.title = "如果是被包养了,就不要谈独立人格" } else { mcnBadge.textContent = "No MCN"; } } const blockAuthor = async (name) => { const url = `https://www.zhihu.com/api/v4/members/${name}/actions/block`; const response = await fetch(url, { method: 'POST', credentials: 'include', }); console.log(response); return response.status === 204; } const getMcnAuthorMap = () => { const cache = JSON.parse(localStorage.getItem('mcnCache')) || {}; const mcnMap = {}; for(const [name, data] of Object.entries(cache)) { if(!mcnMap[data.mcn]) { mcnMap[data.mcn] = []; } mcnMap[data.mcn].push({token: name, ...data}); } return mcnMap; } if (typeof unsafeWindow === 'undefined') { window.unsafeWindow = window; } const mcn = unsafeWindow.mcn = () => { const mcnMap = getMcnAuthorMap(); console.group('MCN Map'); for(const [mcn, list] of Object.entries(mcnMap)) { console.groupCollapsed(mcn + ' (' + list.length + ')'); for(const data of list) { console.log(data.token, "\t", data.nickname, "\t", `https://www.zhihu.com/people/${data.token}`); } console.groupEnd(); } console.groupEnd(); } const blockMcn = unsafeWindow.blockMcn = async (name) => { const mcnMap = getMcnAuthorMap(); const authors = mcnMap[name] || []; if (!authors.length) { console.error('没有找到已记录的MCN作者 ' + name); return; } for (const author of authors) { const result = await blockAuthor(author.token); if (result) { console.log(`已屏蔽 ${author.token} ${author.nickname}`); } else { console.error(`屏蔽失败 ${author.token} ${author.nickname}`); } }; console.log("全部完成"); alert("全部完成"); } const headDom = document.querySelector('head'); const hiddenContent = unsafeWindow.hiddenContent = () => { const style = document.createElement('style'); style.id = 'hiddenContent'; style.textContent = ` .RichContent { display: none !important; } .LabelContainer-wrapper { display: none !important; } `; headDom.appendChild(style); } const showContent = unsafeWindow.showContent = () => { const style = document.querySelector('style#hiddenContent'); if (style) { style.remove(); } } let observer; function runObserver() { if (observer) observer.disconnect(); const handle = (node) => { if (node.classList && node.classList.contains('AuthorInfo')) { setTimeout(() => { addMcnBadge(node); }); } } // MutationObserver observer = new MutationObserver((mutationsList, observer) => { for (let mutation of mutationsList) { if (mutation.type === "attributes") { handle(mutation.target); } else { for (const node of mutation.addedNodes) { handle(node); if (node.childNodes) { const nodeIterator = document.createNodeIterator(node); let childNode = nodeIterator.nextNode(); while (childNode) { handle(childNode); childNode = nodeIterator.nextNode(); } } } } } }); const targetNode = window.document.documentElement; observer.observe(targetNode, { childList: true, subtree: true }); } const mcnMenuId = []; const updateMenu = () => { if(typeof GM_registerMenuCommand === 'undefined'){ return; } try { mcnMenuId.forEach(id => { GM_unregisterMenuCommand(id); }) const mcnMap = getMcnAuthorMap(); for(const [mcn, list] of Object.entries(mcnMap)) { const id = GM_registerMenuCommand(`屏蔽 ${mcn} (${list.length})`, async () => { if (!confirm(`确定要屏蔽 ${mcn} (${list.length}) 吗?\n${list.map(v => v.nickname).join(', ')}`)) { return; } await blockMcn(mcn); }); mcnMenuId.push(id); } } catch (error) { console.error(error); } } if(typeof GM_registerMenuCommand !== 'undefined') { GM_registerMenuCommand("隐藏回答正文", function(event) { hiddenContent(); }); GM_registerMenuCommand("显示回答正文", function(event) { showContent(); }); GM_registerMenuCommand("清理缓存", function(event) { localStorage.removeItem('mcnCache'); localStorage.removeItem('noMcn'); updateMenu(); }); updateMenu(); } runObserver(); const authorDomList = document.querySelectorAll('.AuthorInfo'); for(const authorDom of authorDomList) { await addMcnBadge(authorDom); } })();