您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
视频检测设置面板,样式自定义、临界时长调整,支持禁用检测恢复原样,添加自定义规则
// ==UserScript== // @name Bilibili隐藏短视频 // @namespace http://tampermonkey.net/ // @version 6.4 // @description 视频检测设置面板,样式自定义、临界时长调整,支持禁用检测恢复原样,添加自定义规则 // @match *://www.bilibili.com/* // @grant GM_registerMenuCommand // @license GPL 2.0 // ==/UserScript== (function () { 'use strict'; let minDuration = parseInt(localStorage.getItem('minDuration')) || 300; let debounceDelay = parseInt(localStorage.getItem('debounceDelay')) || 500; let isActive = JSON.parse(localStorage.getItem('isActive')) || true; let isPanelVisible = JSON.parse(localStorage.getItem('isPanelVisible')) || false; let styleChoice = localStorage.getItem('styleChoice') || '半透明'; let detectedElements = []; let customRules = JSON.parse(localStorage.getItem('customRules')) || []; let settings = { warnMarketingAccount: JSON.parse(localStorage.getItem('warnMarketingAccount')) || true, warnLowQualityName: JSON.parse(localStorage.getItem('warnLowQualityName')) || true, warnClickbaitTitle: JSON.parse(localStorage.getItem('warnClickbaitTitle')) || true, warnFakeHacker: JSON.parse(localStorage.getItem('warnFakeHacker')) || true, warnPseudoScience: JSON.parse(localStorage.getItem('warnPseudoScience')) || true, }; function initControlPanel() { if (document.getElementById("controlPanel")) return; const panel = document.createElement("div"); panel.style.position = "fixed"; panel.style.top = "10px"; panel.style.right = "10px"; panel.style.width = "260px"; panel.style.padding = "10px"; panel.style.backgroundColor = "#f9f9f9"; panel.style.border = "1px solid #ccc"; panel.style.borderRadius = "8px"; panel.style.boxShadow = "0px 0px 10px rgba(0, 0, 0, 0.1)"; panel.style.zIndex = "9999"; panel.id = "controlPanel"; panel.style.display = isPanelVisible ? "block" : "none"; panel.innerHTML = ` <h3>检测设置 <span id="closePanel" style="cursor:pointer;float:right;">×</span></h3> <label>分界时间 (秒): <input type="number" id="minDuration" value="${minDuration}"></label><br> <label>防抖延迟 (毫秒): <input type="number" id="debounceDelay" value="${debounceDelay}"></label><br> <label>样式选择: <select id="styleChoice"> <option value="半透明" ${styleChoice === '半透明' ? 'selected' : ''}>半透明</option> <option value="边框高亮" ${styleChoice === '边框高亮' ? 'selected' : ''}>边框高亮</option> <option value="背景高亮" ${styleChoice === '背景高亮' ? 'selected' : ''}>背景高亮</option> </select> </label><br> <label><input type="checkbox" id="warnMarketingAccount" ${settings.warnMarketingAccount ? 'checked' : ''}> 警惕营销号</label><br> <label><input type="checkbox" id="warnLowQualityName" ${settings.warnLowQualityName ? 'checked' : ''}> 小心科技区小学生低质视频</label><br> <label><input type="checkbox" id="warnClickbaitTitle" ${settings.warnClickbaitTitle ? 'checked' : ''}> 小心标题党</label><br> <label><input type="checkbox" id="warnFakeHacker" ${settings.warnFakeHacker ? 'checked' : ''}> 警惕假黑客</label><br> <label><input type="checkbox" id="warnPseudoScience" ${settings.warnPseudoScience ? 'checked' : ''}> 小心伪科普</label><br> <button id="toggleDetection">${isActive ? "禁用检测" : "启用检测"}</button> <button id="addCustomRule">添加自定义规则</button> <button id="clearLogs">清空日志</button> <h4>检测日志</h4> <div id="logInfo" style="height: 100px; overflow-y: auto; background: #e9e9e9; padding: 5px; border-radius: 4px;"></div> `; document.body.appendChild(panel); document.getElementById("toggleDetection").onclick = toggleDetection; document.getElementById("closePanel").onclick = closePanel; document.getElementById("minDuration").onchange = updateSettings; document.getElementById("debounceDelay").onchange = updateSettings; document.getElementById("styleChoice").onchange = updateSettings; document.getElementById("warnMarketingAccount").onchange = updateSettings; document.getElementById("warnLowQualityName").onchange = updateSettings; document.getElementById("warnClickbaitTitle").onchange = updateSettings; document.getElementById("warnFakeHacker").onchange = updateSettings; document.getElementById("warnPseudoScience").onchange = updateSettings; document.getElementById("addCustomRule").onclick = addCustomRule; document.getElementById("clearLogs").onclick = clearLogs; } function toggleDetection() { isActive = !isActive; localStorage.setItem("isActive", isActive); document.getElementById("toggleDetection").textContent = isActive ? "禁用检测" : "启用检测"; if (!isActive) { clearMarkers(); } else { runDetection(); } } function closePanel() { isPanelVisible = false; localStorage.setItem("isPanelVisible", isPanelVisible); document.getElementById("controlPanel").style.display = "none"; } function updateSettings() { minDuration = parseInt(document.getElementById("minDuration").value); debounceDelay = parseInt(document.getElementById("debounceDelay").value); styleChoice = document.getElementById("styleChoice").value; settings.warnMarketingAccount = document.getElementById("warnMarketingAccount").checked; settings.warnLowQualityName = document.getElementById("warnLowQualityName").checked; settings.warnClickbaitTitle = document.getElementById("warnClickbaitTitle").checked; settings.warnFakeHacker = document.getElementById("warnFakeHacker").checked; settings.warnPseudoScience = document.getElementById("warnPseudoScience").checked; localStorage.setItem("minDuration", minDuration); localStorage.setItem("debounceDelay", debounceDelay); localStorage.setItem("styleChoice", styleChoice); localStorage.setItem("warnMarketingAccount", settings.warnMarketingAccount); localStorage.setItem("warnLowQualityName", settings.warnLowQualityName); localStorage.setItem("warnClickbaitTitle", settings.warnClickbaitTitle); localStorage.setItem("warnFakeHacker", settings.warnFakeHacker); localStorage.setItem("warnPseudoScience", settings.warnPseudoScience); runDetection(); } function addCustomRule() { const rule = prompt("请输入自定义规则(格式:关键词:提示)"); if (rule) { const [keyword, tip] = rule.split(":"); if (keyword && tip) { customRules.push({ keyword: keyword.trim(), tip: tip.trim() }); localStorage.setItem("customRules", JSON.stringify(customRules)); } else { alert("规则格式不正确,请使用“关键词:提示”的格式!"); } } } function clearLogs() { detectedElements = []; document.getElementById("logInfo").innerHTML = ""; } function updateLogInfo() { const logDiv = document.getElementById("logInfo"); logDiv.innerHTML = ` 当前检测到的视频数量:${detectedElements.length}<br> 索引位置:${detectedElements.map((elem) => elem.index).join(", ")} `; } function convertDurationToSeconds(durationText) { const timeParts = durationText.split(":").map(Number); if (timeParts.length === 2) { return timeParts[0] * 60 + timeParts[1]; } else if (timeParts.length === 3) { return timeParts[0] * 3600 + timeParts[1] * 60 + timeParts[2]; } return 0; } function clearMarkers() { detectedElements.forEach((item) => { item.element.style.opacity = "1"; item.element.style.border = ""; item.element.style.backgroundColor = ""; const warning = item.element.querySelector(".short-video-warning"); if (warning) warning.remove(); }); detectedElements = []; updateLogInfo(); } function applyStyle(element, warningText) { if (styleChoice === "半透明") { element.style.opacity = "0.5"; } else if (styleChoice === "边框高亮") { element.style.border = "2px solid red"; } else if (styleChoice === "背景高亮") { element.style.backgroundColor = "rgba(255, 0, 0, 0.2)"; } if (warningText) { const warning = document.createElement("div"); warning.className = "short-video-warning"; warning.style.position = "absolute"; warning.style.top = "10px"; warning.style.left = "10px"; warning.style.padding = "4px 8px"; warning.style.backgroundColor = "rgba(255, 0, 0, 1)"; // 不透明 warning.style.color = "white"; warning.style.fontSize = "12px"; warning.style.fontWeight = "bold"; warning.style.borderRadius = "4px"; warning.style.zIndex = "10"; warning.textContent = warningText; element.style.position = "relative"; element.appendChild(warning); } } function processVideoCards() { const videoSelectors = ['.bili-video-card', '.video-page-card-small']; videoSelectors.forEach((selector) => { const videoCards = document.querySelectorAll(selector); videoCards.forEach((card, index) => { if (detectedElements.find((elem) => elem.element === card)) return; const followedElement = card.querySelector('.bili-video-card__info--icon-text') || card.querySelector('.upname .name'); if (followedElement && followedElement.textContent.includes('已关注')) return; const upNameElement = card.querySelector('.bili-video-card__info--author') || card.querySelector('.upname .name'); const titleElement = card.querySelector('.bili-video-card__info--tit a') || card.querySelector('.title a'); const durationElement = card.querySelector('.bili-video-card__stats__duration') || card.querySelector('.duration'); let warningText = ""; // 检测营销号 if (settings.warnMarketingAccount && upNameElement && upNameElement.textContent.includes("观察")) { warningText = "警惕营销号"; } // 检测低质量视频 else if (settings.warnLowQualityName && upNameElement && (upNameElement.textContent.match(/_/g) || []).length >= 2) { warningText = "小心科技区小学生低质视频"; } // 检测标题党 else if (settings.warnClickbaitTitle && titleElement && (titleElement.textContent.match(/!/g) || []).length >= 2) { warningText = "小心标题党"; } // 检测假黑客 else if (settings.warnFakeHacker && upNameElement && /(黑客|网安|白帽)/.test(upNameElement.textContent)) { warningText = "警惕假黑客"; } // 检测伪科普 else if (settings.warnPseudoScience && titleElement && /(禁止废话|废话)/.test(titleElement.textContent)) { warningText = "小心伪科普"; } // 自定义规则检测 else { for (let rule of customRules) { if ((upNameElement && upNameElement.textContent.includes(rule.keyword)) || (titleElement && titleElement.textContent.includes(rule.keyword))) { warningText = rule.tip; break; } } } // 检测短视频 if (!warningText && durationElement) { const durationText = durationElement.textContent.trim(); const durationInSeconds = convertDurationToSeconds(durationText); if (durationInSeconds < minDuration) { warningText = durationInSeconds < 60 ? "小心沉迷短视频!" : "短视频"; } } if (warningText) { applyStyle(card, warningText); detectedElements.push({ element: card, index }); updateLogInfo(); } }); }); } // 防抖函数定义 function debounce(func, delay) { let timeout; return function (...args) { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, args), delay); }; } const observer = new MutationObserver(debounce(() => { if (isActive) runDetection(); }, debounceDelay)); function runDetection() { clearMarkers(); processVideoCards(); } initControlPanel(); observer.observe(document.body, { childList: true, subtree: true }); GM_registerMenuCommand("显示/隐藏控制面板", () => { isPanelVisible = !isPanelVisible; localStorage.setItem("isPanelVisible", isPanelVisible); document.getElementById("controlPanel").style.display = isPanelVisible ? "block" : "none"; }); })();