稳定可靠的AB点循环工具,适配最新B站页面结构
当前为
// ==UserScript==
// @name B站循环助手-自适应版
// @namespace bilibili-replayer
// @version 1.22
// @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 createToolbar = () => {
let retryCount = 0;
const maxRetries = 30;
const tryCreate = () => {
const video = document.querySelector('#bilibili-player video');
const controlBar = document.querySelector('.bpx-player-control-bottom');
if (!video || !controlBar) {
retryCount++;
if (retryCount < maxRetries) {
setTimeout(tryCreate, 500);
}
return;
}
const controller = new VideoController(video);
// 修改控制栏样式以支持flex布局
controlBar.style.display = 'flex';
controlBar.style.alignItems = 'center';
controlBar.style.position = 'relative';
// 获取或创建右侧控制区
let rightControls = controlBar.querySelector('.bpx-player-control-right');
if (!rightControls) {
rightControls = document.createElement('div');
rightControls.className = 'bpx-player-control-right';
controlBar.appendChild(rightControls);
}
// 创建工具栏容器
const toolbarbox = document.createElement('div');
toolbarbox.className = 'ab-loop-toolbar';
// 将工具栏插入到右侧控制区的开头
if (rightControls.firstChild) {
rightControls.insertBefore(toolbarbox, rightControls.firstChild);
} else {
rightControls.appendChild(toolbarbox);
}
// 创建自定义样式
const style = document.createElement('style');
style.textContent = `
.ab-loop-toolbar {
display: flex;
align-items: center;
height: 100%;
margin-right: 10px;
}
.bpx-player-control-right {
display: flex;
align-items: center;
}
.tool-item {
padding: 0 6px;
margin: 0 1px;
height: 22px;
line-height: 22px;
color: #ffffff;
cursor: pointer;
opacity: 0.85;
transition: all 0.2s ease;
border-radius: 2px;
user-select: none;
}
.tool-button:hover {
opacity: 1;
background-color: rgba(255, 255, 255, 0.1);
}
.active-button {
background-color: #00a1d6 !important;
color: white !important;
opacity: 1 !important;
}
/* 全屏模式下的样式调整 */
.bpx-player-container[data-screen="full"] .ab-loop-toolbar {
height: 32px;
}
.bpx-player-container[data-screen="full"] .tool-item {
height: 24px;
line-height: 24px;
font-size: 14px;
}
`;
document.head.appendChild(style);
// 创建按钮
const pointA = Utils.createButton('起点', 'tool-item tool-button', toolbarbox);
const toA = Utils.createButton('跳A', 'tool-item tool-button', toolbarbox);
Utils.createButton('|', 'tool-item tool-text', toolbarbox);
const pointB = Utils.createButton('终点', 'tool-item tool-button', toolbarbox);
const toB = Utils.createButton('跳B', 'tool-item tool-button', toolbarbox);
Utils.createButton('|', 'tool-item tool-text', toolbarbox);
const Start = Utils.createButton('▶循环', 'tool-item tool-button', toolbarbox);
controller.pointButtons = [pointA, pointB];
// 事件监听
pointA.addEventListener('click', () => {
controller.setPoint(0, video.currentTime);
});
pointB.addEventListener('click', () => {
controller.setPoint(1, video.currentTime);
});
Start.addEventListener('click', () => controller.startLoop(Start));
toA.addEventListener('click', () => { video.currentTime = controller.points[0]; });
toB.addEventListener('click', () => { video.currentTime = controller.points[1]; });
// 全屏切换监听
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'data-screen') {
// 可以在这里添加全屏切换时的额外处理逻辑
}
});
});
const playerContainer = document.querySelector('.bpx-player-container');
if (playerContainer) {
observer.observe(playerContainer, {
attributes: true,
attributeFilter: ['data-screen']
});
}
};
tryCreate();
};
// 检查页面加载状态
if (document.readyState === 'complete') {
createToolbar();
} else {
window.addEventListener('load', createToolbar);
}
})();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址