Last active
April 8, 2026 13:01
-
-
Save Qixingchen/94c69949cd90f4858ebb7d200c44e135 to your computer and use it in GitHub Desktop.
隐藏B站动态短视频及充电视频
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name 隐藏B站动态短视频 | |
| // @namespace http://tampermonkey.net/ | |
| // @version 1.2 | |
| // @description 隐藏B站动态页面中视频长度小于1分钟的条目,以及充电专属视频 | |
| // @author qixingchen | |
| // @match https://t.bilibili.com/* | |
| // @icon https://www.bilibili.com/favicon.ico | |
| // @grant none | |
| // @run-at document-idle | |
| // @updateURL https://gist.github.com/Qixingchen/94c69949cd90f4858ebb7d200c44e135/raw/hide_short_videos.user.js | |
| // @downloadURL https://gist.github.com/Qixingchen/94c69949cd90f4858ebb7d200c44e135/raw/hide_short_videos.user.js | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| // 配置:最小视频时长(秒),小于此值将被隐藏 | |
| const MIN_DURATION_SECONDS = 60; | |
| let hiddenCount = 0; | |
| let hiddenChargeCount = 0; | |
| // 解析时长字符串(格式如 "04:09", "00:16", "1:23:45") | |
| function parseDuration(durationStr) { | |
| const parts = durationStr.split(':').map(Number); | |
| if (parts.length === 2) { | |
| // MM:SS 格式 | |
| return parts[0] * 60 + parts[1]; | |
| } else if (parts.length === 3) { | |
| // HH:MM:SS 格式 | |
| return parts[0] * 3600 + parts[1] * 60 + parts[2]; | |
| } | |
| return 0; | |
| } | |
| // 格式化秒数为可读字符串 | |
| function formatDuration(seconds) { | |
| if (seconds < 60) { | |
| return `${seconds}秒`; | |
| } else if (seconds < 3600) { | |
| return `${Math.floor(seconds / 60)}分${seconds % 60}秒`; | |
| } else { | |
| const h = Math.floor(seconds / 3600); | |
| const m = Math.floor((seconds % 3600) / 60); | |
| return `${h}小时${m}分`; | |
| } | |
| } | |
| // 获取当前屏幕顶部显示的是第几条可见动态 | |
| function getTopVisibleIndex() { | |
| const visibleItems = Array.from(document.querySelectorAll('.bili-dyn-list__item:not([style*="display: none"])')); | |
| for (let i = 0; i < visibleItems.length; i++) { | |
| const rect = visibleItems[i].getBoundingClientRect(); | |
| // 找到第一个底部在视口内的条目 | |
| if (rect.bottom > 0) { | |
| return i + 1; | |
| } | |
| } | |
| return 1; | |
| } | |
| // 显示统计信息 | |
| function showStats() { | |
| let statsEl = document.getElementById('hide-short-video-stats'); | |
| if (!statsEl) { | |
| statsEl = document.createElement('div'); | |
| statsEl.id = 'hide-short-video-stats'; | |
| statsEl.style.cssText = ` | |
| position: fixed; | |
| bottom: 20px; | |
| right: 20px; | |
| background: rgba(0, 161, 214, 0.9); | |
| color: white; | |
| padding: 10px 15px; | |
| border-radius: 8px; | |
| font-size: 14px; | |
| z-index: 10000; | |
| font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; | |
| box-shadow: 0 2px 10px rgba(0,0,0,0.2); | |
| cursor: pointer; | |
| transition: opacity 0.3s; | |
| `; | |
| statsEl.title = '点击隐藏此提示'; | |
| statsEl.onclick = () => { | |
| statsEl.style.opacity = '0'; | |
| setTimeout(() => statsEl.remove(), 300); | |
| }; | |
| document.body.appendChild(statsEl); | |
| } | |
| if (hiddenCount > 0 || hiddenChargeCount > 0) { | |
| const visibleCount = document.querySelectorAll('.bili-dyn-list__item:not([style*="display: none"])').length; | |
| const topIndex = getTopVisibleIndex(); | |
| let line1 = `第 ${topIndex}/${visibleCount} 条动态`; | |
| let line2 = ''; | |
| if (hiddenCount > 0) { | |
| line2 += `已隐藏 ${hiddenCount} 个短视频(<${formatDuration(MIN_DURATION_SECONDS)})`; | |
| } | |
| if (hiddenChargeCount > 0) { | |
| if (hiddenCount > 0) line2 += ','; | |
| line2 += `${hiddenChargeCount} 个充电专属`; | |
| } | |
| statsEl.innerHTML = line1 + '<br>' + line2; | |
| statsEl.style.display = 'block'; | |
| } else { | |
| statsEl.style.display = 'none'; | |
| } | |
| } | |
| // 检查是否为充电专属视频 | |
| function isChargeExclusive(listItem) { | |
| // 充电专属角标的选择器 | |
| const chargeBadges = listItem.querySelectorAll('.bili-dyn-card-video__badge, .bili-dyn-card-video__tag'); | |
| for (const badge of chargeBadges) { | |
| const text = badge.textContent.trim(); | |
| if (text.includes('充电专属') || text.includes('充电')) { | |
| return true; | |
| } | |
| } | |
| // 也检查其他可能的角标位置 | |
| const allBadges = listItem.querySelectorAll('[class*="badge"], [class*="tag"]'); | |
| for (const badge of allBadges) { | |
| const text = badge.textContent.trim(); | |
| if (text === '充电专属' || text === '充电') { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| // 隐藏短视频条目和充电专属视频 | |
| function hideShortVideos() { | |
| // 查找所有视频时长元素 | |
| const durationElements = document.querySelectorAll('.duration-time'); | |
| let newHidden = 0; | |
| let newChargeHidden = 0; | |
| // 处理所有动态条目 | |
| const listItems = document.querySelectorAll('.bili-dyn-list__item'); | |
| listItems.forEach(listItem => { | |
| // 跳过已处理的元素 | |
| if (listItem.dataset.hideProcessed) return; | |
| listItem.dataset.hideProcessed = 'true'; | |
| // 检查是否为充电专属 | |
| if (isChargeExclusive(listItem)) { | |
| if (listItem.style.display !== 'none') { | |
| listItem.style.display = 'none'; | |
| listItem.dataset.hiddenByScript = 'true'; | |
| listItem.dataset.hiddenReason = 'charge'; | |
| newChargeHidden++; | |
| console.log(`[隐藏短视频] 已隐藏充电专属视频`); | |
| } | |
| return; | |
| } | |
| // 查找时长元素 | |
| const durationEl = listItem.querySelector('.duration-time'); | |
| if (!durationEl) return; | |
| const durationStr = durationEl.textContent.trim(); | |
| const durationSeconds = parseDuration(durationStr); | |
| // 如果时长小于阈值,隐藏整个动态条目 | |
| if (durationSeconds > 0 && durationSeconds < MIN_DURATION_SECONDS) { | |
| if (listItem.style.display !== 'none') { | |
| listItem.style.display = 'none'; | |
| listItem.dataset.hiddenByScript = 'true'; | |
| listItem.dataset.hiddenReason = 'short'; | |
| newHidden++; | |
| console.log(`[隐藏短视频] 已隐藏 ${durationStr} 的视频`); | |
| } | |
| } | |
| }); | |
| if (newHidden > 0 || newChargeHidden > 0) { | |
| hiddenCount += newHidden; | |
| hiddenChargeCount += newChargeHidden; | |
| showStats(); | |
| } | |
| } | |
| // 使用 MutationObserver 监听动态内容变化 | |
| const observer = new MutationObserver((mutations) => { | |
| hideShortVideos(); | |
| }); | |
| // 页面加载完成后开始观察 | |
| const startObserver = () => { | |
| const listContainer = document.querySelector('.bili-dyn-list__items'); | |
| if (listContainer) { | |
| observer.observe(listContainer, { | |
| childList: true, | |
| subtree: true | |
| }); | |
| // 初始执行一次 | |
| hideShortVideos(); | |
| } else { | |
| // 如果容器还没加载,等待后重试 | |
| setTimeout(startObserver, 500); | |
| } | |
| }; | |
| // 页面加载后启动 | |
| if (document.readyState === 'loading') { | |
| document.addEventListener('DOMContentLoaded', startObserver); | |
| } else { | |
| startObserver(); | |
| } | |
| // 同时也监听整个 body 的变化,以防容器后来才出现 | |
| const bodyObserver = new MutationObserver(() => { | |
| if (document.querySelector('.bili-dyn-list__items')) { | |
| startObserver(); | |
| bodyObserver.disconnect(); | |
| } | |
| }); | |
| bodyObserver.observe(document.body, { childList: true, subtree: true }); | |
| // 监听滚动事件,实时更新当前位置 | |
| let scrollTimer = null; | |
| window.addEventListener('scroll', () => { | |
| if (scrollTimer) clearTimeout(scrollTimer); | |
| scrollTimer = setTimeout(() => { | |
| if (hiddenCount > 0 || hiddenChargeCount > 0) { | |
| showStats(); | |
| } | |
| }, 100); | |
| }, { passive: true }); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment