dgj's bilibili ads guard

remove all ads from bilibili.com

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         dgj's bilibili ads guard
// @namespace    http://tampermonkey.net/
// @version      2024-06-18
// @description  remove all ads from bilibili.com
// @author       noobdawn
// @match        https://www.bilibili.com/
// @icon         https://www.google.com/s2/favicons?sz=64&domain=bilibili.com
// @grant        GM_xmlhttpRequest
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    var blockData = localStorage.getItem("dgjBlockData");
    //if (blockData === null)
    {
        blockData = {
            "up_name": "",
            // up主的名字

            "up_uid": "",
            // up主的UID

            "video_keyword": 
                // sb游戏
                "剑网3,原神,崩坏,星穹铁道,星铁,绝区,未定事件簿,米哈游,仙家军,明日方舟,鹰角,海猫,鸣潮,战双帕弥什,库洛,少前,少女前线,面包房少女,散爆,羽中,无期迷途,叠纸,奇迹暖暖,无限暖暖,恋与深空,恋与制作人,百面千相,姚润昊,深空之眼,来古弥新,物华弥新,新月同行,归龙潮,破晓序列,卡拉彼丘,碧蓝档案,蔚蓝档案,雀魂,以闪亮之名,光与夜之恋,尘白禁区",
            // 视频的关键词

            "video_label": 
                // sb游戏 
                "鸣潮,鸣潮公测二创,鸣潮公测创作者激励计划,新三国,火影忍者手游,地下城与勇士,dnf,dnfpk,300英雄,MOBA,三百英雄,剑网3,星穹铁道2.2波提欧,暴雪,原神,崩坏,崩坏学园2,崩坏3,崩坏星穹铁道,星穹铁道,绝区零,绝区0,未定事件簿,米哈游,仙家军,明日方舟,鹰角,鹰角网络,海猫,鸣潮,战双帕弥什,库洛,少前,少前2,少女前线,少女前线2,面包房少女,散爆,羽中,叠纸游戏,奇迹暖暖,无限暖暖,恋与深空,恋与制作人,百面千相,姚润昊,深空之眼,来古弥新,物华弥新,新月同行,归龙潮,望月,破晓序列,卡拉彼丘,碧蓝档案,蔚蓝档案,雀魂,以闪亮之名,光与夜之恋,尘白禁区" +
                // 没营养的东西
                "助眠,生活,情感,日常,校园,娱乐,记录,舞蹈,Vtuber,hololive,免单挑战,探店,美食,时尚,穿搭"
            // 视频的标签
            
        };
        blockData.up_name = blockData.up_name.split(",");
        blockData.video_keyword = blockData.video_keyword.split(",");
        blockData.video_label = blockData.video_label.split(",");
        blockData.up_uid = blockData.up_uid.split(",");
        localStorage.setItem("dgjBlockData", JSON.stringify(blockData));
    }

    const DEBUG = true;

    function removeAds(node, msg) {
        if (DEBUG)
        {
            // 删除所有子元素
            while (node.firstChild) {
                node.removeChild(node.firstChild);
            }
            // 添加一个文本节点
            node.appendChild(document.createTextNode(msg));
        }
        else
            node.remove();
    }

    // 从URL中获取UID
    function GetUidFromUrl(url) {
        var index = url.indexOf("space.bilibili.com/");
        if (index === -1)
            return -1;
        // 将剩下的所有字符转换为字符串
        var uid = url.substring(index + 19);
        return parseInt(uid);
    }

    // 根据UP主屏蔽视频
    function BlockVideoByUp(node) {
        // 向下查找,找到class为"bili-video-card__info--owner"的a,这就是UP主的链接
        var owner = node.getElementsByClassName("bili-video-card__info--owner");
        if (owner.length > 0) {
            var uid = GetUidFromUrl(owner[0].href);
            if (uid === -1)
                return true;
            // 如果uid在blockData的up_uid数组中,就删除这个视频
            if (blockData.up_uid.indexOf(uid) !== -1)
            {
                removeAds(node, "触发UP主:" + uid);
                return true;
            }
            owner = node.getElementsByClassName("bili-video-card__info--author");
            if (owner.length > 0) {
                var name = owner[0].innerText;
                // 如果name在blockData的up_name数组中,就删除这个视频
                if (blockData.up_name.indexOf(name) !== -1)
                {
                    removeAds(node, "触发UP主:" + name);
                    return true;
                }
            }
            return false;
        }
        return true;
    }

    // 根据视频屏蔽视频
    function BlockVideoByVideo(node) {
        var link = node.getElementsByClassName("bili-video-card__info--tit");
        if (link.length > 0) {
            console.log(link[0].title);
            var title = link[0].title;
            for (var j = 0; j < blockData.video_keyword.length; j++){
                if (title.includes(blockData.video_keyword[j])) {
                    removeAds(node, "触发关键字:" + blockData.video_keyword[j]);
                    return;
                }
            }
        }
        // 向下查找,找到class为"bili-video-card__image--link"的a,这就是视频的链接
        link = node.getElementsByClassName("bili-video-card__image--link");
        if (link.length > 0) {
            var url = link[0].href;
            // 打开视频链接,获取视频的关键词和标签
            GM_xmlhttpRequest({
                method: "GET",
                url: url,
                onload: function(response) {
                    var data = response.responseText;
                    // 找到<meta data-vue-meta="true" itemprop="keywords" name="keywords" content="
                    let start_string = "<meta data-vue-meta=\"true\" itemprop=\"keywords\" name=\"keywords\" content=\"";
                    let end_string = "\"><meta";
                    var index = data.indexOf(start_string);
                    if (index !== -1)
                    {
                        var keywords = data.substring(index + start_string.length, data.indexOf(end_string, index));
                        var keywordArray = keywords.split(",");
                        // 抛弃第一个元素
                        keywordArray.shift();
                        console.log(keywordArray);
                        // 如果labels数组中有一个元素在blockData的video_label数组中,就删除这个视频
                        for (i = 0; i < keywordArray.length; i++)
                        {
                            if (blockData.video_label.indexOf(keywordArray[i]) !== -1)
                            {
                                removeAds(node, "触发标签:" + keywordArray[i]);
                                return;
                            }
                        }
                    }
                }
            });
        }
    }

    // 每次页面元素变化时,都会触发此函数
    var observer = new MutationObserver(function(mutations) {
        // 遍历所有变化
        mutations.forEach(function(mutation) {
            mutation.addedNodes.forEach(function(node) {
                if (node instanceof HTMLDivElement) {
                    // 为菜单新增一个按钮
                    if (node.className === "bili-video-card__info--no-interest-panel")
                    {
                        // 创建一个新的选项,class为"bili-video-card__info--no-interest-panel--item",innerText为"屏蔽此UP主"
                        var item = document.createElement("div");
                        item.className = "bili-video-card__info--no-interest-panel--item";
                        item.innerText = "屏蔽此UP主";
                        // 将新的选项插入到菜单中
                        node.appendChild(item);
                        // 监听点击事件
                        item.addEventListener("click", function() {
                            // todo
                        });
                    }

                    // 如果新增的节点的class为"floor-single-card",这部分一般是直播间、番剧、国创、课堂、综艺推荐卡片,干掉
                    if (node.className === "floor-single-card") {
                        removeAds(node, "Ban原因:推送");
                        return;
                    }
                    // 如果新增的节点的class为"bili-video-card is-rcmd",这部分一般是不能点不感兴趣的卡片,直接干掉
                    if (node.className === "bili-video-card is-rcmd") {
                        removeAds(node, "Ban原因:广告");
                        return;
                    }
                    if (node.className === "bili-video-card is-rcmd enable-no-interest")
                    {
                        node.style.marginTop = '22px';
                    }
                    
                    if (BlockVideoByUp(node) !== true)
                        BlockVideoByVideo(node);
                }
            });
        });
    });

    // 监听整个文档
    observer.observe(document, {
        childList: true,
        subtree: true
    });

    // 移除滚动播放广告
    // 找到所有class为"recommended-swipe grid-anchor"的div,这就是左上角的广告滚动页
    var ads = document.getElementsByClassName("recommended-swipe grid-anchor");
    for (var i = 0; i < ads.length; i++) {
        removeAds(ads[i], "Ban原因:广告滚动页");
    }

    // 找到所有首页的广告
    // 找到所有class为"bili-video-card is-rcmd"的div
    ads = document.getElementsByClassName("bili-video-card is-rcmd");
    for (i = 0; i < ads.length; i++) {
        if (ads[i].className === "bili-video-card is-rcmd")
        {
            if (ads[i].parentNode.className === "feed-card")
                removeAds(ads[i].parentNode, "Ban原因:广告");
            else
                removeAds(ads[i], "Ban原因:广告");
        }
    }

    ads = document.getElementsByClassName("feed-card");
    for (i = 0; i < ads.length; i++) {
        // 将样式中的margin-top设为40像素
        ads[i].style.marginTop = '22px';
        if (BlockVideoByUp(ads[i]) !== true)
            BlockVideoByVideo(ads[i]);
    }


})();