您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
支持设置自定义片头片尾,播放时自动跳转
// ==UserScript== // @name B站自动跳片头片尾 // @namespace http://tampermonkey.net/ // @version 1.7 // @description 支持设置自定义片头片尾,播放时自动跳转 // @author mankaki // @match *://www.bilibili.com/video/* // @icon https://www.bilibili.com/favicon.ico // @grant none // @license GPL-3.0 // ==/UserScript== (function() { 'use strict'; const KEY_HEAD = 'bili_skip_head'; const KEY_TAIL = 'bili_skip_tail'; const KEY_ENABLED = 'bili_skip_enabled'; let headSec = parseFloat(localStorage.getItem(KEY_HEAD)) || null; let tailSec = parseFloat(localStorage.getItem(KEY_TAIL)) || null; let enabled = localStorage.getItem(KEY_ENABLED) === 'true'; let hasJumpedToTail = false; // 标志变量,记录是否已跳转到片尾 // 创建浮窗 const infoDiv = document.createElement('div'); Object.assign(infoDiv.style, { position: 'fixed', bottom: '80px', right: '20px', padding: '8px 12px', background: 'rgba(0,0,0,0.7)', color: '#fff', fontSize: '14px', borderRadius: '4px', zIndex: 9999, fontFamily: 'sans-serif', opacity: 0, display: 'none', transition: 'opacity 0.5s' }); document.body.appendChild(infoDiv); let hideTimer = null; function showInfo() { const head = headSec !== null ? formatTime(headSec) : '—'; const tail = tailSec !== null ? formatTime(tailSec) : '—'; const status = enabled ? '✅ 开启' : '❌ 关闭'; infoDiv.textContent = `片头: ${head} 片尾: ${tail} 状态: ${status}`; infoDiv.style.display = 'block'; infoDiv.style.opacity = '1'; if (hideTimer) clearTimeout(hideTimer); hideTimer = setTimeout(() => { infoDiv.style.opacity = '0'; setTimeout(() => infoDiv.style.display = 'none', 500); }, 3000); } function formatTime(sec) { const h = Math.floor(sec / 3600), m = Math.floor(sec % 3600 / 60), s = Math.floor(sec % 60); return (h > 0 ? h + ':' : '') + String(m).padStart(2, '0') + ':' + String(s).padStart(2, '0'); } function parseTime(str) { if (!str) return null; let sec = 0; if (str.includes(':')) { const p = str.split(':').map(Number).reverse(); sec = (p[0] || 0) + (p[1] || 0) * 60 + (p[2] || 0) * 3600; } else sec = parseFloat(str); return isNaN(sec) ? null : sec; } // 设置片头/尾 function setTimes() { let h = prompt('设置片头时间(mm:ss 或 秒数,不跳请留空):', headSec !== null ? formatTime(headSec) : ''); let t = prompt('设置片尾时间(mm:ss 或 秒数,不跳请留空):', tailSec !== null ? formatTime(tailSec) : ''); const hSec = parseTime(h); const tSec = parseTime(t); if ((h && hSec === null) && (t && tSec === null)) return alert('至少设置一个有效时间'); headSec = hSec; tailSec = tSec; localStorage.setItem(KEY_HEAD, headSec === null ? '' : headSec); localStorage.setItem(KEY_TAIL, tailSec === null ? '' : tailSec); enabled = true; localStorage.setItem(KEY_ENABLED, 'true'); showInfo(); } // 监控播放跳转片头/尾 function monitor(video) { video.addEventListener('timeupdate', () => { if (!enabled) return; const currentTime = video.currentTime; const duration = video.duration; if (headSec !== null && currentTime < headSec) { video.currentTime = headSec; } else if (tailSec !== null && duration - currentTime <= tailSec) { // 在片尾时间段内,跳转到视频的最后一秒,仅跳转一次 if (!hasJumpedToTail) { video.currentTime = duration - 1; hasJumpedToTail = true; } } else { // 重置标志变量,以便下次进入片尾时间段时可以跳转 hasJumpedToTail = false; } }); } document.addEventListener('keydown', e => { const tag = document.activeElement.tagName; if (tag === 'INPUT' || tag === 'TEXTAREA') return; // Shift + M 设置片头片尾时间 if (e.key.toLowerCase() === 'm' && e.shiftKey) { e.preventDefault(); setTimes(); } // O 键开启/关闭功能 if (e.key.toLowerCase() === 'o') { e.preventDefault(); enabled = !enabled; localStorage.setItem(KEY_ENABLED, enabled ? 'true' : 'false'); showInfo(); } }); // 初次加载进来,显示一次浮窗 showInfo(); const video = document.querySelector('video'); if (video) monitor(video); else { new MutationObserver((_, obs) => { const v = document.querySelector('video'); if (v) { monitor(v); obs.disconnect(); } }).observe(document.body, { childList: true, subtree: true }); } })();