// ==UserScript==
// @name 隐藏b站视频详情页右侧的"活动推广"和"大家围观的直播"以及首页广告
// @name:en Hide promotions on Bilibili's video details page and homepage
// @namespace http://tampermonkey.net/
// @version 0.2.0
// @description Hide specified Bilibili elements using MutationObserver
// @description:en Hide specified Bilibili elements using MutationObserver
// @author aspen138
// @match *://www.bilibili.com/video/*
// @match *://www.bilibili.com/*
// @match *://www.bilibili.com
// @match *://search.bilibili.com/*
// @icon https://www.bilibili.com/favicon.ico
// @grant none
// @license MIT
// ==/UserScript==
(function () {
'use strict';
if (window.location.hostname.includes('bilibili.com')) {
const styleElement1 = document.createElement('style');
styleElement1.textContent = `.login-tip, .vip-login, .vip-login-tip, .login-panel-popover { display: none !important; }`;
document.head.appendChild(styleElement1);
}
if (document.cookie.includes('DedeUserID')) {
//console.log("has loged in.");
// add CSS to hide some elements
const styleElement = document.createElement('style');
styleElement.textContent = ` .desktop-download-tip { display: none !important; }`; //隐藏右下角的下载客户端的推广弹窗
document.head.appendChild(styleElement);
}
else {
//console.log("not loged in.");
// add CSS to hide some elements
const originAppendChild = Node.prototype.appendChild;
Node.prototype.appendChild = function (childElement) {
if (childElement.tagName === 'SCRIPT' && childElement.src.includes("login")) {
console.log("src=", src);
return null;
}
else {
return originAppendChild.call(this, childElement);
}
}
}
// Select elements with href containing 'cm.bilibili.com/cm/api'
var elements = document.querySelectorAll('a[href*="cm.bilibili.com/cm/api"]');
elements.forEach(function(element) {
// Find the closest parent with class 'bili-video-card'
var parentCard = element.closest('.bili-video-card');
if (parentCard) {
// Store original height to maintain layout
var originalHeight = parentCard.children[0].children[0].offsetHeight;
// Create replacement message div
var messageDiv = document.createElement('div');
messageDiv.style.cssText = `
background-color: #f0f0f0;
color: #666;
padding: 15px;
text-align: center;
font-size: 14px;
height: ${originalHeight}px;
display: flex;
align-items: center;
justify-content: center;
`;
messageDiv.textContent = "The AD content is hidden";
// Replace content while keeping the card
parentCard.innerHTML = '';
parentCard.appendChild(messageDiv);
}
});
// Enhanced function to thoroughly hide elements
function hideElement(element) {
if (!element) return;
// Apply more aggressive hiding styles
const hideStyles = {
'display': 'none !important',
'visibility': 'hidden !important',
'opacity': '0 !important',
'background': 'white !important',
'color': 'white !important',
'pointer-events': 'none !important',
'height': '0 !important',
'width': '0 !important',
'overflow': 'hidden !important',
'position': 'absolute !important',
'z-index': '-9999 !important',
'clip': 'rect(0, 0, 0, 0) !important'
};
// Apply styles using both direct style and cssText for maximum effectiveness
Object.entries(hideStyles).forEach(([property, value]) => {
element.style.setProperty(property, value.replace(' !important', ''), 'important');
});
// Hide all child elements recursively
Array.from(element.children).forEach(child => {
hideElement(child);
});
// Remove any inline event listeners
element.onclick = null;
element.onmouseover = null;
element.onmouseenter = null;
element.onmouseleave = null;
}
// Function to handle all target elements
function hideAllTargetElements() {
const targetElements = [
'#slide_ad',
'#right-bottom-banner',
'.pop-live-small-mode.part-1',
'.ad-floor-cover.b-img',
'#bannerAd',
'.vcd',
'a[data-loc-id="4331"]',
'#activity_vote',
'.ad-report.video-card-ad-small',
'.ad-report.ad-floor-exp',
'.slide-ad-exp',
'.activity-m-v1.act-now',
'.video-page-special-card-small',
'.btn-ad',
'div[data-v-2ce37bb8].btn-ad',
'.palette-button-adcard.is-bottom', // New element
'.palette-button-adcard' // More specific selector for the new element
//,'div[data-v-7b35db32].vip-login-tip'
];
targetElements.forEach(selector => {
const elements = document.querySelectorAll(selector);
elements.forEach(hideElement);
});
}
// Create a more specific MutationObserver
const observer = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
// Check for added nodes
if (mutation.addedNodes.length) {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) { // Element node
// Check if the added node is a target element
if (node.id === 'slide_ad' ||
node.classList.contains('slide-ad-exp') ||
node.classList.contains('ad-report') ||
node.classList.contains('activity-m-v1') ||
node.classList.contains('video-page-special-card-small') ||
node.classList.contains('btn-ad') ||
node.classList.contains('palette-button-adcard')) { // Added new class check
hideElement(node);
}
// Also check children of added nodes
const targetElements = node.querySelectorAll('#slide_ad, .slide-ad-exp, .ad-report, .activity-m-v1, .video-page-special-card-small, .btn-ad, .palette-button-adcard');
targetElements.forEach(hideElement);
}
});
}
// Check for attribute changes
if (mutation.type === 'attributes') {
const element = mutation.target;
if (element.id === 'slide_ad' ||
element.classList.contains('slide-ad-exp') ||
element.classList.contains('ad-report') ||
element.classList.contains('activity-m-v1') ||
element.classList.contains('video-page-special-card-small') ||
element.classList.contains('btn-ad') ||
element.classList.contains('palette-button-adcard')
// ||element.classList.contains('vip-login-tip')
) { // Added new class check
hideElement(element);
}
}
});
});
// Configure the observer to watch for everything
const observerConfig = {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['style', 'class']
};
// Initial hiding
hideAllTargetElements();
// Start observing
observer.observe(document.body, observerConfig);
// Set up periodic checks just in case
const checkInterval = setInterval(hideAllTargetElements, 1000);
// Cleanup after 30 seconds
setTimeout(() => {
clearInterval(checkInterval);
observer.disconnect(); // Optionally disconnect the observer after cleanup
}, 30000);
})();