// ==UserScript== // @name 视频播放优化(支持脚本猫)- 修复下一集跳转+小窗口拖拽 // @namespace https://github.com/ // @version 3.0.0 // @description 修复网站视频无法跳转下一集问题,优化视频小窗口拖拽移动体验,支持自动跳转+手动跳转,小窗口边界限制 // @author 自定义 // @match *://*/* // 匹配所有网站,可根据需要修改为具体网站域名,如 *://xxx.com/* // @grant none // @license MIT // @run-at document-end // DOM加载完成后运行,适配脚本猫环境 // ==/UserScript== (function() { 'use strict'; // 等待DOM完全加载(双重保障,适配不同网站加载情况) function waitDOMLoaded(callback) { if (document.readyState === 'complete' || document.readyState === 'interactive') { callback(); } else { document.addEventListener('DOMContentLoaded', callback); } } waitDOMLoaded(function() { /************************** 一、视频下一集跳转核心功能 **************************/ // 1. 核心配置参数(可自定义修改) const videoConfig = { videoElement: document.getElementById('mainVideo'), videoSourceElement: document.getElementById('videoSource'), nextVideoUrl: document.getElementById('nextVideoUrl')?.innerText || '', jumpNextBtn: document.getElementById('jumpNextBtn'), autoJump: true, // 是否开启播放结束自动跳转 jumpDelay: 2000, // 自动跳转延迟(毫秒) isJumpAble: true // 防重复跳转开关 }; // 校验核心元素,避免报错 if (!videoConfig.videoElement || !videoConfig.videoSourceElement) { console.warn('[视频优化脚本] 核心视频元素未找到,请确认DOM结构中存在mainVideo和videoSource'); return; } // 2. 自动跳转:监听视频播放结束事件 videoConfig.videoElement.addEventListener('ended', function() { if (!videoConfig.autoJump || !videoConfig.nextVideoUrl || !videoConfig.isJumpAble) { return; } // 延迟跳转,提升用户体验 setTimeout(() => { jumpToNextVideo(); }, videoConfig.jumpDelay); }); // 3. 手动跳转:绑定按钮点击事件 if (videoConfig.jumpNextBtn) { videoConfig.jumpNextBtn.addEventListener('click', function() { if (!videoConfig.nextVideoUrl || !videoConfig.isJumpAble) { alert('暂无下一集视频'); return; } jumpToNextVideo(); }); } // 4. 核心跳转方法 function jumpToNextVideo() { videoConfig.isJumpAble = false; // 禁用跳转,防止重复触发 // 更新视频资源 videoConfig.videoSourceElement.src = videoConfig.nextVideoUrl; // 加载并播放新视频 videoConfig.videoElement.load(); videoConfig.videoElement.play() .then(() => { updateNextVideoInfo(); // 动态更新下一集信息 videoConfig.isJumpAble = true; // 恢复跳转开关 }) .catch((err) => { console.error('[视频优化脚本] 下一集播放失败:', err); alert('下一集视频加载失败,请稍后重试'); videoConfig.isJumpAble = true; }); } // 5. 动态更新下一集信息(可替换为真实接口) function updateNextVideoInfo() { // 真实场景中替换为 fetch/axios 请求 // 示例: // fetch('/api/get-next-video', { // method: 'POST', // headers: { 'Content-Type': 'application/json' }, // body: JSON.stringify({ currentId: 'xxx' }) // }).then(res => res.json()).then(data => { // if (data.success) { // document.getElementById('nextVideoUrl').innerText = data.nextUrl; // videoConfig.nextVideoUrl = data.nextUrl; // } // }); // 模拟更新 const randomNextUrl = `next-video-${Math.floor(Math.random() * 10)}.mp4`; if (document.getElementById('nextVideoUrl')) { document.getElementById('nextVideoUrl').innerText = randomNextUrl; } videoConfig.nextVideoUrl = randomNextUrl; } // 6. 视频加载失败监听 videoConfig.videoElement.addEventListener('error', function(err) { console.error('[视频优化脚本] 视频加载失败:', err); alert('当前视频无法播放,请检查资源或网络'); videoConfig.isJumpAble = true; }); /************************** 二、小窗口拖拽移动优化 **************************/ // 1. 小窗口配置参数(可自定义修改) const floatingConfig = { floatingWrapper: document.getElementById('floatingVideoWrapper'), floatingVideo: document.getElementById('floatingVideo'), floatingSource: document.getElementById('floatingVideoSource'), dragHandle: document.getElementById('dragHandle'), closeBtn: document.getElementById('closeFloatingBtn'), toggleBtn: document.getElementById('toggleFloatingBtn'), isDragging: false, offsetX: 0, offsetY: 0, defaultPosition: { left: '20px', bottom: '20px' } // 默认位置 }; // 校验小窗口元素 if (!floatingConfig.floatingWrapper) { console.warn('[视频优化脚本] 小窗口容器未找到,跳过小窗口功能'); return; } // 2. 初始化小窗口位置 function initFloatingPosition() { floatingConfig.floatingWrapper.style.position = 'fixed'; floatingConfig.floatingWrapper.style.zIndex = '99999'; // 脚本猫环境下提高层级,防止被遮挡 floatingConfig.floatingWrapper.style.display = 'none'; floatingConfig.floatingWrapper.style.transition = 'all 0.2s ease'; floatingConfig.floatingWrapper.style.left = floatingConfig.defaultPosition.left; floatingConfig.floatingWrapper.style.bottom = floatingConfig.defaultPosition.bottom; } initFloatingPosition(); // 3. 拖拽核心逻辑(支持手柄/整个窗口拖拽) const dragTarget = floatingConfig.dragHandle || floatingConfig.floatingWrapper; dragTarget.addEventListener('mousedown', startDrag); document.addEventListener('mousemove', drag); document.addEventListener('mouseup', endDrag); // 开始拖拽 function startDrag(e) { floatingConfig.isDragging = true; const rect = floatingConfig.floatingWrapper.getBoundingClientRect(); // 计算鼠标与窗口的偏移量,实现精准拖拽 floatingConfig.offsetX = e.clientX - rect.left; floatingConfig.offsetY = e.clientY - rect.top; // 视觉反馈 floatingConfig.floatingWrapper.style.cursor = 'move'; floatingConfig.floatingWrapper.style.opacity = '0.95'; } // 拖拽中(边界限制,防止移出视口) function drag(e) { if (!floatingConfig.isDragging) return; let newLeft = e.clientX - floatingConfig.offsetX; let newTop = e.clientY - floatingConfig.offsetY; // 视口尺寸 const viewportW = window.innerWidth; const viewportH = window.innerHeight; // 小窗口尺寸 const wrapperW = floatingConfig.floatingWrapper.offsetWidth; const wrapperH = floatingConfig.floatingWrapper.offsetHeight; // 边界限制 newLeft = Math.max(0, Math.min(newLeft, viewportW - wrapperW)); newTop = Math.max(0, Math.min(newTop, viewportH - wrapperH)); // 更新位置 floatingConfig.floatingWrapper.style.left = `${newLeft}px`; floatingConfig.floatingWrapper.style.top = `${newTop}px`; floatingConfig.floatingWrapper.style.bottom = 'auto'; } // 结束拖拽 function endDrag() { floatingConfig.isDragging = false; floatingConfig.floatingWrapper.style.cursor = 'default'; floatingConfig.floatingWrapper.style.opacity = '1'; } // 4. 小窗口与主窗口切换 if (floatingConfig.toggleBtn) { floatingConfig.toggleBtn.addEventListener('click', function() { const isShow = floatingConfig.floatingWrapper.style.display === 'block'; const mainVideo = videoConfig.videoElement; const mainSource = videoConfig.videoSourceElement; if (isShow) { // 隐藏小窗口,显示主窗口 floatingConfig.floatingWrapper.style.display = 'none'; mainVideo.style.display = 'block'; // 同步播放进度 mainVideo.currentTime = floatingConfig.floatingVideo.currentTime; floatingConfig.floatingVideo.pause(); mainVideo.play().catch(err => console.warn('[视频优化脚本] 主视频播放失败:', err)); } else { // 显示小窗口,隐藏主窗口 floatingConfig.floatingWrapper.style.display = 'block'; mainVideo.style.display = 'none'; // 同步资源和进度 floatingConfig.floatingSource.src = mainSource.src; floatingConfig.floatingVideo.load(); floatingConfig.floatingVideo.currentTime = mainVideo.currentTime; mainVideo.pause(); floatingConfig.floatingVideo.play().catch(err => console.warn('[视频优化脚本] 小窗口视频播放失败:', err)); } }); } // 5. 关闭小窗口 if (floatingConfig.closeBtn) { floatingConfig.closeBtn.addEventListener('click', function() { floatingConfig.floatingWrapper.style.display = 'none'; const mainVideo = videoConfig.videoElement; mainVideo.style.display = 'block'; // 同步进度 mainVideo.currentTime = floatingConfig.floatingVideo.currentTime; floatingConfig.floatingVideo.pause(); mainVideo.play().catch(err => console.warn('[视频优化脚本] 主视频播放失败:', err)); // 恢复默认位置 initFloatingPosition(); }); } console.log('[视频优化脚本] 初始化完成(支持脚本猫)'); }); })();