// ==UserScript== // @name 适用平台:弘成教育,学起Plus,重庆理工 // @namespace http://scriptcat.net/ // @version 0.6 // @description 视频:自动静音+2倍速+自动播放+结束切节;大纲:策略模式自动适配不同目录结构 // @match *://*.chinaedu.net/* // @match *://*.sccchina.net/* // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; /* ============================================================ 视频页逻辑(iframe 内部) ============================================================ */ if (location.href.includes('video.html')) { console.log('[学起Plus] 视频页脚本启动'); const observer = new MutationObserver((mutations, obs) => { const v = document.querySelector('video'); if (v) { console.log('[学起Plus] 检测到video元素,设置属性'); setupVideo(v); obs.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); const existingVideo = document.querySelector('video'); if (existingVideo) { setupVideo(existingVideo); observer.disconnect(); } function setupVideo(v) { v.muted = true; v.autoplay = true; v.playbackRate = 2; v.play().then(() => { console.log('[学起Plus] 视频开始播放'); }).catch(() => { console.log('[学起Plus] 自动播放被阻止,等待用户首次点击'); document.addEventListener('click', () => v.play(), { once: true }); }); v.addEventListener('ended', () => { console.log('[学起Plus] 视频结束,发送 studyNext 消息'); (window.parent || window).postMessage('studyNext', '*'); setTimeout(() => { const newV = document.querySelector('video'); if (newV) newV.play().catch(() => {}); }, 3000); }); } return; // 视频页不需要后续大纲逻辑 } /* ============================================================ 大纲页逻辑(主窗口) ============================================================ */ console.log('[学起Plus] 大纲页脚本启动'); // 清理可能的遮罩 const cleanMask = () => { const mask = document.querySelector('#pop, #cover'); if (mask) mask.remove(); }; cleanMask(); setInterval(cleanMask, 2000); // 接收来自 iframe 的切节消息,统一分发 window.addEventListener('message', (e) => { if (e.data === 'studyNext') { console.log('[学起Plus] 收到 studyNext 消息,开始分发'); dispatchSectionNext(); } }); /* ---------- 策略注册表:检测条件 + 对应切换函数 ---------- */ const strategies = [ { // 策略1:平级 zTree 目录(如高等数学) match: () => document.querySelector('#ztree_online li'), handler: zTreeNext }, { // 策略2:嵌套子菜单目录(旧版课程,有 ul.sub-menu) match: () => document.querySelector('ul.sub-menu'), handler: nestedMenuNext } // 未来新增策略示例: // { // match: () => document.querySelector('#new-tree .chapter'), // handler: newCourseNext // } ]; /** * 策略分发:按顺序查找第一个匹配的策略并执行 * 注意:一旦匹配成功即停止,不会因为执行失败自动回退 */ function dispatchSectionNext() { for (const strategy of strategies) { if (strategy.match()) { console.log('[学起Plus] 匹配到策略:', strategy.handler.name); strategy.handler(); return; } } console.error('[学起Plus] 未找到匹配的课程目录结构,切换失败'); } /* ---------- 具体切换函数实现 ---------- */ // 策略1:平级 zTree 目录 function zTreeNext() { const $ = window.$; const $items = $('#ztree_online li'); if (!$items.length) return; let $active = $items.find('a.curSelectedNode').closest('li'); if (!$active.length && window.currOutlineId) { $active = $items.filter('#' + window.currOutlineId); } if (!$active.length) { $active = $items.first(); } const currentIndex = $items.index($active); const $next = $items.eq(currentIndex + 1); if ($next.length) { $items.find('a').removeClass('curSelectedNode'); $next.find('a').addClass('curSelectedNode'); $next.find('a')[0].click(); $next[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' }); console.log('[学起Plus] zTreeNext 切换成功'); } else { console.log('[学起Plus] 已经是最后一个节点'); } } // 策略2:嵌套子菜单目录(旧版备用) function nestedMenuNext() { const $ = window.$; const $li = $('li').filter((_, li) => !$(li).find('ul.sub-menu').length); let $active = $li.filter('[class*="activeState"]'); if (!$active.length && window.currOutlineId) { $active = $li.filter(`[nid="${window.currOutlineId}"]`); } const $next = $li.eq($li.index($active) + 1); if ($next.length) { $('ul.sub-menu').hide() .filter($next.parents('li').map((_, li) => $(li).children('ul.sub-menu')[0])) .show() .parent().addClass('open'); $next.find('a')[0].click(); console.log('[学起Plus] nestedMenuNext 切换成功'); } } })();