您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
基于关键词实现的广告动态屏蔽,支持用户自定义关键词 (原作者: QingMu_, Assistant; 二开: lsw)
// ==UserScript== // @name B站广告动态屏蔽 (二开版) // @namespace http://tampermonkey.net/ // @version 0.1 // @description 基于关键词实现的广告动态屏蔽,支持用户自定义关键词 (原作者: QingMu_, Assistant; 二开: lsw) // @author QingMu_, Assistant, lsw // @match https://t.bilibili.com/* // @icon https://static.hdslb.com/images/favicon.ico // @license MIT // ==/UserScript== (function() { 'use strict'; // --- 配置 --- const STORAGE_KEY = 'bilibiliAdBlockKeywords_v1.4'; // 版本化键名,避免冲突 const DEFAULT_KEYWORDS = [ "淘宝闪购", "美团外卖", ]; const PLACEHOLDER_TEXT_PREFIX = "检测到关键词 '"; const PLACEHOLDER_TEXT_SUFFIX = "',广告已屏蔽"; const OBSERVER_CONFIG = { childList: true, subtree: true }; const RETRY_INTERVAL = 500; const MAX_RETRIES = 20; // --- 状态变量 --- let BLOCKED_KEYWORDS = []; let retryCount = 0; let settingsPanel = null; // 缓存设置面板元素 // --- UI 样式 --- const UI_STYLES = ` #bilibili-adblock-settings-btn { position: fixed; top: 120px; /* 放在默认播放速度按钮下方 */ right: 10px; z-index: 10000; padding: 8px 12px; background-color: #00a1d6; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; box-shadow: 0 2px 4px rgba(0,0,0,0.2); transition: background-color 0.3s; } #bilibili-adblock-settings-btn:hover { background-color: #00b5e5; } #bilibili-adblock-settings-panel { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 500px; max-height: 80vh; background-color: white; border: 1px solid #ccc; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.3); z-index: 10001; padding: 20px; display: none; /* 默认隐藏 */ flex-direction: column; font-family: Arial, sans-serif; } #bilibili-adblock-settings-panel h2 { margin-top: 0; margin-bottom: 15px; text-align: center; } #bilibili-adblock-keyword-list { list-style: none; padding: 0; margin: 0 0 15px 0; border: 1px solid #ddd; border-radius: 4px; max-height: 200px; overflow-y: auto; } #bilibili-adblock-keyword-list li { padding: 8px 12px; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center; } #bilibili-adblock-keyword-list li:last-child { border-bottom: none; } .bilibili-adblock-keyword-text { flex-grow: 1; word-break: break-all; } .bilibili-adblock-delete-btn { background-color: #ff4d4f; color: white; border: none; border-radius: 4px; padding: 4px 8px; cursor: pointer; font-size: 12px; } .bilibili-adblock-delete-btn:hover { background-color: #ff7875; } #bilibili-adblock-add-section { display: flex; margin-bottom: 15px; } #bilibili-adblock-new-keyword { flex-grow: 1; padding: 8px; border: 1px solid #ccc; border-radius: 4px 0 0 4px; font-size: 14px; } #bilibili-adblock-add-btn { padding: 8px 12px; background-color: #00a1d6; color: white; border: none; border-radius: 0 4px 4px 0; cursor: pointer; font-size: 14px; } #bilibili-adblock-add-btn:hover { background-color: #00b5e5; } #bilibili-adblock-panel-actions { display: flex; justify-content: space-between; } .bilibili-adblock-panel-btn { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; } #bilibili-adblock-save-btn { background-color: #00a1d6; color: white; } #bilibili-adblock-save-btn:hover { background-color: #00b5e5; } #bilibili-adblock-close-btn, #bilibili-adblock-reset-btn { background-color: #f0f0f0; color: #333; } #bilibili-adblock-close-btn:hover, #bilibili-adblock-reset-btn:hover { background-color: #e0e0e0; } #bilibili-adblock-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 10000; /* 略低于面板 */ display: none; /* 默认隐藏 */ } `; // --- 数据持久化 --- function loadKeywords() { try { const storedKeywords = localStorage.getItem(STORAGE_KEY); if (storedKeywords) { const parsed = JSON.parse(storedKeywords); if (Array.isArray(parsed)) { console.log("B站广告屏蔽: 已加载用户自定义关键词"); return parsed; } } } catch (e) { console.error("B站广告屏蔽: 加载关键词失败:", e); } console.log("B站广告屏蔽: 使用默认关键词"); return [...DEFAULT_KEYWORDS]; // 返回副本 } function saveKeywords(keywordsArray) { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(keywordsArray)); console.log("B站广告屏蔽: 关键词已保存到 localStorage"); return true; } catch (e) { console.error("B站广告屏蔽: 保存关键词失败:", e); alert("保存失败,请检查浏览器存储空间或权限设置。"); return false; } } // --- UI 创建与交互 --- function injectStyles() { if (!document.getElementById('bilibili-adblock-styles')) { const styleSheet = document.createElement("style"); styleSheet.id = 'bilibili-adblock-styles'; styleSheet.innerText = UI_STYLES; document.head.appendChild(styleSheet); } } function createSettingsUI() { // 防止重复创建 if (document.getElementById('bilibili-adblock-settings-btn')) return; // 创建遮罩层 const overlay = document.createElement('div'); overlay.id = 'bilibili-adblock-overlay'; overlay.addEventListener('click', closeSettingsPanel); document.body.appendChild(overlay); // 创建设置按钮 const settingsBtn = document.createElement('button'); settingsBtn.id = 'bilibili-adblock-settings-btn'; settingsBtn.textContent = '屏蔽设置'; settingsBtn.addEventListener('click', openSettingsPanel); document.body.appendChild(settingsBtn); // 创建设置面板 const panel = document.createElement('div'); panel.id = 'bilibili-adblock-settings-panel'; panel.innerHTML = ` <h2>B站广告屏蔽设置</h2> <ul id="bilibili-adblock-keyword-list"></ul> <div id="bilibili-adblock-add-section"> <input type="text" id="bilibili-adblock-new-keyword" placeholder="输入新关键词"> <button id="bilibili-adblock-add-btn">添加</button> </div> <div id="bilibili-adblock-panel-actions"> <button id="bilibili-adblock-reset-btn" class="bilibili-adblock-panel-btn">重置为默认</button> <div> <button id="bilibili-adblock-close-btn" class="bilibili-adblock-panel-btn">取消</button> <button id="bilibili-adblock-save-btn" class="bilibili-adblock-panel-btn">保存</button> </div> </div> `; document.body.appendChild(panel); settingsPanel = panel; // 缓存面板引用 // 绑定事件 document.getElementById('bilibili-adblock-add-btn').addEventListener('click', addKeywordFromInput); document.getElementById('bilibili-adblock-new-keyword').addEventListener('keypress', function(e) { if (e.key === 'Enter') addKeywordFromInput(); }); document.getElementById('bilibili-adblock-save-btn').addEventListener('click', saveSettings); document.getElementById('bilibili-adblock-close-btn').addEventListener('click', closeSettingsPanel); document.getElementById('bilibili-adblock-reset-btn').addEventListener('click', resetToDefaults); } function openSettingsPanel() { if (!settingsPanel) return; populateKeywordList(); // 打开时更新列表 document.getElementById('bilibili-adblock-overlay').style.display = 'block'; settingsPanel.style.display = 'flex'; document.getElementById('bilibili-adblock-new-keyword').focus(); } function closeSettingsPanel() { if (!settingsPanel) return; document.getElementById('bilibili-adblock-overlay').style.display = 'none'; settingsPanel.style.display = 'none'; } function populateKeywordList(keywords = BLOCKED_KEYWORDS) { const listElement = document.getElementById('bilibili-adblock-keyword-list'); listElement.innerHTML = ''; // 清空现有列表 keywords.forEach(keyword => { const li = document.createElement('li'); li.innerHTML = ` <span class="bilibili-adblock-keyword-text">${keyword}</span> <button class="bilibili-adblock-delete-btn" data-keyword="${keyword}">删除</button> `; listElement.appendChild(li); }); // 为新添加的删除按钮绑定事件 listElement.querySelectorAll('.bilibili-adblock-delete-btn').forEach(btn => { btn.addEventListener('click', function() { const keywordToRemove = this.getAttribute('data-keyword'); removeFromKeywordList(keywordToRemove); }); }); } function addKeywordFromInput() { const input = document.getElementById('bilibili-adblock-new-keyword'); const newKeyword = input.value.trim(); if (newKeyword && !BLOCKED_KEYWORDS.includes(newKeyword)) { BLOCKED_KEYWORDS.push(newKeyword); populateKeywordList(); // 更新UI input.value = ''; // 清空输入框 } else if (newKeyword && BLOCKED_KEYWORDS.includes(newKeyword)) { alert("关键词已存在!"); } input.focus(); } function removeFromKeywordList(keyword) { BLOCKED_KEYWORDS = BLOCKED_KEYWORDS.filter(k => k !== keyword); populateKeywordList(); // 更新UI } function resetToDefaults() { if (confirm("确定要重置为默认关键词列表吗?")) { BLOCKED_KEYWORDS = [...DEFAULT_KEYWORDS]; populateKeywordList(); // 更新UI } } function saveSettings() { // 从UI列表中获取当前关键词(更安全) const currentKeywords = []; document.querySelectorAll('#bilibili-adblock-keyword-list .bilibili-adblock-keyword-text').forEach(span => { currentKeywords.push(span.textContent); }); BLOCKED_KEYWORDS = currentKeywords; if (saveKeywords(BLOCKED_KEYWORDS)) { closeSettingsPanel(); blockAds(); // 应用新规则 console.log("B站广告屏蔽: 设置已保存并应用"); } } // --- 核心屏蔽逻辑 --- function getDynamicItems() { return document.querySelectorAll(".bili-dyn-item__main"); } function findBlockedKeyword(text) { return BLOCKED_KEYWORDS.find(keyword => text.includes(keyword) ) || null; } function blockAds() { try { const dynamicItems = getDynamicItems(); dynamicItems.forEach((item) => { if (item.innerText) { const matchedKeyword = findBlockedKeyword(item.innerText); if (matchedKeyword) { const bodyElement = item.querySelector('.bili-dyn-item__body'); if (bodyElement && !bodyElement.dataset.blocked) { bodyElement.dataset.blocked = 'true'; bodyElement.style.display = 'none'; const placeholder = document.createElement('div'); placeholder.className = 'ad-blocked-placeholder'; placeholder.style.cssText = ` color: #999; font-style: italic; padding: 15px 20px; border: 1px dashed #ccc; border-radius: 4px; margin: 10px 0; background-color: #f9f9f9; `; placeholder.textContent = `${PLACEHOLDER_TEXT_PREFIX}${matchedKeyword}${PLACEHOLDER_TEXT_SUFFIX}`; bodyElement.parentNode.insertBefore(placeholder, bodyElement.nextSibling); } } } }); } catch (error) { console.error("B站广告屏蔽脚本执行出错:", error); } } // --- 脚本初始化 --- function initializeScript() { BLOCKED_KEYWORDS = loadKeywords(); // 1. 加载关键词 injectStyles(); // 2. 注入样式 createSettingsUI(); // 3. 创建UI startObserver(); // 4. 启动监听 console.log("B站广告屏蔽脚本 (v1.4) 已初始化"); } function startObserver() { const targetNode = document.querySelector(".bili-dyn-list"); if (targetNode) { blockAds(); // Initial run const observer = new MutationObserver(blockAds); observer.observe(targetNode, OBSERVER_CONFIG); console.log("B站广告屏蔽脚本已启动并开始监听。"); } else if (retryCount < MAX_RETRIES) { retryCount++; console.log(`B站广告屏蔽: 等待动态列表加载... (${retryCount}/${MAX_RETRIES})`); setTimeout(startObserver, RETRY_INTERVAL); } else { console.warn("B站广告屏蔽脚本:未能找到动态列表容器 '.bili-dyn-list',脚本可能需要更新或已失效。"); } } // --- 启动 --- if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", initializeScript); } else { initializeScript(); } })();