// ==UserScript== // @name 软通学习平台-视频播完自动下一集 // @namespace http://tampermonkey.net/ // @version 2026.08.05.1 // @description 在软通教育学习平台(eco.issedu365.com)课程详情页,视频播放结束后自动点击"下一个"播放下一课;支持后台保持播放、画中画模式(兼容Edge原生PiP按钮、跨集记忆状态)。 // @author SmallRob // @match https://eco.issedu365.com/application/appcoursedetail/* // @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NCIgaGVpZ2h0PSI2NCIgdmlld0JveD0iMCAwIDY0IDY0Ij4KICA8ZGVmcz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iYmciIHgxPSIwJSIgeTE9IjAlIiB4Mj0iMCUiIHkyPSIxMDAlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzNCODJGNiIvPgogICAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMxRTQwQUYiLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8ZmlsdGVyIGlkPSJzaGFkb3ciIHg9Ii0yMCUiIHk9Ii0yMCUiIHdpZHRoPSIxNDAlIiBoZWlnaHQ9IjE0MCUiPgogICAgICA8ZmVEcm9wU2hhZG93IGR4PSIwIiBkeT0iMSIgc3RkRGV2aWF0aW9uPSIxIiBmbG9vZC1jb2xvcj0iIzAwMCIgZmxvb2Qtb3BhY2l0eT0iMC4zIi8+CiAgICA8L2ZpbHRlcj4KICA8L2RlZnM+CiAgPHJlY3Qgd2lkdGg9IjY0IiBoZWlnaHQ9IjY0IiByeD0iMTQiIGZpbGw9InVybCgjYmcpIi8+CiAgPGNpcmNsZSBjeD0iMzIiIGN5PSIxOCIgcj0iNS41IiBmaWxsPSIjRUY0NDQ0IiBmaWx0ZXI9InVybCgjc2hhZG93KSIvPgogIDxyZWN0IHg9IjI3LjUiIHk9IjI3IiB3aWR0aD0iOSIgaGVpZ2h0PSIyNiIgcng9IjQuNSIgZmlsbD0iI0VGNDQ0NCIgZmlsdGVyPSJ1cmwoI3NoYWRvdykiLz4KPC9zdmc+ // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; const CONFIG = { cooldownMs: 8000, // 触发下一集后的冷却时间,防止重复点击 nextDelayAfterEnded: 2000, // 视频 ended 后延迟多久触发下一集 keepPlayingInBackground: true,// 页面后台时保持视频播放 keepAliveInterval: 3000, // 后台保持播放检查间隔 enablePiP: true, // 是否显示画中画按钮 pipReenterDelay: 2000, // 切换集数后重新进入 PiP 的延迟 pipStorageKey: 'softone-pip-wanted', // PiP 状态持久化 key debug: true // 是否打印调试日志 }; const log = (...args) => { if (CONFIG.debug) console.log('[软通自动下一集]', ...args); }; const state = { lastNextAt: 0, playerEndedBound: false, // 是否已绑定播放器 ended 事件 autoPlayKeys: new Set(), // 已尝试自动播放的视频源,避免重复 keepAliveTimer: null, isBackground: false, pipWanted: false, // 用户是否想用画中画(持久化到 localStorage) pipActive: false, // 当前是否处于画中画 pipButton: null, // 画中画按钮元素 pipBoundVideo: null, // 已绑定 PiP 事件的 video 元素 pipRequesting: false, // PiP 请求防重入标记(避免同时多个 requestPictureInPicture) pipSwitchingEpisode: false // 是否正在切换集数(区分"切集退出"和"用户手动退出") }; // ==================== 工具 ==================== function safeClick(element) { if (!element) return false; try { element.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window })); return true; } catch (e) { log('点击失败:', e); return false; } } function canTriggerNext() { const now = Date.now(); if (now - state.lastNextAt < CONFIG.cooldownMs) { log('冷却期内,忽略本次触发'); return false; } state.lastNextAt = now; return true; } // ==================== 查找元素 ==================== function getCurrentVideo() { // 页面使用 videojs + HWPlayer,视频元素 ID 为 streamVideoContent // videojs 会在 内部创建