Greasy Fork

Greasy Fork is available in English.

B站广告替换为Pixiv推荐图片

移除B站首页推荐中的所有推广视频广告,包括小火箭🚀,漫画,纪录片等,以及正统广告。使用Pixiv推荐图片替换广告内容。需要提前登陆过pixiv账号,不需要Cookies或者账号token。

当前为 2025-02-26 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name           B站广告替换为Pixiv推荐图片
// @name:en        Bilibili Ad Replacement with Pixiv Recommended Images
// @namespace      http://tampermonkey.net/
// @version        1.4
// @description    移除B站首页推荐中的所有推广视频广告,包括小火箭🚀,漫画,纪录片等,以及正统广告。使用Pixiv推荐图片替换广告内容。需要提前登陆过pixiv账号,不需要Cookies或者账号token。
// @description:en Remove promotional video ads from Bilibili's homepage recommendations, including small rocket 🚀 ads and regular ads. Use Pixiv recommended images to replace the ads. A Pixiv account must be logged in beforehand, but no cookies or account tokens are required.
// @author         RecycleBee 
// @match          *://www.bilibili.com/*
// @match          *://www.pixiv.net/en/*
// @grant          GM_openInTab
// @grant          GM_addValueChangeListener
// @grant          GM_setValue
// @grant          GM_getValue
// @grant          GM_xmlhttpRequest
// @license MIT

// ==/UserScript==

