// ==UserScript== // @name 湖南开放大学自动刷课(解决自动播放问题版) // @namespace http://tampermonkey.net/ // @version 2.0 // @description 解决自动播放被阻止问题,确保视频持续播放 // @author 唐跃翔 // @match *.hnsydwpx.cn/* // @grant GM_addStyle // @grant GM_log // @grant GM_notification // @run-at document-idle // @license MIT // @downloadURL none // ==/UserScript== (function() { 'use strict'; // 配置参数 const config = { checkInterval: 5000, // 状态检查间隔(ms) interactionWait: 3000, // 等待用户交互时间(ms) maxRetry: 300, // 最大重试次数 debugMode: true // 调试模式 }; // 添加UI指示器 GM_addStyle(` .script-indicator { position: fixed; top: 20px; right: 20px; background: #4CAF50; color: white; padding: 8px 15px; border-radius: 4px; box-shadow: 0 2px 5px rgba(0,0,0,0.2); z-index: 9999; font-size: 30px; } .script-indicator.error { background: #F44336; } `); const indicator = document.createElement('div'); indicator.className = 'script-indicator'; indicator.textContent = '阿唐的刷课脚本已经启动啦'; document.body.appendChild(indicator); // 解决自动播放问题的视频控制器 class VideoController { constructor() { this.player = null; this.retryCount = 0; this.isWaitingInteraction = false; this.init(); } async init() { try { this.player = await this.waitForElement('#coursePlayer video'); this.addFakeInteractionLayer(); this.startMonitoring(); this.notify('视频控制器已启动'); } catch (error) { this.notify(`初始化失败: ${error.message}`, 'error'); indicator.classList.add('error'); indicator.textContent = '脚本初始化失败'; } } // 添加伪交互层解决自动播放限制 addFakeInteractionLayer() { GM_addStyle(` .interaction-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: transparent; z-index: 9998; cursor: pointer; } .interaction-notice { position: fixed; bottom: 80px; right: 20px; background: rgba(0,0,0,0.7); color: white; padding: 10px 15px; border-radius: 4px; z-index: 9999; max-width: 300px; font-size: 14px; text-align: center; box-shadow: 0 2px 10px rgba(0,0,0,0.5); } `); // 创建覆盖层 const overlay = document.createElement('div'); overlay.className = 'interaction-overlay'; overlay.onclick = () => this.handleUserInteraction(); document.body.appendChild(overlay); // 添加提示 const notice = document.createElement('div'); notice.className = 'interaction-notice'; notice.innerHTML = '点击页面任意位置激活自动播放功能
3秒后自动尝试播放'; document.body.appendChild(notice); this.isWaitingInteraction = true; setTimeout(() => { if (this.isWaitingInteraction) { this.handleUserInteraction(); notice.innerHTML = '已自动激活播放功能'; setTimeout(() => notice.remove(), 2000); } }, config.interactionWait); } // 处理用户交互 handleUserInteraction() { if (!this.isWaitingInteraction) return; this.isWaitingInteraction = false; document.querySelector('.interaction-overlay')?.remove(); document.querySelector('.interaction-notice')?.remove(); // 首次播放需要用户触发 this.playVideo().then(() => { this.notify('用户交互后自动播放已启动'); }).catch(error => { this.notify(`交互后播放失败: ${error}`, 'error'); }); } // 开始监控 startMonitoring() { this.monitorInterval = setInterval(() => { if (!this.isWaitingInteraction && this.player.paused && !this.player.ended) { this.playVideo(); } }, config.checkInterval); // 监听视频事件 this.player.addEventListener('pause', () => { if (!this.isWaitingInteraction) { this.notify('检测到视频暂停,尝试恢复'); this.playVideo(); } }); this.player.addEventListener('ended', () => { this.notify('当前视频播放完毕'); this.nextChapter(); }); } // 播放视频(处理自动播放限制) async playVideo() { if (this.retryCount >= config.maxRetry) { this.notify('达到最大重试次数,请手动点击播放', 'error'); GM_notification({ title: '自动播放被阻止', text: '请手动点击播放按钮', timeout: 5000 }); indicator.classList.add('error'); indicator.textContent = '自动播放被阻止'; return; } try { const playPromise = this.player.play(); if (playPromise !== undefined) { await playPromise; this.retryCount = 0; this.notify('不用慌,视频已经播放成功啦!哈哈ヾ(≧▽≦*)o'); indicator.classList.remove('error'); indicator.textContent = '阿唐的自动刷课脚本运行中'; } } catch (error) { this.retryCount++; this.notify(`播放失败 (${this.retryCount}/${config.maxRetry}): ${error}`, 'error'); // 尝试通过点击按钮播放 const playBtn = await this.waitForElement('.xgplayer-play', document, 1000).catch(() => null); if (playBtn) { playBtn.click(); this.notify('已尝试点击播放按钮'); } // 直接尝试静音播放 if (this.retryCount >= 1) { this.player.muted = true; this.player.play().catch(e => this.notify(`静音播放也失败: ${e}`, 'error')); } } } // 切换到下一章节 nextChapter() { const items = document.querySelectorAll('li[data-v-469a21ef]'); for (let item of items) { const progress = item.querySelector('.progress')?.textContent.trim(); if (progress != '100%'&&progress != '99%'&&progress != '98%'&&progress != '97%'&&progress != '96%'&&progress != '95%'&&progress != '94%') { item.click(); this.notify(`切换到未完成章节: ${item.querySelector('.name').textContent}`); // 点击后等待视频加载并开始播放 setTimeout(() => this.playVideo(), 2000); return; } } this.notify('所有章节已完成,返回课程中心'); window.location.href = 'https://www.hnsydwpx.cn/mineCourse'; } // 等待元素出现 waitForElement(selector, parent = document, timeout = 10000) { return new Promise((resolve, reject) => { const startTime = Date.now(); const check = () => { const el = parent.querySelector(selector); if (el) { resolve(el); } else if (Date.now() - startTime < timeout) { setTimeout(check, 500); } else { reject(new Error(`元素未找到: ${selector}`)); } }; check(); }); } // 弹窗通知 notify(message, type = 'info') { if (config.debugMode) { GM_notification({ title: `[唐跃翔的视频控制]`, text: message, timeout: 5000 }); } } } // 页面初始化 function check2425(items,index) { items[index].click(); setTimeout(() => { //先检查元素是否存在 const button = document.querySelector('.el-tab-pane .el-row .el-button'); if (button) { if(index)console.log('2024年章节未完成,程序优先学习2024年章节!'); try { button.click(); } catch (clickError) { console.log('点击操作失败,执行备用方案:', clickError); } } else { console.log('2024已经完成,学习2025年课程!'); if(!index)console.log('全部完成啦!'); else check2425(items,0); } new VideoController(); },2000); } function init() { // 只在对视频页面启用 if (location.pathname.includes('/videoPlayback') || location.pathname.includes('/getcourseDetails')) { new VideoController(); } if(location.pathname.includes('/mineCourse')){ setTimeout(() => { console.log('go to my course') const items = document.querySelectorAll('.years div[data-v-fa6b87b5]'); check2425(items,1); }, 2000); } } // 启动脚本 if (document.readyState === 'complete') { init(); } else { window.addEventListener('load', init); } })();