您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在贴吧吧页隐藏黑名单用户发布的主题帖。
// ==UserScript== // @name 贴吧屏蔽主题帖 // @namespace https://example.com/tieba-thread-blacklist // @version 1.7.3 // @description 在贴吧吧页隐藏黑名单用户发布的主题帖。 // @author you // @match https://tieba.baidu.com/f?kw=* // @match https://tieba.baidu.com/f/*?kw=* // @run-at document-idle // @grant GM_getValue // @grant GM_setValue // @grant GM_addStyle // ==/UserScript== (function () { 'use strict'; const STORAGE_KEY = 'tieba_thread_blacklist_users'; const PANEL_ID = 'tb-blk-panel'; const normalize = (name) => (name || '').replace(/\u200B/g, '').replace(/\s+/g, '').trim().toLowerCase(); function getList() { const raw = GM_getValue(STORAGE_KEY, []); return Array.from(new Set(raw.map(normalize).filter(Boolean))); } function setList(arr) { GM_setValue(STORAGE_KEY, Array.from(new Set(arr.map(normalize).filter(Boolean)))); refreshPanel(); scheduleScan(); } function addUsers(users) { const cur = new Set(getList()); users.map(normalize).filter(Boolean).forEach((u) => cur.add(u)); setList(Array.from(cur)); } function removeUsers(users) { const cur = new Set(getList()); users.map(normalize).filter(Boolean).forEach((u) => cur.delete(u)); setList(Array.from(cur)); } function ensurePanel() { if (document.getElementById(PANEL_ID)) return; GM_addStyle(` #${PANEL_ID}{ position: fixed; z-index: 99999; right: 16px; bottom: 24px; background: rgba(0,0,0,.75); color: #fff; border-radius: 12px; padding: 8px 10px; font: 12px/1.4 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue","PingFang SC","Noto Sans CJK SC","Microsoft YaHei",sans-serif; max-height: 240px; width: 220px; overflow-y: auto; overflow-x: hidden; box-shadow: 0 4px 12px rgba(0,0,0,.3); } #${PANEL_ID}::-webkit-scrollbar { width: 6px; } #${PANEL_ID}::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.4); border-radius: 3px; } #${PANEL_ID}::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.7); } #${PANEL_ID}::-webkit-scrollbar-track { background: transparent; } #${PANEL_ID}.minimized {padding:6px 10px; cursor:pointer; height:auto; max-height:none; overflow:visible;} #${PANEL_ID}.minimized .content {display:none;} #${PANEL_ID} button{ cursor:pointer; border:none; border-radius: 6px; padding: 3px 6px; background:#fff; color:#111; font-weight:600; font-size:12px; } #${PANEL_ID} button.ghost{ background:transparent; color:#fff; border:1px solid rgba(255,255,255,.4); } #${PANEL_ID} .topbar{display:flex; justify-content:space-between; align-items:center; margin-bottom:6px;} #${PANEL_ID} .min-btn{ background:transparent; color:#fff; border:none; font-size:14px; cursor:pointer; } #${PANEL_ID} .list{ margin-top:6px; display:flex; flex-direction:column; gap:4px; } #${PANEL_ID} .row-item{ display:flex; justify-content:flex-start; align-items:center; background:rgba(255,255,255,.1); padding:2px 6px; border-radius:6px; } #${PANEL_ID} .row-item span.username{ display:inline-block; max-width:80%; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; } #${PANEL_ID} .row-item .del{ cursor:pointer; color:#ff6666; font-weight:bold; margin-right:6px; flex-shrink:0; } .tb-blk-laji{ display:inline-block; margin-left:4px; cursor:pointer; color:#999; font-size:12px; } .tb-blk-laji:hover{ color:#f55; text-decoration:underline; } `); const div = document.createElement('div'); div.id = PANEL_ID; div.classList.add("minimized"); // 默认最小化 div.innerHTML = ` <div class="topbar"> <div><strong>黑名单</strong> <span class="muted">(${getList().length})</span></div> <button class="min-btn" title="最小化/展开">-</button> </div> <div class="content"> <div class="row"> <button id="tb-blk-add">添加</button> <button id="tb-blk-remove" class="ghost">删除</button> <button id="tb-blk-export" class="ghost">导出</button> <button id="tb-blk-import" class="ghost">导入</button> </div> <div class="list" id="tb-blk-list"></div> </div> `; document.body.appendChild(div); div.querySelector('.min-btn').addEventListener('click', () => { div.classList.toggle('minimized'); }); div.querySelector('#tb-blk-add').onclick = () => { const v = prompt('添加用户,多个用空格或逗号:', ''); if (v) addUsers(v.split(/[,\s]+/)); }; div.querySelector('#tb-blk-remove').onclick = () => { const v = prompt('移除用户,多个用空格或逗号:', ''); if (v) removeUsers(v.split(/[,\s]+/)); }; div.querySelector('#tb-blk-export').onclick = () => { alert(JSON.stringify(getList(), null, 2)); }; div.querySelector('#tb-blk-import').onclick = () => { const v = prompt('粘贴导入 JSON:', ''); if (v) { try { addUsers(JSON.parse(v)); } catch { alert('JSON 格式错误'); } } }; refreshPanel(); } function refreshPanel() { const list = getList(); const el = document.querySelector(`#${PANEL_ID} .muted`); if (el) el.textContent = `(${list.length})`; const listEl = document.getElementById('tb-blk-list'); if (!listEl) return; listEl.innerHTML = ''; list.forEach((u) => { const row = document.createElement('div'); row.className = 'row-item'; row.innerHTML = `<span class="del">✕</span><span class="username" title="${u}">${u}</span>`; row.querySelector('.del').onclick = () => removeUsers([u]); listEl.appendChild(row); }); } function getAuthorFromCard(card) { try { const df = card.getAttribute('data-field'); if (df) { const obj = JSON.parse(df); if (obj?.author_name) return obj.author_name; } const a = card.querySelector('.tb_icon_author'); if (a) return a.title || a.textContent; const b = card.querySelector('.threadlist_author, .frs-author-name'); if (b) return b.title || b.textContent; } catch {} return ''; } function hideIfBlacklisted(card, bl) { if (card.dataset._tbblk_done) return; const author = normalize(getAuthorFromCard(card)); if (!author) return; injectBlockButton(card, author); if (bl.has(author)) { card.style.display = 'none'; } card.dataset._tbblk_done = '1'; } function injectBlockButton(card, author) { if (card.querySelector('.tb-blk-laji')) return; const target = card.querySelector('.frs-author-name, .tb_icon_author, .threadlist_author_name'); if (!target) return; const btn = document.createElement('span'); btn.textContent = '[拉黑]'; btn.className = 'tb-blk-laji'; btn.onclick = (e) => { e.stopPropagation(); addUsers([author]); card.style.display = 'none'; alert(`已拉黑用户:${author}`); }; target.insertAdjacentElement('afterend', btn); } function scanOnce() { const bl = new Set(getList()); document.querySelectorAll('.j_thread_list, [data-field]').forEach((card) => { hideIfBlacklisted(card, bl); }); } let timer; function scheduleScan() { clearTimeout(timer); timer = setTimeout(scanOnce, 200); } const mo = new MutationObserver(scheduleScan); function startObserver() { mo.observe(document.body, { childList: true, subtree: true }); } function init() { if (!/\/f\?kw=/i.test(location.href)) return; ensurePanel(); startObserver(); scheduleScan(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else init(); })();