您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
发现更大的世界和更多的软广!
// ==UserScript== // @name 让MCN闪耀,让荣誉的勋章更容易看到! // @namespace mcn.is.very.very.good // @version 1.0.3 // @description 发现更大的世界和更多的软广! // @author Dislike soft AD // @license MIT // @match https://www.zhihu.com/* // @grant unsafeWindow // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_setClipboard // ==/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, manual = false) => { const cache = getCache(token); if (cache?.mcn) return cache.mcn; if (isNoMcn(token)) return false; // false is no mcn, null is no record if (promiseMap[token]) { return promiseMap[token]; } const autoLoad = localStorage.getItem('mcnAutoLoad') || false; if (!autoLoad && !manual) { return null; } 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 || false); promiseMap[token] = null; }); return promiseMap[token]; } const clearBadge = (mcnBadge) => { mcnBadge.onclick = null; mcnBadge.style.cursor = null; mcnBadge.style.border = null; mcnBadge.style.backgroundColor = null; 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'; mcnBadge.style.borderRadius = '3px'; } const updateBadge = (mcnBadge, token, mcn) => { clearBadge(mcnBadge); if (mcn) { mcnBadge.textContent = mcn; mcnBadge.style.marginLeft = '5px'; mcnBadge.style.display = 'inline-block'; mcnBadge.style.color = '#FFFFFF'; mcnBadge.style.backgroundColor = '#FF0000'; if (useIcon) { mcnBadge.textContent = '🐕🦺' + mcn; mcnBadge.style.backgroundColor = null; mcnBadge.style.color = "#FF0000"; } mcnBadge.title = "如果是被包养了,就不要谈独立人格" } else if (mcn === false) { mcnBadge.textContent = "No MCN"; } else { mcnBadge.textContent = "点击加载MCN"; mcnBadge.style.cursor = 'pointer'; mcnBadge.style.color = '#aaa'; mcnBadge.style.backgroundColor = '#FFFFFF'; mcnBadge.style.border = '1px solid #aaa'; mcnBadge.style.padding = '1px'; mcnBadge.onclick = async () => { clearBadge(mcnBadge); const mcn = await getAuthorMcn(token, true); updateBadge(mcnBadge, token, mcn); }; } } const addMcnBadge = async (authorDom) => { if (authorDom.querySelector('.mcn-badge')) return; const box = authorDom.querySelector('.AuthorInfo-head'); const mcnBadge = document.createElement('span'); box.appendChild(mcnBadge); const userLink = authorDom.querySelector('.UserLink-link'); if (!userLink) return; const link = userLink.getAttribute('href'); const token = link.split('/').pop(); clearBadge(mcnBadge); const mcn = await getAuthorMcn(token); updateBadge(mcnBadge, token, mcn); } const addQuestionerMcnBadge = async (dom) => { console.log('addQuestionerMcnBadge', dom); if (!dom) return; if(dom.querySelector('.mcn-badge')) return; const link = dom.querySelector('.BrandQuestionSymbol-brandLink'); if (!link) return; const token = link.getAttribute('href').split('/').pop(); console.log('token', token); const mcnBadge = document.createElement('span'); // push BrandQuestionSymbol-brandLink next dom.insertBefore(mcnBadge, link.nextSibling); clearBadge(mcnBadge, token, null); const mcn = await getAuthorMcn(token); updateBadge(mcnBadge, token, 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?.contains('AuthorInfo')) { setTimeout(() => { addMcnBadge(node); }); } if (node.classList?.contains('BrandQuestionSymbol')) { setTimeout(() => { addQuestionerMcnBadge(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 = []; let showMcnList = false; const updateMenu = () => { if (typeof GM_registerMenuCommand === 'undefined') { return; } try { mcnMenuId.forEach(id => { GM_unregisterMenuCommand(id); }); const isAuto = localStorage.getItem('mcnAutoLoad') || false; const autoLoadId = GM_registerMenuCommand(`自动加载MCN(当前:${isAuto ? '自动': '手动'})`, function (event) { localStorage.setItem('mcnAutoLoad', isAuto ? '' : '1'); updateMenu(); }); mcnMenuId.push(autoLoadId); const hasHCstyle = document.querySelector('style#hiddenContent'); if (hasHCstyle) { mcnMenuId.push(GM_registerMenuCommand("显示回答正文(当前:隐藏)", function (event) { showContent(); updateMenu(); })); } else { mcnMenuId.push(GM_registerMenuCommand("隐藏回答正文(当前:显示)", function (event) { hiddenContent(); updateMenu(); })); } mcnMenuId.push(GM_registerMenuCommand("复制表格", function (event) { const mcnMap = getMcnAuthorMap(); const textList = []; for (const [mcn, list] of Object.entries(mcnMap)) { for (const data of list) { textList.push(`${mcn}\t${data.token}\t${data.nickname}\thttps://www.zhihu.com/people/${data.token}`); } } GM_setClipboard(textList.join('\n')); })); mcnMenuId.push(GM_registerMenuCommand("清理缓存", function (event) { if (!confirm('确定要清理缓存吗?')) return; localStorage.removeItem('mcnCache'); localStorage.removeItem('noMcn'); updateMenu(); })); mcnMenuId.push(GM_registerMenuCommand(`${showMcnList ? '▼' : '▶'} 显示MCN列表${showMcnList ? '' : ' (需再次打开菜单)'}`, function (event) { showMcnList = !showMcnList; updateMenu(); }, { autoClose: true })); if (showMcnList) { 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') { updateMenu(); } runObserver(); addQuestionerMcnBadge(); const authorDomList = document.querySelectorAll('.AuthorInfo'); for (const authorDom of authorDomList) { await addMcnBadge(authorDom); } })();