Greasy Fork is available in English.

ddys_ad.js

广告隐藏

// ==UserScript==
// @name         ddys_ad.js
// @namespace    http://tampermonkey.net/
// @version      0.11
// @description  广告隐藏
// @author       wuuconix
// @match        *://*/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=ddys.tv
// @grant        none
// @license      MIT
// ==/UserScript==

/* 存储在本地的云端规则,用于提高过滤速度 */
let adListCloud = localStorage.getItem("ddys_ad_cloud")
if (adListCloud) {
    adListCloud = JSON.parse(adListCloud)
    filter(adListCloud)
}

/* 云端的过滤规则,存储于 https://gist.github.com/wuuconix/82b6b724694d773f455eac38202fcca8 */
fetch(`https://mirror.ghproxy.com/https://gist.githubusercontent.com/wuuconix/82b6b724694d773f455eac38202fcca8/raw/ad.json?ts=${Date.now()}`).then(res => res.json()).then(res => {
    filter(res[location.hostname])
    localStorage.setItem("ddys_ad_cloud", JSON.stringify(res[location.hostname] ?? []))
})

/* 本地的过滤规则,存储于 localStorage 由用户通过ctrl+shift+鼠标左键 增加 */
let adList = localStorage.getItem("ddys_ad")
if (adList) {
    adList = JSON.parse(adList)
    filter(adList)
}

function filter(adList) {
    if (!Array.isArray(adList) || adList.length == 0) {
        return
    }

    const style = document.createElement("style")
    style.innerHTML = `${adList.join(",")} {
        width: 0px !important;
        height: 0px !important;
        opacity: 0 !important;
        pointer-events: none !important;
    }`

    document.head.appendChild(style)
}

/* 支持 ctrl+shift+鼠标左键 选中某元素加入本地过滤规则中 */
document.addEventListener("click", (e) => {
    if (!e.ctrlKey || !e.shiftKey) {
        return
    }

    e.preventDefault()
    e.stopPropagation()

    const target = e.target
    target.style.width="0px"
    target.style.height="0px"

    const jsPath = getDomPath(target)
    let adList = localStorage.getItem("ddys_ad")

    if (adList) {
        adList = JSON.parse(adList)
        adList.push(jsPath)
        localStorage.setItem("ddys_ad", JSON.stringify(adList))
    } else {
        localStorage.setItem("ddys_ad", JSON.stringify([jsPath]))
    }
})

/* 获取选中的某个元素的css路径 https://gist.github.com/karlgroves/7544592 */
function getDomPath(el, noVerify) {
    // store the original element if verify is enabled. If it isn't, then don't even bother 
    // taking up any memory for it.

    const origElem = el;

    if ( ! el ) {
        console.error('No element provided');
        return;
    }

    const stack = [];
    let levelCount = 0;
    let nearestElemWithId = null;

    let sibParent;
    let sibSiblings;

    do {
        levelCount++;

        let sibCount = 0;
        let sibIndex = 0;
        sibParent = el?.parentNode;
        sibSiblings = sibParent?.children;

        if ( sibSiblings ){
            sibSiblings = Array.from(sibSiblings).filter( sibElem => el.nodeName == sibElem.nodeName );
        }

        // Iterate over the childNodes of the elements parentNode to get the
        // index to use
        if ( sibSiblings ){
            for ( let i = 0; i < sibSiblings.length; i++ ) {
            let sib = sibSiblings[i];

            //if ( sib.nodeName != el.nodeName )  continue;
            
                sibCount++;

                if ( sib === el ) {
                // If this is the correct element, then save the sibIndex
                // and stop looping
                sibIndex = sibCount;
                break;
                }
            }
        }

        if ( el && el.hasAttribute('id') && el.id != '' ) {
        nearestElemWithId = el.id;

        // Turns out, if you have an id that starts with a numerical value, then you can't
        // use it in querySelector[All] unless you either escape it or add [id=] to it.
        if ( /^[0-9]/.test(el.id) ){
            stack.unshift(`[id="${el.id}"]`);
        }
        else {
            stack.unshift(`#${el.id}`);
        }
        } 
        else if ( sibCount > 1 ) {
        stack.unshift(el.nodeName.toLowerCase() + ':nth-of-type(' + parseInt(sibIndex) + ')');
        } 
        else {
        stack.unshift(el.nodeName.toLowerCase());
        }

        el = sibParent;
    }
    while( sibParent?.nodeType === Node.ELEMENT_NODE && nearestElemWithId === null );


    if ( stack[0] === 'html' )
        stack.shift();

    const result = stack.join(' > ');

    if ( noVerify ) return result;

    let selectionFromResult;

    try {
        selectionFromResult = document.querySelector(result);
    }
    catch(err){
        console.error(`Encountered an exception when trying to verify querySelector(${result})\n\tError:`, err);
    }

    // If there's no matches when using querySelector() with the result string, then
    // return false;
    if ( ! selectionFromResult ){
        console.error(`Failed to find any document using querySelector(${result})`);
        return false;
    }

    // If there is a result, but its not the same element, then return false;
    else if ( ! origElem.isSameNode(selectionFromResult) ){
        console.error(`Element returned from querySelector(${result}) is not the same as the element provided`);
    }

    // If we got here, then the matched element is the same element, then it's been verified.
    return result;
}