Greasy Fork

Greasy Fork is available in English.

隐藏b站视频详情页右侧的"活动推广"和"大家围观的直播"以及首页广告

Hide specified Bilibili elements using MutationObserver

当前为 2024-12-21 提交的版本,查看 最新版本

// ==UserScript==
// @name         隐藏b站视频详情页右侧的"活动推广"和"大家围观的直播"以及首页广告
// @name:en      Hide promotions on Bilibili's video details page and homepage
// @namespace    http://tampermonkey.net/
// @version      0.1.24
// @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_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==




// Function to create and append the Cover link
function appendCoverLink() {
    // Select the parent container where the new element will be appended
    const parentContainer = document.querySelector('.video-info-detail-list.video-info-detail-content:not(.modified)');

    if (!parentContainer) {
        console.warn('Parent container not found. Ensure the selector is correct.');
        return;
    }

    // Extract the cover image URL from the document head
    const imageMetaTag = document.head.querySelector('[itemprop="image"]');
    if (!imageMetaTag) {
        console.warn('Image meta tag with [itemprop="image"] not found.');
        return;
    }

    // Replace 'http' with 'https' if necessary
    const coverImgUrl = 'https://' + imageMetaTag.getAttribute('content').replace('http', 'https').split('@')[0];

    // Create the new container div with appropriate classes
    console.log("coverImgUrl=", coverImgUrl);

    // Create the new container div with appropriate classes
    const coverItem = document.createElement('div');
    coverItem.classList.add('cover-item', 'item'); // Add additional classes if needed

    // Create the SVG icon (optional)
    const coverIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    coverIcon.setAttribute('class', 'cover-icon');
    coverIcon.setAttribute('style', 'width:20px;height:20px;');
    coverIcon.setAttribute('viewBox', '0 0 20 20');
    coverIcon.setAttribute('width', '20');
    coverIcon.setAttribute('height', '20');

    // Example SVG path (you can customize this)
    const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    path.setAttribute('d', 'M10 0 L20 20 L0 20 Z'); // Simple triangle as placeholder
    path.setAttribute('fill', 'currentColor');
    coverIcon.appendChild(path);

    // Create the link element
    const coverLink = document.createElement('a');
    coverLink.setAttribute('href', coverImgUrl);
    coverLink.setAttribute('target', '_blank'); // Opens link in a new tab
    coverLink.setAttribute('rel', 'noopener noreferrer'); // Security best practice
    coverLink.classList.add('cover-link');

    // **Add the hover text using the title attribute**
    coverLink.setAttribute('title', 'You may need F5 refresh to get consistent cover');

    // Create the text node
    const linkText = document.createElement('span');
    linkText.classList.add('cover-text');
    linkText.textContent = 'Cover';

    // Assemble the link
    coverLink.appendChild(coverIcon); // Optional: Append icon
    coverLink.appendChild(linkText);

    // Append the link to the new item container
    coverItem.appendChild(coverLink);

    // Append the new item to the parent container
    parentContainer.classList.add('modified');
    parentContainer.appendChild(coverItem);

    console.log('Cover link appended successfully.');
}



(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
    }, 30*1000);


     // Retrieve the current setting, default to false
    let isEnableAppendCoverLink = GM_getValue('isEnableAppendCoverLink', false);

    // Function to toggle the setting
    function toggleAppendCoverLink() {
        isEnableAppendCoverLink = !isEnableAppendCoverLink;
        GM_setValue('isEnableAppendCoverLink', isEnableAppendCoverLink);
        // Provide feedback to the user
        alert(`Append Cover Link is now ${isEnableAppendCoverLink ? 'Enabled' : 'Disabled'}. Refresh to work.`);
    }

    // Register a single menu command
    GM_registerMenuCommand(
        isEnableAppendCoverLink? 'Status: ✅Enable Append Cover Link': 'Status: ❌Disbale Append Cover Link',
        toggleAppendCoverLink
    );

    if (isEnableAppendCoverLink){
        setInterval(()=>appendCoverLink(), 2*1000);
    }

})();