Greasy Fork is available in English.
移除B站首页推荐中的所有推广视频广告,包括小火箭🚀,漫画,纪录片等,以及正统广告。使用Pixiv推荐图片替换广告内容。需要提前登陆过pixiv账号,不需要Cookies或者账号token。
当前为
// ==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 });
})();