Greasy Fork

Greasy Fork is available in English.

屏蔽B站营销视频和推广视频

屏蔽部分B站(bilibili)主页推荐的视频卡片,屏蔽up主粉丝少于一定数量的,屏蔽直播与右侧推广,屏蔽带广告标签的

当前为 2024-06-14 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==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.0
// @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
// ==/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.error(`getUid error, processedCards: ${processedCards}, uid: ${uid}`);
        return -1;
      }
    }

    console.error(`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.error(`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.error(`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: '20px', 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();
})();