您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
稳定可靠的AB点循环工具,适配最新B站页面结构
当前为
// ==UserScript== // @name B站循环助手-稳定版 // @namespace bilibili-replayer // @version 1.3 // @description 稳定可靠的AB点循环工具,适配最新B站页面结构 // @author dms // @match https://www.bilibili.com/video/BV* // @match https://www.bilibili.com/bangumi/play/ep* // @match https://www.bilibili.com/medialist/play/* // @icon https://www.google.com/s2/favicons?sz=64&domain=bilibili.com // @grant GM_notification // @grant GM_setValue // @grant GM_getValue // ==/UserScript== (function() { 'use strict'; const isNormalVideo = /^(https?:\/\/(www\.)bilibili\.com\/video\/(?:BV|AV)\w+).*/i.test(window.location.href); const copyText = text => { const textArea = document.createElement('textarea'); textArea.setAttribute('readonly', 'readonly'); textArea.value = text; document.body.appendChild(textArea); textArea.select(); document.execCommand('copy'); document.body.removeChild(textArea); }; const createButton = (text, className, parent) => { const button = document.createElement('div'); className.split(' ').forEach(c => button.classList.add(c)); button.innerText = text; parent.appendChild(button); return button; }; const createToolbar = () => { const toolbarbox = document.createElement('div'); toolbarbox.style = 'width: 100%; height: 1.5rem;'; const container = document.querySelector('#playerWrap') || document.querySelector('#player_module'); container.appendChild(toolbarbox); if(document.querySelector('#player_module')) { document.querySelector('#player_module').style.marginBottom = '2rem'; } const toolbarShadow = toolbarbox.attachShadow({mode: 'closed'}); const toolbarStyle = document.createElement('style'); toolbarStyle.innerHTML = ` #replayer-toolbar { width: 100%; height: 1.5rem; font-size: 0.8rem; line-height: 1.6rem; margin: .2rem 0; } #replayer-toolbar::after { content: " "; display: block; clear: both; } .tool-item { float: left; padding: 0 0.3rem; border-radius: .2rem; } .tool-button { border: 1px solid rgba(0, 0, 0, .1); cursor: pointer; } .active-button { background-color: #00aeec; color: white; } .hide { display: none; } `; const getLinkClass = isNormalVideo ? '' : ' hide'; toolbarShadow.appendChild(toolbarStyle); const toolbar = document.createElement('div'); toolbar.id = 'replayer-toolbar'; toolbarShadow.appendChild(toolbar); createButton('起点:', 'tool-item tool-text', toolbar); const pointA = createButton('起点A', 'tool-item tool-button', toolbar); const toA = createButton('跳到这里', 'tool-item tool-button', toolbar); const linkA = createButton('复制链接', 'tool-item tool-button' + getLinkClass, toolbar); createButton('|', 'tool-item tool-text', toolbar); createButton('终点:', 'tool-item tool-text', toolbar); const pointB = createButton('终点B', 'tool-item tool-button', toolbar); const toB = createButton('跳到这里', 'tool-item tool-button', toolbar); const linkB = createButton('复制链接', 'tool-item tool-button' + getLinkClass, toolbar); createButton('|', 'tool-item tool-text', toolbar); const Start = createButton('开始循环', 'tool-item tool-button', toolbar); createButton('|', 'tool-item tool-text' + getLinkClass, toolbar); createButton('当前:', 'tool-item tool-text' + getLinkClass, toolbar); const linkNow = createButton('复制链接', 'tool-item tool-button' + getLinkClass, toolbar); const video = document.querySelector('#bilibili-player video'); const points = [0, video.duration-1]; const pointButtons = [pointA, pointB]; const setPoint = (i, val) => { if(val && val.trim()) { if(!/^(\d+h)?(\d+m)?\d+(\.\d+)?$/i.test(val)) { alert('格式有误,请注意查看示例格式'); return; } if(typeof(val) === 'string') { const hms = val.split(/h|m/g); const h = /\d+h/.test(val) ? +hms[0] : 0; const m = /\d+m/.test(val) ? +hms[hms.length-2] : 0; const s = +hms[hms.length-1]; points[i] = h*3600 + m*60 + s; } else { points[i] = val; } pointButtons[i].classList.add('active-button'); GM_setValue('Point_'+i, points[i]); return; } points[i] = i ? video.duration-1 : 0; pointButtons[i].classList.remove('active-button'); GM_setValue('Point_'+i, null); }; const savedPointA = GM_getValue('Point_0'); const savedPointB = GM_getValue('Point_1'); if(savedPointA !== null) { pointA.classList.add('active-button'); points[0] = savedPointA; } if(savedPointB !== null) { pointB.classList.add('active-button'); points[1] = savedPointB; } pointA.addEventListener('click', () => { const pointAInput = prompt('请输入一个时间(单位:秒),默认值是当前时间点。取消则清除此时间点,恢复为默认值:视频开头。\n输入值可以包含分钟,例如:三分十二秒写作 3m12\n输入值可以包含小时,例如:一小时三分十二秒写作 1h3m12', video.currentTime); setPoint(0, pointAInput); }); pointB.addEventListener('click', () => { const pointBInput = prompt('请输入一个时间(单位:秒),默认值是当前时间点。取消则清除此时间点,恢复为默认值:视频结尾(前一秒)。\n输入值可以包含分钟,例如:三分十二秒写作 3m12\n输入值可以包含小时,例如:一小时三分十二秒写作 1h3m12', video.currentTime); setPoint(1, pointBInput); }); let mainTimer = 0; Start.addEventListener('click', () => { if(mainTimer) { clearInterval(mainTimer); mainTimer = 0; Start.classList.remove('active-button'); return; } Start.classList.add('active-button'); mainTimer = setInterval(() => { const A = points[0] <= points[1] ? points[0] : points[1]; const B = points[0] > points[1] ? points[0] : points[1]; if(video.currentTime >= B) { video.currentTime = A; } }, 200); }); toA.addEventListener('click', () => { video.currentTime = points[0]; }); toB.addEventListener('click', () => { video.currentTime = points[1]; }); const getLink = t => { const link = window.location.href.replace(/^(https?:\/\/(www\.)bilibili\.com\/video\/(?:BV|AV)\w+).*/i, '$1') + '?t=' + t; copyText(link); alert('带时间标记的链接已复制到剪切板。'); }; linkA.addEventListener('click', () => { getLink(points[0]); }); linkB.addEventListener('click', () => { getLink(points[1]); }); linkNow.addEventListener('click', () => { getLink(video.currentTime); }); }; window.addEventListener('load', () => { const waitTimer = setInterval(() => { if(document.querySelector('#bilibili-player video')) { clearInterval(waitTimer); createToolbar(); } }, 1000); }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址