您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
根据根据关键词和正则表达式,自动关闭在标题或标签中包含这些关键词的B站视频
// ==UserScript== // @name B站防沉迷 // @namespace http://tampermonkey.net/ // @version 1.0.1 // @license MIT // @icon https://www.bilibili.com/favicon.ico // @description 根据根据关键词和正则表达式,自动关闭在标题或标签中包含这些关键词的B站视频 // @author Vz // @match *://*.bilibili.com/* // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // ==/UserScript== (function() { 'use strict'; //默认参数 const defaultBlockedWords = [ '这是关键词', '/这是正则表达式/' ]; const defaultStartTime = "16:00"; const defaultEndTime = "22:00"; const defaultEnableTimeRange = true; const defaultShowTips = true; // 获取当前时间 const now = new Date(); const currentHour = now.getHours(); const currentMinute = now.getMinutes(); // 从存储中加载关键词列表和时间设置 let blockedWords = GM_getValue('blockedWords',defaultBlockedWords ); let startTime = GM_getValue('startTime', defaultStartTime); let endTime = GM_getValue('endTime', defaultEndTime); let showTips = GM_getValue('showTips', defaultShowTips); let enableTimeRange = GM_getValue('enableTimeRange', defaultEnableTimeRange); //运行时更新参数 function getCustomValue () { blockedWords = GM_getValue('blockedWords',defaultBlockedWords ); startTime = GM_getValue('startTime', defaultStartTime); endTime = GM_getValue('endTime', defaultEndTime); showTips = GM_getValue('showTips', defaultShowTips); enableTimeRange = GM_getValue('enableTimeRange', defaultEnableTimeRange); } if(!enableTimeRange){ //不勾选停用时段直接执行主逻辑 mainLogic(); }else{ // 将时间字符串转换为分钟数 function timeToMinutes(timeString) { const [hours, minutes] = timeString.split(':').map(Number); return hours * 60 + minutes; } // 检查当前时间是否在停用区间内 const currentTimeInMinutes = currentHour * 60 + currentMinute; const startTimeInMinutes = timeToMinutes(startTime); const endTimeInMinutes = timeToMinutes(endTime); if (!(currentTimeInMinutes >= startTimeInMinutes && currentTimeInMinutes < endTimeInMinutes)) { // 不在停用时间内,才执行主逻辑 mainLogic(); } } // 获取当前页面的标题 function getTitle() { const url = new URL(window.location.href); const path = url.pathname; // 根据路径选择不同的标题元素类名 let titleElement; if (path.startsWith('/video/')) { titleElement = document.querySelector('.video-title'); } else if (path.startsWith('/list/')) { titleElement = document.querySelector('.video-title-href'); } //alert(titleElement ? titleElement.innerHTML : 'No title found'); return titleElement ? titleElement.innerHTML : ''; } // 获取视频的 BV 号 function getBvNumber() { const url = new URL(window.location.href); const path = url.pathname; const searchParams = url.searchParams; // 从路径中获取 BV 号 if (path.startsWith('/video/')) { const bvMatch = path.match(/\/video\/(BV\w+)/); return bvMatch ? bvMatch[1] : null; } else if (path.startsWith('/list/')) { return searchParams.get('bvid'); } return null; } // 获取视频标签 function getVideoApiTags(videoBv) { fetch(`https://api.bilibili.com/x/web-interface/view/detail/tag?bvid=${videoBv}`) .then((response) => response.json()) .then((data) => { const tags = data.data ? data.data.map(tag => tag.tag_name) : []; checkBlockedWords(getTitle(), tags); }) .catch((error) => console.error('Error fetching video tags:', error)); } // 检查标题和标签是否包含屏蔽关键词 function checkBlockedWords(title, tags) { //调试用 //alert('title: ' + title + '\n' + 'tags: ' + tags + '\n' + 'bvNumber: ' + bvNumber); // 将标题和标签转换为小写 const allText = [title.toLowerCase(), ...tags.map(tag => tag.toLowerCase())].join(' '); for (const word of blockedWords) { if (typeof word === 'string' && word.trim() === '') { // 跳过空串的检查 continue; } if (typeof word === 'string'&& !word.startsWith('/')) { if (allText.includes(word.toLowerCase())) { if(showTips){ alert('Blocked by keyword: ' + word); } window.close(); window.stop(); window.location.href = 'about:blank'; return; } } else if (word.startsWith('/')) { // 修改正则表达式以不区分大小写 const insensitiveWord = new RegExp(word.slice(1, -1), 'ius'); if (insensitiveWord.test(allText)) { if(showTips){ alert('Blocked by regex: ' + word); } window.close(); window.stop(); window.location.href = 'about:blank'; return; } } } } // 主逻辑 function mainLogic() { // 获取当前页面的完整 URL const currentUrl = window.location.href; if (currentUrl.includes('/video/') || currentUrl.includes('/list/')) { const bvNumber = getBvNumber(); if (bvNumber) { getVideoApiTags(bvNumber); } else { checkBlockedWords(getTitle(), []); } }} // 创建模态对话框 function createModal() { // 从存储中加载关键词列表和时间设置 getCustomValue(); const modal = document.createElement('div'); modal.id = 'keywordModal'; modal.innerHTML = ` <div id="modalContent"> <h2>关键词列表</h2> <ul> <li>每行一个关键词或正则,不区分大小写</li> <li>请勿使用过于激进的关键词或正则</li> <li>正则默认 ius 模式,无需 flag,语法:/abc小d+/</li> </ul> <textarea id="keywordList"></textarea> <div id="timeSelector"> <label><input type="checkbox" id="enableTimeRange" ${enableTimeRange ? 'checked' : ''}> 停用时段: </label> <div style="display: inline-block;margin-top: 5px;"> <input type="time" id="startTime" name="startTime" value="${startTime}"> <span> - </span> <input type="time" id="endTime" name="endTime" value="${endTime}"> </div> </div> <div style="margin-bottom: 10px;"> <label><input type="checkbox" id="showTips" ${showTips ? 'checked' : ''}> 网页关闭提示 (仅提示,不会阻止网页关闭)</label> </div> <button id="saveButton">保存</button> <button id="closeButton">关闭</button> <div id="saveStatus">保存成功!</div> </div> `; // 填充文本域 const keywordListTextArea = modal.querySelector('#keywordList'); keywordListTextArea.value = blockedWords.join('\n'); // 保存按钮事件 modal.querySelector('#saveButton').addEventListener('click', () => { const newKeywords = keywordListTextArea.value.split('\n').map(line => { if (line.startsWith('/')) { try { new RegExp(line.slice(1, -1), 'ius'); return line } catch (e) { alert(`Invalid regex: ${line}`); return null; } } return line; }).filter(Boolean); const newStartTime = modal.querySelector('#startTime').value; const newEndTime = modal.querySelector('#endTime').value; const newEnableTimeRange = modal.querySelector('#enableTimeRange').checked; const newShowTips = modal.querySelector('#showTips').checked; GM_setValue('blockedWords', newKeywords); GM_setValue('startTime', newStartTime); GM_setValue('endTime', newEndTime); GM_setValue('enableTimeRange', newEnableTimeRange); GM_setValue('showTips', newShowTips); //alert("enableTimeRange: " + newEnableTimeRange); const saveStatus = modal.querySelector('#saveStatus') saveStatus.style.color = "#00AEEC"; // 定义一个变量来存储 setTimeout 的 ID let timeoutId = null; // 函数来设置定时器 function setMyTimeout() { // 清除之前的定时器(如果存在) if (timeoutId) { clearTimeout(timeoutId); } // 设置新的定时器 timeoutId = setTimeout(() => { setTimeout(() =>{saveStatus.style.color = "rgba(0,0,0,0)"; mainLogic(); },1200); }, 1200); } // 调用函数来设置定时器 setMyTimeout(); }); // 关闭按钮事件 modal.querySelector('#closeButton').addEventListener('click', () => { closeModal(); }); // 添加模态对话框到页面 document.body.appendChild(modal); } // 关闭模态对话框 function closeModal() { const modal = document.getElementById('keywordModal'); if (modal) { modal.remove(); } } // 注册菜单命令 GM_registerMenuCommand('🔑 关键词设置', createModal); const style = document.createElement('style'); style.innerHTML = ` #keywordModal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.2); display: flex; justify-content: center; align-items: center; z-index: 1000; } #modalContent { background-color: white; padding: 20px; border-radius: 8px; width: 30%; max-width: 300px; min-width:240px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); font-size: 14px; } #modalContent h2 { margin-bottom: 10px; font-weight: bold; font-size: 16px; } #modalContent ul { margin-bottom: 10px; font-size: 12px; color: #555555; } #modalContent #keywordList { max-width: 100%; width: 100%; height: 200px; box-sizing: border-box; padding: 6px; border-radius: 4px; border: 2px solid #D1D5DB; font-family: inherit; } #modalContent #timeSelector { padding: 10px 0; } #modalContent input { vertical-align: -1.5px; } /* 设置选中状态下的checkbox样式 */ #modalContent input:checked { background-color: #00AEEC; /* 你可以更改这个颜色为你想要的颜色 */ } #modalContent #startTime, #modalContent #endTime { padding:0 4px; border-radius: 4px; border: 2px solid #D1D5DB; font-family: inherit; } #modalContent button { margin-top: 10px; padding: 5px 16px; cursor: pointer; border-radius: 4px; border: none; outline: 2px solid #D1D5DB; font-size: 14px; } #modalContent #saveButton { margin-right: 10px; color: white; background-color: #00AEEC; outline: 2px solid #00AEEC; } #modalContent #saveStatus { float: right; margin-top: 10px; color: rgba(0,0,0,0); transition: all 0.2s ease-out; font-size: 16px; } `; document.head.appendChild(style); })();