// ==UserScript== // @name 中华医学远程继续教育课程视频自动播放与下一集跳转 // @namespace http://tampermonkey.net/ // @version 1.0 // @description 打开课程视频后自动播放;若被浏览器阻止,点击页面任意处即开始;视频结束后自动跳转下一集 // @match https://cme.yiigle.com/teaching/course?* // @grant none // @run-at document-end // @license GPL-3.0 // ==/UserScript== (function() { 'use strict'; let video = null; let checkInterval = null; function log(msg) { console.log('[AutoNext] ' + msg); } function getVideoElement() { return document.querySelector('video'); } // 查找下一集的可点击元素(适配多种常见结构) function getNextVideoItem() { // 尝试多种可能的容器选择器 const selectors = ['.item', '.chapter', '.lesson', '.video-item', 'li']; let items = []; for (const sel of selectors) { const found = document.querySelectorAll(sel); if (found.length > 0) { items = found; break; } } if (items.length === 0) { log('未找到课程列表项'); return null; } for (let i = 0; i < items.length; i++) { const el = items[i]; // 判断当前项是否激活(active 类或其子元素存在 active) const isActive = el.classList.contains('active') || el.querySelector('.active'); if (isActive) { const next = items[i + 1]; if (next) { // 优先返回可点击的子元素(a 标签或含有 .title/.name 的元素) const clickable = next.querySelector('a, .title, .name'); return clickable || next; } else { log('已是最后一项'); return null; } } } log('未找到当前播放项'); return null; } function goToNext() { const next = getNextVideoItem(); if (next) { log('跳转下一集'); next.click(); } else { log('没有下一集'); } } function bindEndedEvent(videoElem) { if (!videoElem) return; if (videoElem._autoNextBound) return; videoElem._autoNextBound = true; videoElem.addEventListener('ended', function() { log('视频播放结束'); goToNext(); }); log('已绑定 ended 事件'); } function playVideo(videoElem) { if (!videoElem) return Promise.reject('No video element'); if (!videoElem.paused) return Promise.resolve(); return videoElem.play(); } // 显示一个浮动提示按钮(也可点击页面任意处触发) function showPlayHint() { if (document.getElementById('auto-play-hint')) return; const hint = document.createElement('div'); hint.id = 'auto-play-hint'; hint.style.cssText = ` position: fixed; bottom: 80px; right: 20px; background: #409EFF; color: #fff; padding: 12px 20px; border-radius: 8px; font-size: 16px; cursor: pointer; z-index: 9999; box-shadow: 0 2px 12px rgba(0,0,0,0.3); font-family: sans-serif; `; hint.textContent = '▶ 点击开始自动播放'; hint.addEventListener('click', function(e) { e.stopPropagation(); const v = getVideoElement(); if (v) { playVideo(v).then(() => { log('用户点击按钮,播放成功'); hint.style.display = 'none'; }).catch(err => log('播放失败:' + err)); } }); document.body.appendChild(hint); // 同时监听任意点击(可移除按钮后播放) const oneClick = function() { const v = getVideoElement(); if (v && v.paused) { playVideo(v).then(() => { log('用户点击任意处,播放成功'); if (hint.parentNode) hint.style.display = 'none'; }).catch(err => {}); } document.removeEventListener('click', oneClick); document.removeEventListener('touchstart', oneClick); }; document.addEventListener('click', oneClick); document.addEventListener('touchstart', oneClick); log('已显示播放提示,等待用户交互'); } function initAutoPlay() { const v = getVideoElement(); if (!v) { log('视频元素未找到,继续等待...'); return false; } video = v; bindEndedEvent(v); if (!v.paused) { log('视频已在播放'); return true; } playVideo(v).then(() => { log('自动播放成功'); }).catch(err => { if (err.name === 'NotAllowedError') { log('自动播放被浏览器阻止,等待用户交互'); showPlayHint(); } else { log('播放异常:' + err.message); } }); return true; } // 循环检测视频元素 function start() { if (checkInterval) return; let attempts = 0; checkInterval = setInterval(function() { attempts++; const v = getVideoElement(); if (v) { clearInterval(checkInterval); checkInterval = null; initAutoPlay(); } else if (attempts > 30) { clearInterval(checkInterval); checkInterval = null; log('超时未找到视频元素'); } }, 1000); } // 页面加载后启动 if (document.readyState === 'complete') { setTimeout(start, 1000); } else { window.addEventListener('load', start); } })();