// ==UserScript==
// @name [Bilibili首页去广告]去除B站首页广告,更改样式
// @version 1.4.0
// @description 去除B站首页的轮播广告,小广告,直播与番剧推荐,并修改若干样式
// @author You
// @match https://www.bilibili.com/
// @match https://www.bilibili.com/?*
// @icon https://i0.hdslb.com/bfs/static/jinkela/long/images/favicon.ico
// @run-at document-start
// @grant none
// @namespace http://tampermonkey.net/
// ==/UserScript==
const OPEN_DEBUG = true;
// 新增一个用于格式化DOM信息的辅助函数
function logDOMInfo(node, source, selector = '') {
if (!OPEN_DEBUG) return;
const classes = node.className && typeof node.className === 'string' ? node.className : '';
const id = node.id ? node.id : '';
const tag = node.tagName ? node.tagName.toLowerCase() : 'unknown';
const text = node.textContent ? node.textContent.substring(0, 50).replace(/\s+/g, ' ').trim() : '';
console.log(
`%c[广告拦截器]%c 拦截元素: %c${tag}%c${id ? '#'+id : ''}%c${classes ? '.'+classes.replace(/\s+/g, '.') : ''}`,
'color: #ff6464; font-weight: bold;',
'color: #333;',
'color: #0066cc; font-weight: bold;',
'color: #cc6600;',
'color: #339933;',
`\n来源: ${source}${selector ? '\n选择器: '+selector : ''}\n内容: ${text}${text.length >= 50 ? '...' : ''}`
);
// 如果浏览器支持,添加DOM节点的引用便于调试
if (typeof console.dir === 'function') {
console.dir(node);
}
}
// 需要移除的广告元素选择器
const selectors = [
'.recommended-swipe',
'.bili-header__channel',
'.feed-card > :not(.enable-no-interest)',
'.bili-video-card.is-rcmd:not(.enable-no-interest)',
'.floor-single-card',
'.bili-live-card',
'.header-channel',
'.fixed-card',
'.palette-button-adcard',
'#slide_ad'
];
// CSS规则,包括广告隐藏和样式修改
const cssRule = `
/* 隐藏广告元素 - 立即生效防止闪现 */
.recommended-swipe,
.bili-header__channel,
.feed-card > :not(.enable-no-interest),
.bili-video-card.is-rcmd:not(.enable-no-interest),
.floor-single-card,
.bili-live-card,
.header-channel,
.fixed-card,
.palette-button-adcard,
#slide_ad {
display: none !important;
visibility: hidden !important;
opacity: 0 !important;
pointer-events: none !important;
height: 0 !important;
width: 0 !important;
max-height: 0 !important;
max-width: 0 !important;
overflow: hidden !important;
position: absolute !important;
z-index: -9999 !important;
}
/* 其他样式调整 */
.bili-header__banner {
margin-bottom: 40px !important;
}
.bili-header__banner::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100px;
background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
z-index: 1;
}
@media (max-width: 1139.9px) {
.recommended-container_floor-aside .container>*:nth-of-type(5) {
margin-top: 24px !important;
}
}
@media (min-width: 1140px) and (max-width: 1299.9px) {
.recommended-container_floor-aside .container>*:nth-of-type(5) {
margin-top: 24px !important;
}
}
@media (min-width: 1140px) and (max-width: 1299.9px) {
.recommended-container_floor-aside .container>*:nth-of-type(n + 6) {
margin-top: 24px !important;
}
}
@media (min-width: 1300px) and (max-width: 1399.9px) {
.recommended-container_floor-aside .container>*:nth-of-type(5) {
margin-top: 24px !important;
}
}
@media (min-width: 1300px) and (max-width: 1399.9px) {
.recommended-container_floor-aside .container>*:nth-of-type(n + 6) {
margin-top: 24px !important;
}
}
@media (min-width: 1400px) and (max-width: 1559.9px) {
.recommended-container_floor-aside .container>*:nth-of-type(6) {
margin-top: 24px !important;
}
}
@media (min-width: 1400px) and (max-width: 1559.9px) {
.recommended-container_floor-aside .container>*:nth-of-type(7) {
margin-top: 24px !important;
}
}
@media (min-width: 1560px) and (max-width: 2059.9px) {
.recommended-container_floor-aside .container>*:nth-of-type(6) {
margin-top: 24px !important;
}
}
@media (min-width: 1560px) and (max-width: 2059.9px) {
.recommended-container_floor-aside .container>*:nth-of-type(7) {
margin-top: 24px !important;
}
}
@media (min-width: 2060px) {
.recommended-container_floor-aside .container>*:nth-of-type(6) {
margin-top: 24px !important;
}
}
@media (min-width: 2060px) {
.recommended-container_floor-aside .container>*:nth-of-type(7) {
margin-top: 24px !important;
}
}
.recommended-container_floor-aside .container>*:nth-of-type(6) {
margin-top: 24px;
}
.recommended-container_floor-aside .container>*:nth-of-type(7) {
margin-top: 24px;
}
.recommended-container_floor-aside .container>*:nth-of-type(n + 8) {
margin-top: 24px !important;
}
.recommended-container_floor-aside .container.is-version8>*:nth-of-type(n + 13) {
margin-top: 24px !important;
}
.recommended-container_floor-aside .container .floor-single-card:first-of-type {
margin-top: 24px !important;
}
.recommended-container_floor-aside .container .load-more-anchor .floor-single-card {
margin-top: 24px !important;
}
`;
// 修改初始化清理函数,增加来源信息
function initialCleanup() {
console.log('%c[广告拦截器]%c 执行初始化清理', 'color: #ff6464; font-weight: bold;', 'color: #333;');
for (const selector of selectors) {
const elements = document.querySelectorAll(selector);
elements.forEach(function (element) {
// 记录初始清理时移除的DOM元素
logDOMInfo(element, '初始化清理', selector);
element.remove();
});
if (elements.length > 0) {
console.log(`[广告拦截器] 初始化清理: 通过选择器 "${selector}" 共移除 ${elements.length} 个元素`);
}
}
}
// 尝试拦截DOM插入
function setupDOMInterceptor() {
// 保存原始的appendChild和insertBefore方法
const originalAppendChild = Element.prototype.appendChild;
const originalInsertBefore = Element.prototype.insertBefore;
// 重写appendChild方法
Element.prototype.appendChild = function(node) {
// 检查新添加的节点是否匹配广告选择器
const result = originalAppendChild.call(this, node);
// 如果是元素节点,检查是否需要移除
if (node.nodeType === 1) {
checkAndRemoveAd(node);
}
return result;
};
// 重写insertBefore方法
Element.prototype.insertBefore = function(node, referenceNode) {
// 执行原始方法
const result = originalInsertBefore.call(this, node, referenceNode);
// 如果是元素节点,检查是否需要移除
if (node.nodeType === 1) {
checkAndRemoveAd(node);
}
return result;
};
}
// 修改checkAndRemoveAd函数添加日志
function checkAndRemoveAd(node) {
// 避免处理非元素节点
if (!node || node.nodeType !== 1) {
return;
}
// 可选:白名单检查,防止误删重要元素
const whitelistClasses = ['video-content', 'bili-video-card__wrap', 'bili-img'];
for (const cls of whitelistClasses) {
if (node.classList && node.classList.contains(cls)) {
return; // 白名单元素不处理
}
}
// 检查节点本身是否匹配选择器
for (const selector of selectors) {
try {
if (node.matches && node.matches(selector)) {
// 记录被拦截的DOM元素
logDOMInfo(node, 'DOM拦截器', selector);
node.remove();
return;
}
} catch (e) {
console.error('[Ad Blocker] 选择器匹配错误:', e, selector);
}
}
// 检查子节点是否匹配选择器,添加安全检查
if (node.querySelectorAll) {
try {
for (const selector of selectors) {
const adElements = node.querySelectorAll(selector);
adElements.forEach(element => {
// 避免移除包含有价值内容的元素
const hasImages = element.querySelectorAll('img:not(.ad-img)').length > 0;
const hasVideos = element.querySelectorAll('video').length > 0;
if ((hasImages || hasVideos) && !element.classList.contains('ad-confirmed')) {
// 记录被隐藏的DOM元素
logDOMInfo(element, 'DOM拦截器(仅隐藏)', selector);
element.style.cssText = 'visibility: hidden !important; height: 0 !important; overflow: hidden !important;';
} else {
// 记录被移除的DOM元素
logDOMInfo(element, 'DOM拦截器(子元素)', selector);
element.remove();
}
});
}
} catch (e) {
console.error('[Ad Blocker] 移除子元素时出错:', e);
}
}
}
// 使用MutationObserver作为后备防线
function setupMutationObserver() {
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.addedNodes.length > 0) {
for (const selector of selectors) {
removeDOMs(selector);
}
break;
}
}
});
// 配置观察器选项
const config = {
childList: true,
subtree: true,
attributes: false,
characterData: false
};
// 开始观察整个document
observer.observe(document.documentElement, config);
return observer;
}
// 修改removeDOMs函数添加日志
function removeDOMs(selector) {
const elements = document.querySelectorAll(selector);
elements.forEach(function (element) {
// 记录通过选择器查询移除的DOM元素
logDOMInfo(element, 'MutationObserver监测', selector);
element.remove();
});
if (elements.length > 0) {
console.log(`[广告拦截器] 通过选择器 "${selector}" 共移除 ${elements.length} 个元素`);
}
}
// 添加CSS规则
function runCSS(cssRule) {
const style = document.createElement('style');
style.appendChild(document.createTextNode(cssRule));
// 确保样式表尽早应用
if (document.head) {
document.head.appendChild(style);
} else {
// 如果head还不存在,等待DOM准备好
const observer = new MutationObserver(() => {
if (document.head) {
document.head.appendChild(style);
observer.disconnect();
}
});
observer.observe(document.documentElement, { childList: true, subtree: true });
}
}
// 主函数
(function() {
// 立即应用CSS规则 - 这是第一道防线
runCSS(cssRule);
// 设置DOM原型方法拦截 - 这是第二道防线
setupDOMInterceptor();
// DOM加载完成后执行初始清理
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initialCleanup);
} else {
initialCleanup();
}
// 设置MutationObserver作为后备防线
const observer = setupMutationObserver();
// 页面卸载时清理
window.addEventListener('unload', () => {
if (observer) {
observer.disconnect();
}
});
})();