// ==UserScript== // @name 屏蔽B站营销视频和推广视频 // @name:zh-CN 屏蔽B站营销视频和推广视频 // @name:zh-TW 屏蔽B站营销视频和推广视频 // @name:en Block Bilibili's marketing videos and promotional videos // @namespace http://tampermonkey.net/ // @version 1.2 // @description 屏蔽部分B站(bilibili)主页推荐的视频卡片,屏蔽up主粉丝少于一定数量的,屏蔽直播与右侧推广,屏蔽带广告标签的 // @description:zh-CN 屏蔽部分B站(bilibili)主页推荐的视频卡片,屏蔽up主粉丝少于一定数量的,屏蔽直播与右侧推广,屏蔽带广告标签的 // @description:zh-TW 遮罩部分B站(bilibili)主頁推薦的視頻卡片,遮罩up主粉絲少於一定數量的,遮罩直播與右側推廣,遮罩帶廣告標籤的 // @description:en Block some video cards recommended on the homepage of Bilibili. The rules are to block those from creators with a certain number of small fans, block live streams and right-hand promotion, and block those with advertising tags. // @author anonymous // @match https://www.bilibili.com/ // @match https://www.bilibili.com/?spm_id_from=* // @icon https://www.bilibili.com/favicon.ico // @grant none // @license GNU General Public License v3.0 // @downloadURL none // ==/UserScript== (function () { 'use strict'; // 定义需要屏蔽的两种视频卡片类名 const BLOCKED_CLASSES = ['floor-single-card', 'bili-live-card is-rcmd']; // 定义需要屏蔽的最小的follower数 const MIN_FOLLOWER = 2000; // 定义接口前缀 const API_USERDATA = 'https://api.bilibili.com/x/relation/stat?vmid='; // 定义已处理卡片数量 let processedCards = 0; function getUid(card) { // 传入一个视频卡片,获取其中的uid并转化为数字并返回 const ownerLink = card.querySelector('.bili-video-card__info--owner'); if (ownerLink) { const uid = ownerLink.href.split('/').pop(); if (uid.match(/^\d+$/)) { return Number(uid); // return uid; } else { console.log(`🔴getUid error, processedCards: ${processedCards}, uid: ${uid}`); return -1; } } console.log(`🔴getUid error, ownerLink error, processedCards: ${processedCards}, ownerLink: ${ownerLink}`); return -1; } async function getFollower(uid) { // 传入uid,返回follower数 const response = await fetch(`${API_USERDATA}${uid}`); const data = await response.json(); if (data.code === 0) { return data.data.follower; } else { console.log(`🔴getFollower error, uid: ${uid}, message: ${data.message}`); return -1; } } // 对于每一个card,获取uid,然后获取follower,如果follower小于MIN_FOLLOWER,就remove // 未能获取到uid或者follower的,也remove // 不满足上面需要remove的,就processedCards++ // 进行异步处理,增加加载速度 // 最大并行处理数 const MAX_PARALLEL = 0; // 当前并行处理数 let parallel = 0; function editCards(card) { const uid = getUid(card); if (uid === -1) { console.log(`🟢remove because getUid error, uid: ${uid}`); card.remove(); return; } const follower = getFollower(uid); if (follower < MIN_FOLLOWER) { console.log(`🟢remove because follower < ${MIN_FOLLOWER}, uid: ${uid}, follower: ${follower}`); card.remove(); return; } } // 创建Intersection Observer实例 const observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { // 处理进入视口的元素 editCards(entry.target); processedCards++; parallel--; // 处理完毕后,停止观察该元素 observer.unobserve(entry.target); } }); }, { rootMargin: '0px', threshold: 0.1 }); // 可以根据需要调整配置 // 对新加载的内容进行观察 function observeNewCards() { const cards = document.querySelectorAll('.bili-video-card.is-rcmd, .floor-single-card, .bili-live-card.is-rcmd'); cards.forEach(card => { observer.observe(card); }); } // 使用MutationObserver来监听新内容的加载,并调用observeNewCards const mutationObserver = new MutationObserver((mutations) => { mutations.forEach(mutation => { if (mutation.type === 'childList') { observeNewCards(); } }); }); mutationObserver.observe(document.querySelector('.recommended-container_floor-aside'), { childList: true, subtree: true }); // 页面加载完成后,立即执行一次,以观察初始内容 observeNewCards(); })();