(function() {
    'use strict';

    const currentUrl = window.location.href;


    // === 处理 Pixiv 页面 ===
    if (currentUrl.includes("pixiv.net/en/")) {
        console.log("少女祈祷中...");

        function waitForElements(selector, callback, timeout = 10000) {
            const startTime = Date.now();
            const checkInterval = 500;

            function check() {
                let elements = document.querySelectorAll(selector);
                if (elements.length > 2) {
                    callback(elements);
                } else if (Date.now() - startTime < timeout) {
                    setTimeout(check, checkInterval);
                } else {
                    console.warn("超时,未找到目标元素");
                    closePage();
                }
            }

            check();
        }

        function closePage() {
            window.close();
        }

        async function fetchIllustDetails(pixivID) {
            const apiUrl = `https://www.pixiv.net/ajax/illust/${pixivID}`;

            // 获得构建缩略图URL需要的时间,API提供:https://github.com/AgMonk/pixiv-utils
            try {
                const response = await fetch(apiUrl);
                const data = await response.json();

                if (data.body && data.body.urls) {
                    let imgUrl = data.body.urls.original;
                    imgUrl = imgUrl.replace(/\\/g, "");
                    const dateMatch = imgUrl.match(/\/(\d{4})\/(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})\/(\d+)/); // 提取日期
                    if (dateMatch) {
                        const [_, year, month, day, hour, minute, second, id] = dateMatch;

                        // 构建缩略图URL提高速度
                        const newImgUrl = `https://i.pixiv.cat/c/360x360_70/img-master/img/${year}/${month}/${day}/${hour}/${minute}/${second}/${id}_p0_square1200.jpg`;
                        console.log(`作品ID ${pixivID} 的新图片 URL:${newImgUrl}`);
                        return newImgUrl;
                    } else {
                        console.warn(`无法提取日期:${pixivID}`);
                        return null;
                    }
                }
            } catch (error) {
                console.error("获取详细信息时出错:", error);
                return null;
            }
        }

        async function fetchAllPixivUrls(uniquePixivIDs) {
            let imgUrls = [];
            for (const pixivID of uniquePixivIDs) {
                const imgUrl = await fetchIllustDetails(pixivID);
                if (imgUrl) {
                    imgUrls.push(imgUrl); // 添加URL
                }
            }
            GM_setValue("pixivImgUrls", imgUrls);
            console.log("所有图片URL已保存:", imgUrls);
            return imgUrls;
        }

        waitForElements("div.sc-jgyytr-1", async function(divs) {
            let targetDiv = divs[3]; // 获取第三个 div,第二个是关注的画师,想改成什么去p站首页找一圈儿就行了。
            let pixivIDs = new Set(); // 去重

            targetDiv.querySelectorAll('a[href^="/en/artworks/"]').forEach(anchor => {
                let href = anchor.getAttribute("href");
                let match = href.match(/^\/en\/artworks\/(\d+)/);
                if (match) {
                    pixivIDs.add(match[1]);
                }
            });

            let uniquePixivIDs = Array.from(pixivIDs); //转为数组
            await fetchAllPixivUrls(uniquePixivIDs);
            GM_setValue("pixivFetched", true);
            closePage();
        });
        return;

    }

    // === 处理 Bilibili 页面 ===

    // 预先加载图片
    function preloadImages(imageUrls) {
        imageUrls.forEach(url => {
            if (!preloadedImages.some(img => img.src === url)) {
                let img = new Image();
                img.src = url;
                preloadedImages.push(img);
            }
        });
    }

    function processAdsOrPlaceholders(element) {
        // 处理广告或占位符
        let pixivImgUrls = GM_getValue("pixivImgUrls", []);
        if (pixivImgUrls.length > 0) {
            let imgUrl = pixivImgUrls.shift(); // 从图片列表中取出第一个图片 URL
            if (imgUrl) {
                preloadImages(pixivImgUrls); // 预加载所有图片

                let img = document.createElement("img");
                img.src = imgUrl;
                img.alt = "Pixiv 图片";
                img.style.cssText = `
            width: 263.84px;
            height: 148.4px;
            object-fit: cover; /* 保证图片按照容器大小裁切 */
            border-radius: 8px;
        `;

                element.innerHTML = ''; // 清除占位文字
                element.appendChild(img);

                // 更新存储
                GM_setValue("pixivImgUrls", pixivImgUrls);
            }
        } else {
            if (!isFetchingPixiv) {
                console.log("所有图片已用完,重新抓取...");
                isFetchingPixiv = true; // 设置标志
                GM_setValue("pixivFetched", false);
                let tab = GM_openInTab("https://www.pixiv.net/en/", { active: false, insert: true, setParent: true });
            }
        }
    }

    function removeAds() {
        // 1. 处理未替换的广告
        document.querySelectorAll('.bili-video-card.is-rcmd').forEach(card => {
            if (!card.classList.contains('enable-no-interest')) {
                let placeholder = document.createElement("div");
                placeholder.style.cssText = `
            display: flex;
            align-items: center;
            justify-content: center;
            width: 263.84px;
            height: 148.4px;
            background: #f4f4f4;
            color: #888;
            font-size: 14px;
            font-weight: bold;
            border-radius: 8px;
            border: 1px dashed #ccc;
            margin: auto;
        `;
                placeholder.innerText = "🚫 广告已屏蔽";

                // 先替换广告,再获取 Pixiv 图片 URL
                card.replaceWith(placeholder);

                processAdsOrPlaceholders(placeholder);
            }
        });

        // 2. 处理已经替换成占位符的广告
        document.querySelectorAll('div').forEach(placeholder => {
            if (placeholder.innerText === "🚫 广告已屏蔽") {
                processAdsOrPlaceholders(placeholder);
            }
        });
    }

    function removeSpecificElements() {
        // 1. 删除所有纪录片、漫画等
        document.querySelectorAll('div[data-v-128321c6]').forEach(element => {
            element.remove();
        });

        // 2. 删除所有瀑布流的广告
        document.querySelectorAll('div[data-v-3581b8d4]').forEach(element => {
            if (!element.closest('.feed-card') && element.classList.contains('bili-video-card') && element.classList.contains('is-rcmd') && element.classList.length === 2) {
                element.remove();
            }
        });
    }

    console.log("Bilibili 运行,检测是否需要抓取 Pixiv 图片...");
    let isFetchingPixiv = false;
    let pixivImgUrls = GM_getValue("pixivImgUrls", []); //检查是否有urls
    if (pixivImgUrls.length === 0 && !isFetchingPixiv) {
        console.log("没有可用的 Pixiv 图片,重新抓取...");
        let tab = GM_openInTab("https://www.pixiv.net/en/", { active: false, insert: true, setParent: true });
        isFetchingPixiv = true;
    }

    // 让火焰净化一切!!!
    let preloadedImages = [];
    removeSpecificElements();
    GM_addValueChangeListener("pixivFetched", (name, oldValue, newValue, remote) => {
        if (newValue === true) { // 更新广告
            console.log("Pixiv 图片已抓取,更新广告...");
            removeAds();
            isFetchingPixiv = false;
        }
    });
    removeAds();

    // 监听 DOM
    let observer = new MutationObserver(() => {
        removeSpecificElements();
        removeAds();
    });
    observer.observe(document.body, { childList: true, subtree: true });

})();