Bilibili 按标签、标题、时长、UP主屏蔽视频

对 Bilibili.com 的视频卡片元素,以标题、UP 主、标签、双重标签、充电专属、收藏投币比、竖屏、时长、播放量、点赞率、视频分区、UP 主等级、UP 主粉丝数、UP 主简介、精选评论、置顶评论来判断匹配,添加覆盖叠加层或隐藏视频,隐藏或屏蔽热搜、附带去除广告等非视频元素的功能。

< 腳本Bilibili 按标签、标题、时长、UP主屏蔽视频的回應

評論:正評 - 腳本一切正常

§
發表於:2025-09-20
編輯:2025-09-20

添加了右下角按钮, 点击可以打开ui; 在每个视频右下角添加一个快速获取视频标签的按钮, 点击后可以弹出ui快速选择需要屏蔽的标签. 以下代码可以直接添加到作者的脚本中(作者也可直接集成到脚本中).

(function() {
  // 创建按钮
  const btn = document.createElement("button");
  btn.textContent = "脚本配置";
  btn.style.position = "fixed";
  btn.style.bottom = "20px";
  btn.style.right = "20px";
  btn.style.zIndex = "999999";
  btn.style.padding = "8px 12px";
  btn.style.background = "#17181A";
  btn.style.color = "#fff";
  btn.style.border = "none";
  btn.style.borderRadius = "6px";
  btn.style.cursor = "pointer";

  // 点击按钮打开配置面板
  btn.addEventListener("click", () => {
    blockedMenuUi(); // 调用已有的UI函数
  });

  document.body.appendChild(btn);

(function () {
  'use strict';

  const SELECTOR = 'div.bili-video-card.is-rcmd';
  const tagsCache = {};

  function av2bv(aid) {
    const XOR_CODE = 23442827791579n;
    const MASK_CODE = 2251799813685247n;
    const MAX_AID = 1n << 51n;
    const BASE = 58n;
    const data = 'FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf';
    const bytes = ['B', 'V', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0'];
    let bvIndex = bytes.length - 1;
    let tmp = (MAX_AID | BigInt(aid)) ^ XOR_CODE;
    while (tmp > 0) {
      bytes[bvIndex] = data[Number(tmp % BigInt(BASE))];
      tmp = tmp / BASE;
      bvIndex -= 1;
    }
    [bytes[3], bytes[9]] = [bytes[9], bytes[3]];
    [bytes[4], bytes[7]] = [bytes[7], bytes[4]];
    return bytes.join('');
  }

  function extractBv(card) {
    const a = card.querySelector('a.bili-video-card__image--link');
    if (!a) return null;
    const href = a.href || '';
    const bvMatch = href.match(/\/(BV[0-9A-Za-z]+)/);
    if (bvMatch) return bvMatch[1];
    const avMatch = href.match(/\/(av)(\d+)/i);
    if (avMatch) return av2bv(avMatch[2]);
    return null;
  }

  async function fetchTags(bv) {
    if (!bv) return '';
    if (tagsCache[bv]) return tagsCache[bv];
    try {
      const resp = await fetch(`https://api.bilibili.com/x/web-interface/view/detail/tag?bvid=${bv}`, { credentials: 'omit' });
      const j = await resp.json();
      let tags = '';
      if (j && Array.isArray(j.data)) {
        tags = j.data.map(t => t.tag_name.replace(/\s+/g, '')).filter(Boolean).join(',');
      } else if (j && j.data && Array.isArray(j.data.tags)) {
        tags = j.data.tags.map(t => t.tag_name || t).filter(Boolean).join(',');
      }
      tagsCache[bv] = tags;
      return tags;
    } catch (e) {
      tagsCache[bv] = '';
      return '';
    }
  }

  function copyToClipboard(text) {
    if (!text) return false;
    if (typeof GM_setClipboard === 'function') {
      try { GM_setClipboard(text); return true; } catch (e) {}
    }
    if (navigator.clipboard && navigator.clipboard.writeText) {
      return navigator.clipboard.writeText(text).then(() => true).catch(() => fallbackCopy(text));
    }
    return fallbackCopy(text);
  }

  function fallbackCopy(text) {
    try {
      const ta = document.createElement('textarea');
      ta.value = text;
      ta.style.position = 'fixed';
      ta.style.left = '-9999px';
      document.body.appendChild(ta);
      ta.select();
      document.execCommand('copy');
      document.body.removeChild(ta);
      return true;
    } catch (e) {
      return false;
    }
  }

  function showTempText(btn, msg, timeout = 1400) {
    const old = btn.innerText;
    btn.innerText = msg;
    setTimeout(() => { btn.innerText = old; }, timeout);
  }

  function addButtonToCard(card) {
    if (card.dataset.copyTagsBtnAdded) return;
    card.dataset.copyTagsBtnAdded = '1';
    card.style.position = card.style.position || 'relative';

    const btnHTML = `<button type="button" class="gm-copy-tags-btn"
        style="position: absolute; bottom: 6px; right: 6px; z-index: 100; padding: 4px 8px; font-size: 12px; background: #17181A; color: #fff; border: none; border-radius: 6px; cursor: pointer; box-shadow: 0 2px 6px rgba(0,0,0,0.2);">
        📋
    </button>`;
    card.insertAdjacentHTML('beforeend', btnHTML);

    const btn = card.querySelector('.gm-copy-tags-btn');
    if (!btn) return;
    if (btn.dataset.listenerAdded) return;
    btn.dataset.listenerAdded = '1';

    btn.addEventListener('click', async (e) => {
      e.stopPropagation();
      e.preventDefault();
      btn.disabled = true;
      const bv = extractBv(card);
      if (!bv) {
        showTempText(btn, '未找到BV');
        btn.disabled = false;
        return;
      }
      const tags = await fetchTags(bv);
      if (tags) {
        // 改为打开标签选择UI而不是直接复制
        showTagSelectionUI(tags.split(','), bv);
        showTempText(btn, '标签已加载');
      } else {
        showTempText(btn, '无标签');
      }
      btn.disabled = false;
    });
  }

  function showTagSelectionUI(tags, bv) {
      // 创建模态框
      const modal = document.createElement('div');
      modal.style.position = 'fixed';
      modal.style.top = '50%';
      modal.style.left = '50%';
      modal.style.transform = 'translate(-50%, -50%)';
      modal.style.zIndex = '10000';
      modal.style.background = '#2a2a2a';
      modal.style.padding = '20px';
      modal.style.borderRadius = '8px';
      modal.style.boxShadow = '0 4px 12px rgba(0,0,0,0.3)';
      modal.style.maxWidth = '80%';
      modal.style.maxHeight = '80%';
      modal.style.overflow = 'auto';

      // 添加标题
      const title = document.createElement('h3');
      title.textContent = `选择要屏蔽的标签 (BV: ${bv})`;
      title.style.margin = '0 0 15px 0';
      title.style.color = '#fff';
      modal.appendChild(title);

      // 添加标签容器
      const tagsContainer = document.createElement('div');
      tagsContainer.style.display = 'flex';
      tagsContainer.style.flexWrap = 'wrap';
      tagsContainer.style.gap = '8px';
      tagsContainer.style.marginBottom = '15px';

      // 添加标签按钮
      tags.forEach(tag => {
        if (!tag) return;

        const tagBtn = document.createElement('button');
        tagBtn.textContent = tag;
        tagBtn.style.padding = '6px 12px';
        tagBtn.style.background = '#3a3a3a';
        tagBtn.style.color = '#fff';
        tagBtn.style.border = 'none';
        tagBtn.style.borderRadius = '4px';
        tagBtn.style.cursor = 'pointer';

        tagBtn.addEventListener('click', () => {
          // 添加到屏蔽标签数组
          if (!blockedParameter.blockedTag_Array.includes(tag)) {
            blockedParameter.blockedTag_Array.push(tag);
            // 保存设置
            GM_setValue("GM_blockedParameter", blockedParameter);

            // 显示添加成功提示
            tagBtn.style.background = '#4caf50';
            setTimeout(() => {
              tagBtn.style.background = '#3a3a3a';
            }, 1000);
          } else {
            // 如果已存在,显示提示
            tagBtn.style.background = '#ff5722';
            setTimeout(() => {
              tagBtn.style.background = '#3a3a3a';
            }, 1000);
          }
        });

        tagsContainer.appendChild(tagBtn);
      });

      modal.appendChild(tagsContainer);

      // 添加关闭按钮
      const closeBtn = document.createElement('button');
      closeBtn.textContent = '关闭';
      closeBtn.style.padding = '8px 16px';
      closeBtn.style.background = '#558EFF';
      closeBtn.style.color = '#fff';
      closeBtn.style.border = 'none';
      closeBtn.style.borderRadius = '4px';
      closeBtn.style.cursor = 'pointer';

      closeBtn.addEventListener('click', () => {
        document.body.removeChild(modal);
        document.body.removeChild(overlay);
      });

      modal.appendChild(closeBtn);

      // 添加半透明背景
      const overlay = document.createElement('div');
      overlay.style.position = 'fixed';
      overlay.style.top = '0';
      overlay.style.left = '0';
      overlay.style.width = '100%';
      overlay.style.height = '100%';
      overlay.style.background = 'rgba(0,0,0,0.7)';
      overlay.style.zIndex = '9999';

      document.body.appendChild(overlay);
      document.body.appendChild(modal);

      // 点击背景关闭
      overlay.addEventListener('click', () => {
        document.body.removeChild(modal);
        document.body.removeChild(overlay);
      });
      }

  function scanAndInject() {
    const cards = document.querySelectorAll(SELECTOR);
    cards.forEach(addButtonToCard);
  }

  scanAndInject();

  const mo = new MutationObserver((mutations) => {
    for (const m of mutations) {
      if (m.addedNodes && m.addedNodes.length) {
        scanAndInject();
        break;
      }
    }
  });
  mo.observe(document.body, { childList: true, subtree: true });

})();

})();

§
發表於:2025-09-20

使用这个优化后的版本

(function() {
  // 创建按钮
  const btn = document.createElement("button");
  btn.textContent = "脚本配置";
  btn.style.position = "fixed";
  btn.style.bottom = "20px";
  btn.style.right = "20px";
  btn.style.zIndex = "999999";
  btn.style.padding = "8px 12px";
  btn.style.background = "#17181A";
  btn.style.color = "#fff";
  btn.style.border = "none";
  btn.style.borderRadius = "6px";
  btn.style.cursor = "pointer";

  // 点击按钮打开配置面板
  btn.addEventListener("click", () => {
    blockedMenuUi(); // 调用已有的UI函数
  });

  document.body.appendChild(btn);

(function () {
  'use strict';

  const SELECTOR = 'div.bili-video-card.is-rcmd';
  const tagsCache = {};

  function av2bv(aid) {
    const XOR_CODE = 23442827791579n;
    const MASK_CODE = 2251799813685247n;
    const MAX_AID = 1n << 51n;
    const BASE = 58n;
    const data = 'FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf';
    const bytes = ['B', 'V', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0'];
    let bvIndex = bytes.length - 1;
    let tmp = (MAX_AID | BigInt(aid)) ^ XOR_CODE;
    while (tmp > 0) {
      bytes[bvIndex] = data[Number(tmp % BigInt(BASE))];
      tmp = tmp / BASE;
      bvIndex -= 1;
    }
    [bytes[3], bytes[9]] = [bytes[9], bytes[3]];
    [bytes[4], bytes[7]] = [bytes[7], bytes[4]];
    return bytes.join('');
  }

  function extractBv(card) {
    const a = card.querySelector('a.bili-video-card__image--link');
    if (!a) return null;
    const href = a.href || '';
    const bvMatch = href.match(/\/(BV[0-9A-Za-z]+)/);
    if (bvMatch) return bvMatch[1];
    const avMatch = href.match(/\/(av)(\d+)/i);
    if (avMatch) return av2bv(avMatch[2]);
    return null;
  }

  async function fetchTags(bv) {
    if (!bv) return '';
    if (tagsCache[bv]) return tagsCache[bv];
    try {
      const resp = await fetch(`https://api.bilibili.com/x/web-interface/view/detail/tag?bvid=${bv}`, { credentials: 'omit' });
      const j = await resp.json();
      let tags = '';
      if (j && Array.isArray(j.data)) {
        tags = j.data.map(t => t.tag_name.replace(/\s+/g, '')).filter(Boolean).join(',');
      } else if (j && j.data && Array.isArray(j.data.tags)) {
        tags = j.data.tags.map(t => t.tag_name || t).filter(Boolean).join(',');
      }
      tagsCache[bv] = tags;
      return tags;
    } catch (e) {
      tagsCache[bv] = '';
      return '';
    }
  }

  function copyToClipboard(text) {
    if (!text) return false;
    if (typeof GM_setClipboard === 'function') {
      try { GM_setClipboard(text); return true; } catch (e) {}
    }
    if (navigator.clipboard && navigator.clipboard.writeText) {
      return navigator.clipboard.writeText(text).then(() => true).catch(() => fallbackCopy(text));
    }
    return fallbackCopy(text);
  }

  function fallbackCopy(text) {
    try {
      const ta = document.createElement('textarea');
      ta.value = text;
      ta.style.position = 'fixed';
      ta.style.left = '-9999px';
      document.body.appendChild(ta);
      ta.select();
      document.execCommand('copy');
      document.body.removeChild(ta);
      return true;
    } catch (e) {
      return false;
    }
  }

  function showTempText(btn, msg, timeout = 1400) {
    const old = btn.innerText;
    btn.innerText = msg;
    setTimeout(() => { btn.innerText = old; }, timeout);
  }

  function addButtonToCard(card) {
    if (card.dataset.copyTagsBtnAdded) return;
    card.dataset.copyTagsBtnAdded = '1';
    card.style.position = card.style.position || 'relative';

    const btnHTML = `<button type="button" class="gm-copy-tags-btn"
        style="position: absolute; bottom: 6px; right: 6px; z-index: 100; padding: 4px 8px; font-size: 12px; background: #17181A; color: #fff; border: none; border-radius: 6px; cursor: pointer; box-shadow: 0 2px 6px rgba(0,0,0,0.2);">
        📋
    </button>`;
    card.insertAdjacentHTML('beforeend', btnHTML);

    const btn = card.querySelector('.gm-copy-tags-btn');
    if (!btn) return;
    if (btn.dataset.listenerAdded) return;
    btn.dataset.listenerAdded = '1';

    btn.addEventListener('click', async (e) => {
      e.stopPropagation();
      e.preventDefault();
      btn.disabled = true;
      const bv = extractBv(card);
      if (!bv) {
        showTempText(btn, '未找到BV');
        btn.disabled = false;
        return;
      }
      const tags = await fetchTags(bv);
      if (tags) {
        // 改为打开标签选择UI而不是直接复制
        showTagSelectionUI(tags.split(','), bv);
        showTempText(btn, '标签已加载');
      } else {
        showTempText(btn, '无标签');
      }
      btn.disabled = false;
    });
  }

  function showTagSelectionUI(tags, bv) {
      // 创建模态框
      const modal = document.createElement('div');
      modal.style.position = 'fixed';
      modal.style.top = '50%';
      modal.style.left = '50%';
      modal.style.transform = 'translate(-50%, -50%)';
      modal.style.zIndex = '10000';
      modal.style.background = '#2a2a2a';
      modal.style.padding = '20px';
      modal.style.borderRadius = '8px';
      modal.style.boxShadow = '0 4px 12px rgba(0,0,0,0.3)';
      modal.style.maxWidth = '80%';
      modal.style.maxHeight = '80%';
      modal.style.overflow = 'auto';
      modal.style.color = '#fff';

      // 添加标题
      const title = document.createElement('h3');
      title.textContent = `选择要屏蔽的标签 (BV: ${bv})`;
      title.style.margin = '0 0 15px 0';
      modal.appendChild(title);

      // 添加说明
      const description = document.createElement('p');
      description.textContent = '绿色背景表示已添加到屏蔽列表,点击可移除;灰色背景表示未添加,点击可添加';
      description.style.margin = '0 0 15px 0';
      description.style.fontSize = '14px';
      description.style.color = '#ccc';
      modal.appendChild(description);

      // 添加标签容器
      const tagsContainer = document.createElement('div');
      tagsContainer.style.display = 'flex';
      tagsContainer.style.flexWrap = 'wrap';
      tagsContainer.style.gap = '8px';
      tagsContainer.style.marginBottom = '15px';

      // 添加标签按钮
      tags.forEach(tag => {
        if (!tag) return;

        const tagBtn = document.createElement('button');
        tagBtn.textContent = tag;
        tagBtn.style.padding = '6px 12px';
        tagBtn.style.border = 'none';
        tagBtn.style.borderRadius = '4px';
        tagBtn.style.cursor = 'pointer';
        tagBtn.style.transition = 'all 0.2s ease';

        // 检查标签是否已经在屏蔽列表中
        const isAlreadyBlocked = blockedParameter.blockedTag_Array.includes(tag);

        // 根据是否已屏蔽设置不同的样式
        if (isAlreadyBlocked) {
          tagBtn.style.background = '#4caf50'; // 绿色表示已屏蔽
          tagBtn.style.color = '#fff';
          tagBtn.title = '点击从屏蔽列表中移除';
        } else {
          tagBtn.style.background = '#3a3a3a'; // 灰色表示未屏蔽
          tagBtn.style.color = '#fff';
          tagBtn.title = '点击添加到屏蔽列表';
        }

        tagBtn.addEventListener('click', () => {
          const index = blockedParameter.blockedTag_Array.indexOf(tag);

          if (index === -1) {
            // 添加到屏蔽标签数组
            blockedParameter.blockedTag_Array.push(tag);
            tagBtn.style.background = '#4caf50'; // 变为绿色
            tagBtn.title = '点击从屏蔽列表中移除';

            // 显示添加成功提示
            const tempText = tagBtn.textContent;
            tagBtn.textContent = '✓ 已添加';
            setTimeout(() => {
              tagBtn.textContent = tempText;
            }, 1000);
          } else {
            // 从屏蔽标签数组中移除
            blockedParameter.blockedTag_Array.splice(index, 1);
            tagBtn.style.background = '#3a3a3a'; // 变为灰色
            tagBtn.title = '点击添加到屏蔽列表';

            // 显示移除成功提示
            const tempText = tagBtn.textContent;
            tagBtn.textContent = '✗ 已移除';
            setTimeout(() => {
              tagBtn.textContent = tempText;
            }, 1000);
          }

          // 保存设置
          GM_setValue("GM_blockedParameter", blockedParameter);

          // 触发屏蔽检查
          FuckYouBilibiliRecommendationSystem();
        });

        tagsContainer.appendChild(tagBtn);
      });

      modal.appendChild(tagsContainer);

      // 添加操作按钮容器
      const buttonContainer = document.createElement('div');
      buttonContainer.style.display = 'flex';
      buttonContainer.style.gap = '10px';
      buttonContainer.style.justifyContent = 'flex-end';

      // 添加一键全部按钮
      const addAllBtn = document.createElement('button');
      addAllBtn.textContent = '一键全部添加';
      addAllBtn.style.padding = '8px 16px';
      addAllBtn.style.background = '#558EFF';
      addAllBtn.style.color = '#fff';
      addAllBtn.style.border = 'none';
      addAllBtn.style.borderRadius = '4px';
      addAllBtn.style.cursor = 'pointer';

      addAllBtn.addEventListener('click', () => {
        tags.forEach(tag => {
          if (!tag || blockedParameter.blockedTag_Array.includes(tag)) return;
          blockedParameter.blockedTag_Array.push(tag);
        });

        // 更新UI样式
        tagsContainer.querySelectorAll('button').forEach(btn => {
          btn.style.background = '#4caf50';
          btn.title = '点击从屏蔽列表中移除';
        });

        // 保存设置
        GM_setValue("GM_blockedParameter", blockedParameter);

        // 触发屏蔽检查
        FuckYouBilibiliRecommendationSystem();

        // 显示成功提示
        addAllBtn.textContent = '✓ 已全部添加';
        setTimeout(() => {
          addAllBtn.textContent = '一键全部添加';
        }, 1000);
      });

      // 添加关闭按钮
      const closeBtn = document.createElement('button');
      closeBtn.textContent = '关闭';
      closeBtn.style.padding = '8px 16px';
      closeBtn.style.background = '#666';
      closeBtn.style.color = '#fff';
      closeBtn.style.border = 'none';
      closeBtn.style.borderRadius = '4px';
      closeBtn.style.cursor = 'pointer';

      closeBtn.addEventListener('click', () => {
        document.body.removeChild(modal);
        document.body.removeChild(overlay);
      });

      buttonContainer.appendChild(addAllBtn);
      buttonContainer.appendChild(closeBtn);
      modal.appendChild(buttonContainer);

      // 添加半透明背景
      const overlay = document.createElement('div');
      overlay.style.position = 'fixed';
      overlay.style.top = '0';
      overlay.style.left = '0';
      overlay.style.width = '100%';
      overlay.style.height = '100%';
      overlay.style.background = 'rgba(0,0,0,0.7)';
      overlay.style.zIndex = '9999';

      document.body.appendChild(overlay);
      document.body.appendChild(modal);

      // 点击背景关闭
      overlay.addEventListener('click', (e) => {
        if (e.target === overlay) {
          document.body.removeChild(modal);
          document.body.removeChild(overlay);
        }
      });

      // ESC键关闭
      const handleKeydown = (e) => {
        if (e.key === 'Escape') {
          document.body.removeChild(modal);
          document.body.removeChild(overlay);
          document.removeEventListener('keydown', handleKeydown);
        }
      };

      document.addEventListener('keydown', handleKeydown);
    }

  function scanAndInject() {
    const cards = document.querySelectorAll(SELECTOR);
    cards.forEach(addButtonToCard);
  }

  scanAndInject();

  const mo = new MutationObserver((mutations) => {
    for (const m of mutations) {
      if (m.addedNodes && m.addedNodes.length) {
        scanAndInject();
        break;
      }
    }
  });
  mo.observe(document.body, { childList: true, subtree: true });

})();

})();

發表回覆

登入以回覆

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址