您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在B站的多P稿件和合集中添加搜索框,进行内容搜索
// ==UserScript== // @name B站分P搜索 // @namespace https://github.com/LianTianYou // @version 1.0.2 // @description 在B站的多P稿件和合集中添加搜索框,进行内容搜索 // @author LianTianYou // @license MIT // @match https://www.bilibili.com/video/* // @icon https://www.bilibili.com/favicon.ico // @grant none // ==/UserScript== (() => { const clearBox = document.createElement("div"); const isDebug = false; function debug(...msg) { const isDebug = false; if (isDebug) { console.log(...msg); }; } /** * 清空筛选结果 */ function clearFilter(data) { if (data == null) return; if (data.parts == null || data.parts.length === 0) return; if (data.pages == null || data.pages.length === 0) return; data.parts.forEach((part, index) => { data.pages[index].style.display = "flex"; part.innerHTML = part.textContent; }); /* 定位到正在播放的分P */ // 分P的容器 const listContainer = document.querySelector('.video-pod__body'); // 当前选择的分P const selectedItem = document.querySelector('.video-pod__item.active'); if (listContainer && selectedItem) { // const offsetTop = selectedItem.offsetTop - listContainer.offsetTop; listContainer.scrollTo({ top: selectedItem.offsetTop, behavior: 'instant' }); } } /** * 根据关键字进行筛选 */ function toggleFilter(data, keyword) { if (keyword == null || data == null) return; if (data.parts == null || data.parts.length === 0) return; if (data.pages == null || data.pages.length === 0) return; const regex = new RegExp(`(${keyword})`, "ig"); debug(keyword); debug(regex); data.parts.forEach((part, index) => { const page = data.pages[index]; let value = part.textContent; if(value.search(regex) != -1) { // 匹配到关键词 page.style.display = "flex"; part.innerHTML = value.replaceAll(regex, '<em class="keyword">$1</em>'); } else { // 未匹配项 page.style.display = "none"; } }); } /** * 根据搜索框的结果进行处理 */ function searchFilter(data, keyword = "") { keyword = keyword.trim(); if (!keyword) { // 关键词为空 clearFilter(data); } else { // 有关键词 toggleFilter(data, keyword); } } /** * 改变清空按钮的显示状态 */ function changeClearBtn(value) { if (!value || value.trim() === "") { clearBox.style.display = "none"; } else if(clearBox.style.display !== "block") { clearBox.style.display = "block"; } } /** * 添加 style 标签 */ function addStyle() { let styleTag = document.createElement("style"); styleTag.type = "text/css"; styleTag.id = "bili-filter"; let styleCode = ` .search-box { margin: 5px auto 0 auto; /* padding: 0 10px; */ background: #F1F2F3; height: 44px; display: flex; align-items: center; } .search-box > input.search { height: 34px; width: 100%; padding: 0 10px; font-size: 14px; outline: none; border: 1px solid #e3e5e7; border-radius: 5px; caret-color: #5e5e5e; } .search-box > input.search:focus { border: 1px solid #00aeec; } .keyword { color: #f25d8e; font-style: normal; } .clear-box { display: none; position: absolute; right: 16px; } .clear-btn { width: 20px; height: 20px; cursor: pointer; display: flex; align-items: center; justify-content: center; } .clear-btn > svg { height: 8px; width: 8px; fill: #61666d; } `; styleTag.appendChild(document.createTextNode(styleCode)); document.querySelector("head").appendChild(styleTag); } /** * 创建自定义的 DOM 元素,并返回容器的节点 */ function createElement(data) { // 插入 style 标签 addStyle(); // 容器 const searchBox = document.createElement("div"); searchBox.className = "search-box"; // 搜索框 const search = document.createElement("input"); search.type = "search"; search.className = "search"; search.placeholder = "搜索分P..."; // search.addEventListener("change", function(e) { // searchFilter(data, e.target.value); // }); search.addEventListener("input", function(e) { searchFilter(data, e.target.value); changeClearBtn(e.target.value); }); searchBox.append(search); // 清空按钮 clearBox.className = "clear-box"; const clearBtn = document.createElement("div"); clearBtn.className = "clear-btn"; clearBtn.innerHTML = '<svg t="1706028151814" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9157" width="200" height="200"><path d="M632.117978 513.833356l361.805812 361.735298a85.462608 85.462608 0 1 1-121.001515 120.789974L511.116463 634.552816 146.913186 998.756094a86.026718 86.026718 0 0 1-121.706652-121.706652L389.480325 512.775651 27.674513 150.969839A85.392095 85.392095 0 0 1 148.393973 30.250379L510.199785 392.056191l366.671258-366.671258a86.026718 86.026718 0 0 1 121.706652 121.706652z" p-id="9158"></path></svg>'; clearBtn.addEventListener("click", function() { search.value = ""; searchFilter(data); changeClearBtn(""); }); clearBox.append(clearBtn); searchBox.append(clearBox); return searchBox; } /** * 在普通分P中添加元素 */ function insertToPages() { const data = { pages: document.querySelectorAll(".video-pod__body .video-pod__item.normal"), parts: document.querySelectorAll(".video-pod__body .video-pod__item.normal div.title-txt") }; if (data.pages == null || data.pages.length === 0 || data.parts == null || data.parts.length === 0) { return; } // 将元素插入到网页中 const searchBox = createElement(data); const pageList = document.querySelector(".video-pod__header .header-top"); // 分P列表 if (pageList) { pageList.after(searchBox); } } /** * 在合集中添加元素 */ function insertToSections() { const data = { pages: document.querySelectorAll(".video-episode-card"), parts: document.querySelectorAll(".video-episode-card .video-episode-card__info-title") }; // 将元素插入到网页中 const searchBox = createElement(data); // const headCon = document.querySelector(".video-sections-head"); // headCon.after(searchBox); // document.querySelector(".video-section-list").style.height = "auto"; } /** 等待元素出现 */ function waitExist(selecter, timeout = 5, check = null) { let interval = 50; let count = 0; const p = new Promise((resolve, reject) => { const timer = setInterval(() => { const ele = document.querySelector(selecter); if (interval * count > timeout * 1000) { clearInterval(timer); // debug("等待超时"); reject(new Error("等待超时")); } count++; debug(ele); if (!ele) return; if (check && !check(ele)) return; clearInterval(timer); resolve(ele); }, interval); }); return p; } /** * 入口函数 */ async function main() { try { // 等待弹幕列表出现 await waitExist("#danmukuBox", 5); debug("#danmukuBox 出现"); // 等待分P列表出现 await waitExist(".video-pod__body", 5); debug(".video-pod__body 出现"); // 等待分P列表顶部操作栏出现 await waitExist(".video-pod__header > .header-top", 5); debug(".header-top 出现"); await waitExist(".video-pod__item.active", 5); // 等待弹幕列表的标题出现 await waitExist("#danmukuBox .bui-dropdown-name", 5); debug(".bui-dropdown-name 出现"); insertToPages(); // if (document.querySelector(".video-pod__body")) { // // 等待分P列表出现 // debug(".video-pod__body 出现"); // // 等待分P列表顶部操作栏出现 // await waitExist(".video-pod__header > .header-top", 5); // debug(".header-top 出现"); // insertToPages(); // } else if(document.querySelector(".base-video-sections-v1")) { // debug("sections 出现"); // const result = await waitExist(".video-episode-card__info-playing .cur-play-icon", 5, (e) => e.style.display !== "none"); // debug("cur-play-icon 出现"); // debug(result); // await new Promise((resolve) => requestAnimationFrame(resolve)); // insertToSections(); // requestIdleCallback(() => { // debug("浏览器空闲"); // // debugger; // }); // } } catch(err) { debug(err); } debug("执行完毕"); } window.onload = () => { debug("onloaded"); main(); }; })();