// ==UserScript== // @name 广开网络教学平台/广东开放大学【最高16倍】自动刷课 // @namespace http://course.ougd.cn/ // @version 2.4.0 // @description 广东开放大学课程视频自动播放、倍速、自动滚动文档、自动切换下一个学习任务,模拟观看行为 // @author GDOU Assistant // @match *://course.ougd.cn/* // @grant none // @run-at document-idle // ==/UserScript== (function() { 'use strict'; // ========== 防止在iframe中执行 ========== if (window.top !== window) return; // ========== 全局单例锁 - 防止重复执行 ========== if (window.__GDOUScriptInitialized__) return; window.__GDOUScriptInitialized__ = true; // ========== 劫持 addEventListener,阻止 beforeunload 事件注册(防止跳转时弹出确认框)========== (function() { var originalAddEventListener = window.addEventListener; window.addEventListener = function(type, listener, options) { // 拦截 beforeunload 事件的注册 if (type === 'beforeunload') { console.log('[GDOU] 拦截了 beforeunload 事件注册'); return; // 不注册,直接返回 } return originalAddEventListener.call(this, type, listener, options); }; // 同样劫持 document.addEventListener var docOriginalAddEventListener = document.addEventListener; document.addEventListener = function(type, listener, options) { if (type === 'beforeunload') { console.log('[GDOU] 拦截了 document.beforeunload 事件注册'); return; } return docOriginalAddEventListener.call(this, type, listener, options); }; // 立即清除已存在的 beforeunload window.onbeforeunload = null; document.onbeforeunload = null; console.log('[GDOU] 已初始化 beforeunload 拦截器'); })(); // ========== 配置与存储 ========== var STORAGE_KEY = 'gdou_automation_v2'; var defaultConfig = { autoPlay: true, // 视频自动播放(默认开启) videoSpeed: 2.0, // 默认倍速 2.0x rememberSettings: true, // 记住设置 autoScrollDocs: true, // 文档自动滚动 autoNext: true, // 完成后自动切换下一个(默认开启) nextDelay: 2000, // 切换下一个前的延迟 showPanel: true, enableShortcuts: true, autoCompletePages: true, debugMode: false }; function loadConfig() { try { var saved = localStorage.getItem(STORAGE_KEY); if (saved) { var parsed = JSON.parse(saved); var merged = {}; for (var key in defaultConfig) { merged[key] = (parsed && typeof parsed[key] !== 'undefined') ? parsed[key] : defaultConfig[key]; } return merged; } } catch(e) { console.warn('加载配置失败:', e); } return Object.assign({}, defaultConfig); } function saveConfig() { if (!CONFIG.rememberSettings) return; try { localStorage.setItem(STORAGE_KEY, JSON.stringify(CONFIG)); } catch(e) { console.warn('保存配置失败:', e); } } // 重置配置(在控制台输入 gdou_reset() 调用 function resetConfig() { try { localStorage.removeItem(STORAGE_KEY); console.log('[GDOU] 配置已重置为默认值'); } catch(e) { console.warn('重置配置失败:', e.message); } } // 将函数暴露到 window,方便用户调用 window.gdou_reset = resetConfig; var CONFIG = loadConfig(); // ========== 工具函数 ========== function log() { if (!CONFIG.debugMode) return; var args = ['[GDOU助手]']; for (var i = 0; i < arguments.length; i++) args.push(arguments[i]); console.log.apply(console, args); } function getPageType() { var url = location.href; // 调试日志 console.log('[GDOU] getPageType 开始检查, URL:', url); // === 步骤1:先检查是否为登录/仪表盘页面 === if (url.indexOf('login/index.php') !== -1 || url.indexOf('authserver') !== -1) { console.log('[GDOU] 类型: login'); return 'login'; } if (url.indexOf('/my/') !== -1 || url.indexOf('/my/index') !== -1) { console.log('[GDOU] 类型: dashboard'); return 'dashboard'; } if (url.indexOf('course/view.php') !== -1) { console.log('[GDOU] 类型: course'); return 'course'; } // === 步骤2:检查视频页面(严格的 URL 模式匹配)=== // 只有明确的视频模块 URL 才返回 video if (url.indexOf('mod/ougdresource/view.php') !== -1) { console.log('[GDOU] 类型: video (ougdresource)'); return 'video'; } if (url.indexOf('mod/resource/view.php') !== -1) { console.log('[GDOU] 类型: video (resource)'); return 'video'; } if (url.indexOf('mod/vod/') !== -1) { console.log('[GDOU] 类型: video (vod)'); return 'video'; } if (url.indexOf('mod/video/') !== -1) { console.log('[GDOU] 类型: video (video)'); return 'video'; } if (url.indexOf('mod/163vod') !== -1) { console.log('[GDOU] 类型: video (163vod)'); return 'video'; } // mooc 模块页面通常内嵌网易云课堂视频播放器,按视频页面处理 if (url.indexOf('mod/mooc/view.php') !== -1) { console.log('[GDOU] 类型: video (mooc)'); return 'video'; } // === 步骤3:检查文档/讨论/测验等页面 === if (url.indexOf('mod/page/view.php') !== -1) { console.log('[GDOU] 类型: page'); return 'page'; } if (url.indexOf('mod/forum/view.php') !== -1) { console.log('[GDOU] 类型: forum'); return 'forum'; } if (url.indexOf('mod/forum/discuss.php') !== -1) { console.log('[GDOU] 类型: discuss'); return 'discuss'; } if (url.indexOf('mod/quiz/view.php') !== -1) { console.log('[GDOU] 类型: quiz'); return 'quiz'; } // === 步骤4:通用 Moodle 模块页面 === if (url.indexOf('mod/assign/view.php') !== -1) { console.log('[GDOU] 类型: assign'); return 'assign'; } if (url.indexOf('mod/label/view.php') !== -1) { console.log('[GDOU] 类型: label'); return 'label'; } if (url.indexOf('mod/book/view.php') !== -1) { console.log('[GDOU] 类型: book'); return 'book'; } if (url.indexOf('mod/folder/view.php') !== -1) { console.log('[GDOU] 类型: folder'); return 'folder'; } if (url.indexOf('mod/url/view.php') !== -1) { console.log('[GDOU] 类型: url'); return 'url'; } if (url.indexOf('mod/lesson/view.php') !== -1) { console.log('[GDOU] 类型: lesson'); return 'lesson'; } if (url.indexOf('mod/scorm/view.php') !== -1) { console.log('[GDOU] 类型: scorm'); return 'scorm'; } // === 步骤5:检查是否含有 mod/xxx/view.php 格式 === var modMatch = url.match(/\/mod\/([a-zA-Z0-9_]+)\/view\.php/i); if (modMatch) { var modName = modMatch[1].toLowerCase(); console.log('[GDOU] 检测到模块:', modName, '- 作为非视频模块处理'); return 'module'; // 所有未列出的 mod 模块都按非视频处理 } // === 步骤6:最后通过元素检查来判断是否为视频页面(仅作为兜底,且严格检查)=== console.log('[GDOU] URL未匹配任何模块,开始检查页面元素...'); // 只有发现真正的