// ==UserScript==
// @name 哔哩哔哩广告全面屏蔽 & 导航精简
// @version 3.2
// @description 屏蔽视频底部广告/活动横幅、侧边栏广告及底部推广、推荐流广告视频、小型广告卡片、视频底部标签、首页轮播、花生平台广告、直播页广告等,完全避开评论区,带UI开关控制,并支持导航栏精简
// @author MRBANK
// @match *://*.bilibili.com/*
// @icon https://www.bilibili.com/favicon.ico
// @grant GM_registerMenuCommand
// @run-at document-end
// ==/UserScript==
// @downloadURL https://cdn.jsdelivr.net/gh/hangzai1667/my-tampermonkey-scripts@main/bilibili.user.js
// @updateURL https://cdn.jsdelivr.net/gh/hangzai1667/my-tampermonkey-scripts@main/bilibili.user.js
(function() {
'use strict';
// ================= 配置管理 =================
const CONFIG_KEY = 'bilibili_purifier_config';
const defaultConfig = {
bottomBanner: true, // 1. 视频底部广告横幅
sideAd: true, // 2. 侧边栏广告(右侧浮动)
rightBottomAd: true, // 3. 侧边栏底部推广
smallAdCard: true, // 4. 小型广告卡片
feedAdVideo: true, // 5. 推荐流广告视频
videoTag: true, // 6. 视频底部标签
activityBanner: true, // 7. 视频底部活动横幅
homeCarouselAd: false, // 8. 首页轮播广告(默认关闭)
huashengBanner: true, // 9. 投稿菜单花生横幅
btnAd: true, // 10. 创作页按钮广告
liveBannerAd: true, // 11. 直播间轮播广告
// --- 导航栏精简 ---
hideAnime: false, // 番剧
hideLive: false, // 直播
hideGameCenter: false, // 游戏中心
hideMall: false, // 会员购
hideManga: false, // 漫画
hideMatch: false, // 赛事
hideDownload: false, // 下载客户端
hideVip: false // 大会员
};
const configStructure = [
{
groupName: "广告与推广",
items: [
{ key: 'bottomBanner', label: '视频底部广告横幅' },
{ key: 'sideAd', label: '侧边栏广告(浮动)' },
{ key: 'rightBottomAd', label: '侧边栏底部推广' },
{ key: 'smallAdCard', label: '小型广告卡片' },
{ key: 'feedAdVideo', label: '推荐流广告视频' },
{ key: 'homeCarouselAd', label: '首页轮播广告' },
{ key: 'huashengBanner', label: '投稿菜单花生横幅' },
{ key: 'btnAd', label: '创作页按钮广告' },
{ key: 'liveBannerAd', label: '直播间轮播广告' }
]
},
{
groupName: "页面元素精简",
items: [
{ key: 'videoTag', label: '视频底部标签' },
{ key: 'activityBanner', label: '视频底部活动横幅' }
]
},
{
groupName: "导航栏精简 (左侧+右侧)",
items: [
{ key: 'hideAnime', label: '隐藏 番剧' },
{ key: 'hideLive', label: '隐藏 直播' },
{ key: 'hideGameCenter', label: '隐藏 游戏中心' },
{ key: 'hideMall', label: '隐藏 会员购' },
{ key: 'hideManga', label: '隐藏 漫画' },
{ key: 'hideMatch', label: '隐藏 赛事' },
{ key: 'hideDownload', label: '隐藏 下载客户端' },
{ key: 'hideVip', label: '隐藏 大会员' }
]
}
];
function getConfig() {
let saved = localStorage.getItem(CONFIG_KEY);
if (saved) {
try {
let oldCfg = JSON.parse(saved);
if (oldCfg.leftBanner !== undefined && oldCfg.bottomBanner === undefined) {
oldCfg.bottomBanner = oldCfg.leftBanner;
delete oldCfg.leftBanner;
localStorage.setItem(CONFIG_KEY, JSON.stringify(oldCfg));
}
return {...defaultConfig, ...oldCfg};
}
catch(e) { return {...defaultConfig}; }
}
return {...defaultConfig};
}
function saveConfig(cfg) {
localStorage.setItem(CONFIG_KEY, JSON.stringify(cfg));
}
// ================= 油猴菜单与设置 UI =================
let isPanelOpen = false;
let needReload = false;
function openSettingsPanel() {
if (isPanelOpen) return;
isPanelOpen = true;
needReload = false;
const style = document.createElement('style');
style.id = 'bp-settings-style';
style.textContent = `
#bp-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.4); z-index: 999998; display: flex; align-items: center; justify-content: center; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; }
#bp-modal { background: #fff; width: 380px; border-radius: 8px; box-shadow: 0 10px 30px rgba(0,0,0,0.15); overflow: hidden; display: flex; flex-direction: column; }
#bp-header { display: flex; justify-content: space-between; align-items: center; padding: 15px 20px; border-bottom: 1px solid #e8e8e8; }
#bp-header h3 { margin: 0; font-size: 16px; color: #333; }
#bp-close-btn { background: none; border: none; font-size: 20px; color: #999; cursor: pointer; line-height: 1; padding: 0; }
#bp-close-btn:hover { color: #333; }
#bp-body { padding: 10px 0; max-height: 70vh; overflow-y: auto; }
.bp-group-title { padding: 10px 20px 5px; margin: 0; font-size: 13px; color: #888; font-weight: 500; }
.bp-switch-row { display: flex; justify-content: space-between; align-items: center; padding: 12px 20px; font-size: 14px; color: #333; transition: background 0.2s; }
.bp-switch-row:hover { background: #fff1f5; }
.bp-switch { position: relative; display: inline-block; width: 40px; height: 22px; flex-shrink: 0; }
.bp-switch input { opacity: 0; width: 0; height: 0; }
.bp-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .3s; border-radius: 22px; }
.bp-slider:before { position: absolute; content: ""; height: 16px; width: 16px; left: 3px; bottom: 3px; background-color: white; transition: .3s; border-radius: 50%; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.bp-switch input:checked + .bp-slider { background-color: #FB7299; }
.bp-switch input:checked + .bp-slider:before { transform: translateX(18px); }
`;
document.head.appendChild(style);
const overlay = document.createElement('div');
overlay.id = 'bp-overlay';
const modal = document.createElement('div');
modal.id = 'bp-modal';
const header = document.createElement('div');
header.id = 'bp-header';
const title = document.createElement('h3');
title.textContent = 'B站净化器 - 设置';
const closeBtn = document.createElement('button');
closeBtn.id = 'bp-close-btn';
closeBtn.textContent = '✕';
header.appendChild(title);
header.appendChild(closeBtn);
const body = document.createElement('div');
body.id = 'bp-body';
const cfg = getConfig();
configStructure.forEach(group => {
const groupTitle = document.createElement('div');
groupTitle.className = 'bp-group-title';
groupTitle.textContent = group.groupName;
body.appendChild(groupTitle);
group.items.forEach(item => {
const row = document.createElement('div');
row.className = 'bp-switch-row';
const label = document.createElement('span');
label.textContent = item.label;
const switchContainer = document.createElement('label');
switchContainer.className = 'bp-switch';
const input = document.createElement('input');
input.type = 'checkbox';
input.checked = cfg[item.key];
input.dataset.key = item.key;
const slider = document.createElement('span');
slider.className = 'bp-slider';
switchContainer.appendChild(input);
switchContainer.appendChild(slider);
row.appendChild(label);
row.appendChild(switchContainer);
body.appendChild(row);
input.addEventListener('change', (e) => {
const currentCfg = getConfig();
currentCfg[e.target.dataset.key] = e.target.checked;
saveConfig(currentCfg);
needReload = true;
});
});
});
modal.appendChild(header);
modal.appendChild(body);
overlay.appendChild(modal);
document.body.appendChild(overlay);
const closePanel = () => {
document.body.removeChild(overlay);
document.head.removeChild(style);
isPanelOpen = false;
if (needReload) location.reload();
};
closeBtn.addEventListener('click', closePanel);
overlay.addEventListener('click', (e) => {
if (e.target === overlay) closePanel();
});
}
GM_registerMenuCommand('🧹 B站净化器设置', openSettingsPanel);
// ================= 核心屏蔽逻辑 =================
// 广告选择器
const BOTTOM_BANNER_AD_SELECTOR = 'a.ad-report-inner[href*="cm.bilibili.com"], a.strip-ad[href*="cm.bilibili.com"], div.ad-report.strip-ad a[href*="cm.bilibili.com"]';
const SIDE_AD_SELECTOR = '#slide_ad, .slide-ad-exp';
const RIGHT_BOTTOM_AD_SELECTOR = 'div.ad-report.ad-floor-exp, div.right-bottom-banner';
const SMALL_AD_CARD_SELECTOR = '.video-card-ad-small';
const FEED_CONTAINER_SELECTOR = '.bili-feed4, .feed-list, .bili-video-card-list, .recommend-container, .video-page-special';
const VIDEO_TAG_SELECTOR = '.video-tag-container';
const ACTIVITY_BANNER_SELECTOR = '.inside-wrp';
const HOME_CAROUSEL_AD_SELECTOR = 'div.recommended-swipe';
const HUASHENG_BANNER_SELECTOR = 'a.upload-huasheng-banner';
const BTN_AD_SELECTOR = 'div.btn-ad';
// 直播间轮播广告:精确匹配包含特定数据类型的翻转容器,避免误伤
const LIVE_BANNER_AD_SELECTOR = 'div.flip-view:has(div[data-type="liveroom_banner_show"])';
// --- 导航栏选择器 ---
const NAV_ANIME_SELECTOR = 'li.v-popover-wrap:has(a.default-entry[href*="anime"])';
const NAV_LIVE_SELECTOR = 'li.v-popover-wrap:has(a.default-entry[href*="live.bilibili"])';
const NAV_GAME_SELECTOR = 'li.v-popover-wrap:has(a.default-entry[href*="game.bilibili"])';
const NAV_MALL_SELECTOR = 'li.v-popover-wrap:has(a.default-entry[href*="show.bilibili"])';
const NAV_MANGA_SELECTOR = 'li.v-popover-wrap:has(a.default-entry[href*="manga.bilibili"])';
const NAV_MATCH_SELECTOR = 'li.v-popover-wrap:has(a.default-entry[href*="match"])';
const NAV_DOWNLOAD_SELECTOR = 'li.v-popover-wrap:has(a.download-client-trigger)';
const NAV_VIP_SELECTOR = 'div.vip-wrap';
// 评论区根容器(绝不处理)
const COMMENT_ROOT_SELECTOR = '#comment-area, .comment-list-holder, .reply-list, .comment-container, .comment-list, .bili-comment';
const HIDE_MARKER = 'data-ad-hidden';
function isInsideCommentArea(element) {
if (!element) return false;
let node = element;
while (node && node !== document.body) {
if (node.nodeType === Node.ELEMENT_NODE && node.matches && node.matches(COMMENT_ROOT_SELECTOR)) {
return true;
}
node = node.parentElement;
}
return false;
}
// 验证是否为活动横幅
function isActivityBanner(el) {
return el.querySelector('.hinter-msg') && el.querySelector('.inside-bg');
}
// 通用隐藏逻辑
function checkAndHide(selector, configKey) {
const cfg = getConfig();
if (!cfg[configKey]) return;
document.querySelectorAll(selector).forEach(el => {
if (!isInsideCommentArea(el) && el.getAttribute(HIDE_MARKER) !== 'true') {
el.style.display = 'none';
el.setAttribute(HIDE_MARKER, 'true');
}
});
}
// ================= 强化:推荐流广告视频识别 =================
function isAdVideoCard(card) {
const adLink = card.querySelector('a[href*="cm.bilibili.com"]');
if (adLink) return true;
if (card.dataset && card.dataset.isAd !== undefined) return true;
if (card.classList.contains('is-ad')) return true;
const statsContainer = card.querySelector('.bili-video-card__stats') ||
card.querySelector('.bili-video-card__image .bili-video-card__mask') ||
card.querySelector('.feed-card-statistics');
if (statsContainer) {
const spans = statsContainer.querySelectorAll('span');
for (let span of spans) {
if (/广告|推广|AD|赞助/i.test(span.textContent.trim())) {
return true;
}
}
}
const imageWrap = card.querySelector('.bili-video-card__image') || card.querySelector('.feed-card-image');
if (imageWrap) {
const cornerTags = imageWrap.querySelectorAll('span[class*="ad"], span[class*="sponsor"], span[class*="promote"]');
for (let tag of cornerTags) {
if (/广告|推广|AD/i.test(tag.textContent.trim())) {
return true;
}
}
}
return false;
}
function hideVideoAdsInRecommended() {
if (!getConfig().feedAdVideo) return;
const containers = document.querySelectorAll(FEED_CONTAINER_SELECTOR);
containers.forEach(container => {
if (isInsideCommentArea(container)) return;
const cards = container.querySelectorAll('.bili-video-card, .feed-card, .video-card');
cards.forEach(card => {
if (!isInsideCommentArea(card) && isAdVideoCard(card)) {
if (card.getAttribute(HIDE_MARKER) === 'true') return;
card.style.display = 'none';
card.setAttribute(HIDE_MARKER, 'true');
}
});
});
}
// 统一清理入口
function fullClean() {
checkAndHide(BOTTOM_BANNER_AD_SELECTOR, 'bottomBanner');
checkAndHide(SIDE_AD_SELECTOR, 'sideAd');
checkAndHide(RIGHT_BOTTOM_AD_SELECTOR, 'rightBottomAd');
checkAndHide(SMALL_AD_CARD_SELECTOR, 'smallAdCard');
checkAndHide(VIDEO_TAG_SELECTOR, 'videoTag');
checkAndHide(HOME_CAROUSEL_AD_SELECTOR, 'homeCarouselAd');
checkAndHide(HUASHENG_BANNER_SELECTOR, 'huashengBanner');
checkAndHide(BTN_AD_SELECTOR, 'btnAd');
checkAndHide(LIVE_BANNER_AD_SELECTOR, 'liveBannerAd');
// 活动横幅需特征双重验证
if (getConfig().activityBanner) {
document.querySelectorAll(ACTIVITY_BANNER_SELECTOR).forEach(wrp => {
if (isActivityBanner(wrp) && !isInsideCommentArea(wrp) && wrp.getAttribute(HIDE_MARKER) !== 'true') {
wrp.style.display = 'none';
wrp.setAttribute(HIDE_MARKER, 'true');
}
});
}
hideVideoAdsInRecommended();
// --- 清理导航栏元素 ---
checkAndHide(NAV_ANIME_SELECTOR, 'hideAnime');
checkAndHide(NAV_LIVE_SELECTOR, 'hideLive');
checkAndHide(NAV_GAME_SELECTOR, 'hideGameCenter');
checkAndHide(NAV_MALL_SELECTOR, 'hideMall');
checkAndHide(NAV_MANGA_SELECTOR, 'hideManga');
checkAndHide(NAV_MATCH_SELECTOR, 'hideMatch');
checkAndHide(NAV_DOWNLOAD_SELECTOR, 'hideDownload');
checkAndHide(NAV_VIP_SELECTOR, 'hideVip');
}
// 处理动态新增节点
function processNewNode(node) {
if (node.nodeType !== Node.ELEMENT_NODE) return;
if (isInsideCommentArea(node)) return;
checkAndHide(BOTTOM_BANNER_AD_SELECTOR, 'bottomBanner');
checkAndHide(SIDE_AD_SELECTOR, 'sideAd');
checkAndHide(RIGHT_BOTTOM_AD_SELECTOR, 'rightBottomAd');
checkAndHide(SMALL_AD_CARD_SELECTOR, 'smallAdCard');
checkAndHide(VIDEO_TAG_SELECTOR, 'videoTag');
checkAndHide(HOME_CAROUSEL_AD_SELECTOR, 'homeCarouselAd');
checkAndHide(HUASHENG_BANNER_SELECTOR, 'huashengBanner');
checkAndHide(BTN_AD_SELECTOR, 'btnAd');
checkAndHide(LIVE_BANNER_AD_SELECTOR, 'liveBannerAd');
if (getConfig().activityBanner) {
const checkActivity = (el) => {
if (isActivityBanner(el) && !isInsideCommentArea(el) && el.getAttribute(HIDE_MARKER) !== 'true') {
el.style.display = 'none';
el.setAttribute(HIDE_MARKER, 'true');
}
};
checkActivity(node);
if (node.querySelectorAll) {
node.querySelectorAll(ACTIVITY_BANNER_SELECTOR).forEach(wrp => checkActivity(wrp));
}
}
// 广告视频卡片检查优化
const cfg = getConfig();
if (cfg.feedAdVideo) {
let needScanVideo = false;
if (node.matches && (node.matches('.bili-video-card') || node.matches('.feed-card') || node.matches(FEED_CONTAINER_SELECTOR))) {
needScanVideo = true;
} else if (node.querySelector && (node.querySelector('.bili-video-card') || node.querySelector('.feed-card') || node.querySelector(FEED_CONTAINER_SELECTOR))) {
needScanVideo = true;
}
if (needScanVideo) {
setTimeout(() => hideVideoAdsInRecommended(), 80);
}
}
// --- 动态节点导航栏检查 ---
checkAndHide(NAV_ANIME_SELECTOR, 'hideAnime');
checkAndHide(NAV_LIVE_SELECTOR, 'hideLive');
checkAndHide(NAV_GAME_SELECTOR, 'hideGameCenter');
checkAndHide(NAV_MALL_SELECTOR, 'hideMall');
checkAndHide(NAV_MANGA_SELECTOR, 'hideManga');
checkAndHide(NAV_MATCH_SELECTOR, 'hideMatch');
checkAndHide(NAV_DOWNLOAD_SELECTOR, 'hideDownload');
checkAndHide(NAV_VIP_SELECTOR, 'hideVip');
}
// MutationObserver 监听页面变化
const observer = new MutationObserver(mutations => {
let hasAddedNodes = false;
for (const mutation of mutations) {
if (mutation.type === 'childList' && mutation.addedNodes.length) {
mutation.addedNodes.forEach(node => processNewNode(node));
hasAddedNodes = true;
}
}
if (hasAddedNodes) {
setTimeout(() => {
fullClean();
}, 150);
}
});
if (document.body) {
observer.observe(document.body, { childList: true, subtree: true });
} else {
window.addEventListener('DOMContentLoaded', () => {
observer.observe(document.body, { childList: true, subtree: true });
});
}
// SPA 路由变化辅助
let lastUrl = location.href;
const urlObserver = new MutationObserver(() => {
if (location.href !== lastUrl) {
lastUrl = location.href;
setTimeout(fullClean, 300);
}
});
urlObserver.observe(document, { subtree: true, childList: true });
// 启动清理
fullClean();
})();