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.1
// @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 > 0) {
callback(elements);
} else if (Date.now() - startTime < timeout) {
setTimeout(check, checkInterval);
} else {
console.warn("超时,未找到目标元素");
}
}
check();
}
function closePage() {
window.close();
}
async function fetchIllustDetails(pixivID) {
const apiUrl = `https://www.pixiv.net/ajax/illust/${pixivID}`;
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;
const newImgUrl = `https://i.pixiv.cat/c/360x360_70/img-master/img/${year}/${month}/${day}/${hour}/${minute}/${second}/${id}_p0_square1200.jpg`;
const formattedDate = `${year}-${month}-${day}`;
const illustTitle = data.body.title;
const authorId = data.body.tags.authorId;
const userUrl = `https://www.pixiv.net/en/users/${authorId}`;
const artworkUrl = `https://www.pixiv.net/en/artworks/${pixivID}`;
const username = data.body.userName;
console.log(`作品ID ${pixivID} 缩略URL:${newImgUrl}`);
return {
imgUrl: newImgUrl,
illustTitle,
artworkUrl,
userUrl,
date: formattedDate,
username,
};
} else {
console.warn(`无法提取${pixivID}`);
return null;
}
}
} catch (error) {
console.error("获取信息时报错:", error);
return null;
}
}
async function fetchAllPixivUrls(uniquePixivIDs) {
let imgUrls = [];
let additionalData = [];
for (const pixivID of uniquePixivIDs) {
const result = await fetchIllustDetails(pixivID);
if (result) {
imgUrls.push(result.imgUrl); // 添加图片URL
additionalData.push({
title: result.illustTitle,
artworkUrl: result.artworkUrl,
userUrl: result.userUrl,
date: result.date,
username: result.username,
});
}
}
GM_setValue("pixivImgUrls", imgUrls);
GM_setValue("pixivAdditionalData", additionalData);
return { imgUrls, additionalData };
}
if (GM_getValue("isFetchingPixiv", false)) {
console.log("少女不用祈祷...");
return;
}
waitForElements("div.gtm-toppage-thumbnail-illustration-recommend-works-zone", async function(divs) {
let pixivIDs = new Set(); // 去重
divs.forEach(div => {
div.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 removeAds() {
// 1.处理未替换的广告
document.querySelectorAll('.bili-video-card.is-rcmd').forEach(card => {
if (!card.classList.contains('enable-no-interest')) {
let imageLink = card.querySelector('.bili-video-card__image--link');
if (imageLink) {
// 获取父元素的宽度
let parentWidth = card.offsetWidth;
let parentHeight = parentWidth * (9 / 16);
let placeholder = document.createElement("div");
placeholder.style.cssText = `
position: relative;
width: 100%;
height: 0;
padding-top: 56.25%;
background: #f4f4f4;
border-radius: 8px;
border: 1px dashed #ccc;
margin: auto;
`;
let textContainer = document.createElement("div");
textContainer.style.cssText = `
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #888;
font-size: 14px;
font-weight: bold;
text-align: center;
width: 100%;
`;
textContainer.innerText = "🚫 广告已屏蔽";
placeholder.appendChild(textContainer);
imageLink.replaceWith(placeholder);
// 清空文字内容,但保留元素结构,不知道为什么一定得要有字符在innerText,空格还不行。
let placeholderText = "\u200B";
let titleElement = card.querySelector('.bili-video-card__info--tit');
if (titleElement) {
let link = titleElement.querySelector('a');
if (link) {
link.innerText = placeholderText;
}
}
let authorElement = card.querySelector('.bili-video-card__info--author');
if (authorElement) authorElement.innerText = placeholderText;
let dateElement = card.querySelector('.bili-video-card__info--date');
if (dateElement) dateElement.innerText = placeholderText;
let creativeAd = card.querySelector('.vui_icon.bili-video-card__info--creative-ad');
if (creativeAd) creativeAd.remove();
let adInfo = card.querySelector('.bili-video-card__info--ad');
if (adInfo) adInfo.remove();
isPixivImageLoaded = false;
processAdsOrPlaceholders(placeholder);
}
}
});
// 处理已经替换成占位符的广告封面
document.querySelectorAll('div').forEach(placeholder => {
if (placeholder.innerText === "🚫 广告已屏蔽") {
processAdsOrPlaceholders(placeholder);
}
});
}
function processAdsOrPlaceholders(element) {
let pixivImgUrls = GM_getValue("pixivImgUrls", []);
let additionalData = GM_getValue("pixivAdditionalData", []);
if (pixivImgUrls.length>0) {
let imgUrl = pixivImgUrls.shift();
let { artworkUrl, title, date, username, userUrl} = additionalData.shift();
if (imgUrl) {
preloadImages(pixivImgUrls); // 预加载剩余图片
let img = document.createElement("img");
img.src = imgUrl;
img.alt = "Pixiv 图片";
img.style.cssText = `
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 8px;
`;
//包裹图片
let link = document.createElement("a");
link.href = artworkUrl;
link.target = "_blank";
link.style.display = "block";
link.appendChild(img);
//图片容器
let imgContainer = document.createElement("div");
imgContainer.style.cssText = `
position: relative;
width: 100%;
height: 0;
padding-top: 56.25%;
background: #f4f4f4;
border-radius: 8px;
overflow: hidden;
`;
imgContainer.appendChild(link);
element.removeAttribute('style');
element.innerHTML = ""; // 清空原内容
element.appendChild(imgContainer);
// 更新其他信息
let titleContainer = element.closest('.bili-video-card').querySelector('.bili-video-card__info--tit');
if (titleContainer) {
titleContainer.title = title;
let titleElement = titleContainer.querySelector('a');
if (titleElement) {
titleElement.innerText = title;
titleElement.href = artworkUrl;
titleElement.title = title;
}
}
let ownerElement = element.closest('.bili-video-card').querySelector('.bili-video-card__info--owner');
if (ownerElement) ownerElement.href = userUrl;
let authorElement = element.closest('.bili-video-card').querySelector('.bili-video-card__info--author');
if (authorElement) {
authorElement.innerText = username;
authorElement.title = username;
}
let dateElement = element.closest('.bili-video-card').querySelector('.bili-video-card__info--date');
if (dateElement) dateElement.innerText = "· " + date;
// 删除广告标识
element.closest('.bili-video-card').querySelectorAll('.vui_icon.bili-video-card__info--creative-ad, .bili-video-card__info--ad')
.forEach(el => el.remove());
// 标记 Pixiv 图片已加载
isPixivImageLoaded = true;
// 更新存储
GM_setValue("pixivImgUrls", pixivImgUrls);
console.log("ID剩余:"+pixivImgUrls.length);
GM_setValue("pixivAdditionalData", additionalData);
}
if (pixivImgUrls.length <= minThreshold && !isFetchingPixiv) {
console.log(`图片少于 ${minThreshold} 张(当前 ${pixivImgUrls.length} 张),重新抓取...`);
isFetchingPixiv = true;
GM_setValue("pixivFetched", false);
GM_openInTab("https://www.pixiv.net/en/", { active: false, insert: true, setParent: true });
}
}
}
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
let minThreshold = 3; // 设定最少剩余图片数,低于这个值就触发抓取
if (pixivImgUrls.length <= minThreshold && !isFetchingPixiv) {
console.log(`图片少于 ${minThreshold} 张,重新抓取...`);
let isFetchingPixiv = true;
let tab = GM_openInTab("https://www.pixiv.net/en/", { active: false, insert: true, setParent: true });
}
// 让火焰净化一切!!!
let preloadedImages = [];
removeSpecificElements();
GM_addValueChangeListener("pixivFetched", (name, oldValue, newValue, remote) => {
if (newValue === true) {
console.log("Pixiv 图片已抓取,等待 DOM 加载后更新广告...");
isPixivImageLoaded = false;
isFetchingPixiv = false;
let observer = new MutationObserver(() => {
if (document.querySelector('.bili-video-card')) {
removeAds();
observer.disconnect(); // 只执行一次
}
});
observer.observe(document.body, { childList: true, subtree: true });
setTimeout(() => {
if (document.body) {
removeAds();
} else {
console.warn("DOM未加载");
setTimeout(removeAds, 500);
}
}, 500);
}
});
let isPixivImageLoaded = false;
removeAds();
// 监听 DOM
let observer = new MutationObserver(() => {
removeSpecificElements();
removeAds();
});
observer.observe(document.body, { childList: true, subtree: true });
})();