// ==UserScript== // @name 隐藏b站视频详情页右侧的"活动推广"和"大家围观的直播"以及首页广告 // @name:en Hide promotions on Bilibili's video details page and homepage // @namespace http://tampermonkey.net/ // @version 0.1.25 // @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 GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_setValue // @grant GM_getValue // @grant GM_notification // @grant GM_info // @grant window.onurlchange // @license MIT // @sandbox JavaScript // @downloadURL none // ==/UserScript== // ↓↓↓↓↓↓↓↓↓模板,建议直接复制 // // 自定义 urlchange 事件(用来监听 URL 变化) function addUrlChangeEvent() { history.pushState = ( f => function pushState(){ var ret = f.apply(this, arguments); window.dispatchEvent(new Event('pushstate')); window.dispatchEvent(new Event('urlchange')); return ret; })(history.pushState); history.replaceState = ( f => function replaceState(){ var ret = f.apply(this, arguments); window.dispatchEvent(new Event('replacestate')); window.dispatchEvent(new Event('urlchange')); return ret; })(history.replaceState); window.addEventListener('popstate',()=>{ window.dispatchEvent(new Event('urlchange')) }); } var menu_ALL = [ ['menu_isEnableAppendCoverLink', '默认追加视频封面链接', '默认追加视频封面链接', true] ], menu_ID = []; for (let i=0;i= menu_ALL.length){ // 如果菜单ID数组长度大于等于菜单数组长度,说明不是首次添加菜单,需要卸载所有脚本菜单 for (let i=0;i { BVid = 'default'; const match = location.pathname.match(/BV[^/]*/); if (match) { BVid = match[0]; } else { // console.error("No match found"); } // Mark this container as modified parentContainer.classList.add(BVid + 'modified'); // Replace 'http' with 'https' if necessary const coverImgUrl = 'https://' + imageMetaTag.getAttribute('content').replace('http', 'https').split('@')[0]; console.log("coverImgUrl=", coverImgUrl); coverLink.setAttribute('href', coverImgUrl); // Ensure the link is only appended once const existingCoverLink = parentContainer.querySelector('.cover-link'); if (existingCoverLink) { existingCoverLink.remove(); } parentContainer.append(coverLink); console.log('Cover link appended successfully.'); }, 2*1000); } (function () { 'use strict'; registerMenuCommand(); 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 }, 30*1000); // window.addEventListener('urlchange', function(){ // // setTimeout(()=>{appendCoverLink();}, 1*1000); // }) // Retrieve the current setting, default to false let isEnableAppendCoverLink = GM_getValue('menu_isEnableAppendCoverLink', false); if (isEnableAppendCoverLink){ const checkIntervalAppendCoverLink = setInterval(()=>appendCoverLink(), 300); // Cleanup after 30 seconds setTimeout(() => { clearInterval(checkIntervalAppendCoverLink); observer.disconnect(); // Optionally disconnect the observer after cleanup }, 30*1000); } })();