您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在B站分P视频列表项左侧悬浮显示序号
// ==UserScript== // @name B站分P视频悬浮序号 // @namespace http://tampermonkey.net/ // @version 1.2 // @description 在B站分P视频列表项左侧悬浮显示序号 // @author You // @match https://www.bilibili.com/video/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; // 全局变量 let currentBV = null; let videoData = null; let retryCount = 0; const MAX_RETRIES = 3; let lastCheckResult = null; let numberSpans = []; // 存储所有创建的序号元素 let debounceTimer; // 获取视频数据 async function fetchData() { try { const bvMatch = window.location.pathname.match(/\/video\/(BV\w+)/); if (!bvMatch) return []; const bv = bvMatch[1]; if (bv === currentBV && videoData !== null) { return videoData; } currentBV = bv; const apiUrl = `https://api.bilibili.com/x/player/pagelist?bvid=${bv}`; const response = await fetch(apiUrl); const result = await response.json(); videoData = result.data || []; return videoData; } catch (error) { console.error('获取视频数据出错:', error); return []; } } // 检查是否为分P视频 async function isMultiPartVideo() { const data = await fetchData(); return data.length > 1; } // 清理已创建的序号元素 function cleanupNumberSpans() { numberSpans.forEach(span => { if (span && span.parentNode) { span.parentNode.removeChild(span); } }); numberSpans = []; } // 获取元素在视口中的位置 function getElementPosition(element) { const rect = element.getBoundingClientRect(); return { top: rect.top + window.scrollY, left: rect.left + window.scrollX, height: rect.height }; } // 添加悬浮序号 async function addNumberIndicators() { // 清理之前的序号 cleanupNumberSpans(); // 检查当前视频是否为分P const bvMatch = window.location.pathname.match(/\/video\/(BV\w+)/); if (!bvMatch) return; const currentBVID = bvMatch[1]; const needCheck = currentBV !== currentBVID || lastCheckResult === null; if (needCheck) { const isMultiPart = await isMultiPartVideo(); lastCheckResult = isMultiPart; if (!isMultiPart) { console.log('当前视频不是分P视频,不添加序号'); return; } } else if (!lastCheckResult) { return; } // 获取列表容器 const listContainer = document.querySelector('.video-pod__list.multip.list'); if (!listContainer) { if (retryCount < MAX_RETRIES) { retryCount++; setTimeout(addNumberIndicators, 3000); } return; } // 获取所有列表项 const items = listContainer.querySelectorAll('.video-pod__item'); if (items.length === 0) { if (retryCount < MAX_RETRIES) { retryCount++; setTimeout(addNumberIndicators, 3000); } return; } retryCount = 0; // 为每个列表项创建序号 items.forEach((item, index) => { const numberSpan = document.createElement('div'); numberSpan.className = 'tm-video-number'; numberSpan.textContent = index + 1; // 设置样式 numberSpan.style.cssText = ` position: absolute; left: 0; top: 0; font-size: 13px; font-weight: bold; color: #00a1d6; background-color: rgba(255,255,255,0.9); padding: 1px 6px; border-radius: 10px; display: none; z-index: 9999; min-width: 18px; text-align: center; box-shadow: 0 1px 3px rgba(0,0,0,0.1); border: 1px solid #e7e7e7; pointer-events: none; transform: translate(-120%, -50%); `; // 添加到body document.body.appendChild(numberSpan); numberSpans.push(numberSpan); // 更新位置函数 const updatePosition = () => { const itemPos = getElementPosition(item); numberSpan.style.top = `${itemPos.top + itemPos.height/2}px`; numberSpan.style.left = `${itemPos.left}px`; }; // 初始定位 updatePosition(); // 事件监听 item.addEventListener('mouseenter', () => { numberSpan.style.display = 'block'; updatePosition(); }); item.addEventListener('mouseleave', () => { numberSpan.style.display = 'none'; }); // 添加全局事件监听 window.addEventListener('scroll', updatePosition); window.addEventListener('resize', updatePosition); }); console.log("已为视频列表添加序号"); } // 防抖函数 function debounce(func, delay) { return function() { clearTimeout(debounceTimer); debounceTimer = setTimeout(func, delay); }; } // 添加全局样式 const style = document.createElement('style'); style.textContent = ` .tm-video-number { transition: opacity 0.2s ease; } .night-mode .tm-video-number { color: #00a1d6 !important; background-color: rgba(33,33,33,0.9) !important; border-color: #444 !important; } `; document.head.appendChild(style); // 初始化函数 function init() { // 清理可能存在的旧监听器 window.removeEventListener('scroll', updateAllPositions); window.removeEventListener('resize', updateAllPositions); window.removeEventListener('popstate', handleRouteChange); // 添加新监听器 window.addEventListener('scroll', updateAllPositions); window.addEventListener('resize', updateAllPositions); window.addEventListener('popstate', handleRouteChange); // 重写pushState const originalPushState = history.pushState; history.pushState = function(...args) { originalPushState.apply(history, args); handleRouteChange(); }; // 初始执行 setTimeout(addNumberIndicators, 2000); } // 更新所有序号位置 function updateAllPositions() { numberSpans.forEach((span, index) => { const items = document.querySelectorAll('.video-pod__item'); if (items[index]) { const itemPos = getElementPosition(items[index]); span.style.top = `${itemPos.top + itemPos.height/2}px`; span.style.left = `${itemPos.left}px`; } }); } // 处理路由变化 function handleRouteChange() { debounce(addNumberIndicators, 500)(); } // 页面加载完成后初始化 window.addEventListener('load', init); })();