// ==UserScript== // @name 安徽继续教育全自动刷课-UI优化终极版新 // @namespace http://tampermonkey.net/ // @version 1.2 // @description 修复视频页被误判为文本页(懒加载/iframe导致) | 作业页不提交、仅目录跳转 | 独立作业跳转开关 | 自动识别未浏览课程 | 多层目录顺序跳转 | 新增联系作者QQ按钮 // @author 1678955137 // @match *://main.ahjxjy.cn/study/html/content/studying/* // @grant GM_addStyle // @grant GM_notification // @grant GM_setValue // @grant GM_getValue // @grant unsafeWindow // @run-at document-end // @license GPL 3 // ==/UserScript== (function() { 'use strict'; const unsafe = unsafeWindow || window; const state = { panel: null, isCollapsed: GM_getValue('panelCollapsed', false), currentSpeed: GM_getValue('playbackSpeed', 1.5), volumeLevel: GM_getValue('volumeLevel', 0), isAutoJumpEnabled: GM_getValue('isAutoJumpEnabled', true), isHomeworkAutoJumpEnabled: GM_getValue('isHomeworkAutoJumpEnabled', false), // 作业页自动跳转开关 logMessages: [], pos: GM_getValue('panelPos', {left: '20px', top: '20%'}), hasProcessedTextPage: false, homeworkProcessed: false, homeworkLogged: false, endJumpScheduled: false, pageType: 'unknown', lastUrl: location.href, textConfirmTimer: null, textJumpTimer: null }; // --- 样式定义 --- GM_addStyle(` :root { --primary: #4CAF50; --bg: rgba(255, 255, 255, 0.95); } #gemini-panel { position: fixed; z-index: 2147483647; width: 300px; background: var(--bg); backdrop-filter: blur(12px); border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); border: 1px solid rgba(0,0,0,0.05); transition: width 0.3s cubic-bezier(0.18, 0.89, 0.32, 1.28), height 0.3s, opacity 0.3s; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; } #gemini-panel.collapsed { width: 50px; height: 50px; border-radius: 25px; cursor: pointer; overflow: hidden; } .panel-header { padding: 12px; background: var(--primary); color: white; border-top-left-radius: 12px; border-top-right-radius: 12px; cursor: move; display: flex; justify-content: space-between; align-items: center; font-weight: bold; } .panel-body { padding: 15px; display: flex; flex-direction: column; gap: 15px; } .collapsed .panel-body, .collapsed .panel-header span { display: none; } .collapsed .panel-header { height: 100%; padding: 0; justify-content: center; background: var(--primary); border-radius: 25px; } .control-row { display: flex; align-items: center; justify-content: space-between; font-size: 14px; color: #333; } .slider-ui { flex: 1; margin: 0 10px; height: 4px; accent-color: var(--primary); cursor: pointer; } .btn-action { width: 100%; padding: 10px; border: none; border-radius: 8px; background: var(--primary); color: white; font-weight: bold; cursor: pointer; transition: transform 0.1s; } .btn-action:active { transform: scale(0.96); } .btn-next { background: #2196F3 !important; } .btn-find-unstudied { background: #FF9800 !important; } .btn-qq { background: #9b59b6 !important; } .log-area { height: 120px; background: #1e1e1e; color: #adff2f; padding: 8px; font-size: 12px; border-radius: 6px; overflow-y: auto; white-space: pre-wrap; box-shadow: inset 0 2px 5px rgba(0,0,0,0.2); line-height: 1.4; } .switch { position: relative; display: inline-block; width: 40px; height: 20px; } .switch input { opacity: 0; width: 0; height: 0; } .slider-round { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .4s; border-radius: 20px; } .slider-round:before { position: absolute; content: ""; height: 16px; width: 16px; left: 2px; bottom: 2px; background-color: white; transition: .4s; border-radius: 50%; } input:checked + .slider-round { background-color: var(--primary); } input:checked + .slider-round:before { transform: translateX(20px); } `); // --- 日志输出 --- function log(msg) { const time = new Date().toLocaleTimeString([], { hour12: false }); state.logMessages.push(`[${time}] ${msg}`); if (state.logMessages.length > 30) state.logMessages.shift(); const el = document.getElementById('logArea'); if (el) { el.textContent = state.logMessages.join('\n'); el.scrollTop = el.scrollHeight; } } // --- 自动展开所有折叠目录 --- function expandAllFolder() { const toggleBtns = document.querySelectorAll('.toggle_lesson'); toggleBtns.forEach(btn => { const childUl = btn.nextElementSibling?.nextElementSibling; if (childUl) { const isHide = childUl.classList.contains('hidden') || getComputedStyle(childUl).display === 'none'; if (isHide) { btn.click(); log("自动展开折叠任务菜单"); } } }); } // --- 查找视频元素(主文档 + 同源 iframe)--- function getVideoEl() { try { const v = document.querySelector('video, .jw-video'); if (v) return v; } catch (e) {} try { const iframes = document.querySelectorAll('iframe'); for (const f of iframes) { try { const doc = f.contentDocument || (f.contentWindow && f.contentWindow.document); if (!doc) continue; const v2 = doc.querySelector('video, .jw-video'); if (v2) return v2; } catch (e2) {} } } catch (e) {} return null; } // --- 判断页面是否存在播放器(video元素 / 播放器容器 / 跨域播放器iframe)--- function hasVideoPlayer() { if (getVideoEl()) return true; try { if (document.querySelector('.jwplayer, .jw-media, .video-js, .ckplayer, .prism-player, #player, .video-player')) return true; } catch (e) {} try { const iframes = document.querySelectorAll('iframe'); for (const f of iframes) { const src = (f.src || '').toLowerCase(); if (/player|video|\.m3u8|media/.test(src)) return true; } } catch (e) {} return false; } // --- 页面类型识别(仅在类型变化时输出日志,避免刷屏)--- function detectPageType() { const hasVideo = hasVideoPlayer(); const isHomeworkPage = document.title.includes('作业') || document.querySelector('a[title*="作业"]') || document.querySelector('i.icon-yuan'); const hasNextBtn = !!document.querySelector('#focus > div.preNext.next') || Array.from(document.querySelectorAll('a, button')).some(el => el.textContent.includes('下一单元') || el.textContent.includes('下一节')); let newType; if (hasVideo) { newType = 'video'; } else if (isHomeworkPage) { newType = 'homework'; } else if (hasNextBtn) { newType = 'text'; } else { newType = 'unknown'; } if (newType !== state.pageType) { const prev = state.pageType; state.pageType = newType; const typeText = { video: '视频课程页', text: '文本/教案页', homework: '作业页面(仅目录跳转)', unknown: '未知页面' }; log(`页面类型识别:${typeText[newType]}`); if (newType === 'video') { // 之前误判为文本/未知,现在发现视频 → 取消待执行的文本跳转 if (prev === 'text' || prev === 'unknown') { cancelPendingJump(); log("✅ 已取消文本页跳转,按视频页处理"); } updateVideo(); } } return state.pageType; } // --- 判断章节是否已浏览/已学习 --- function isSectionStudied(link) { const parentLi = link.closest('li'); if (!parentLi) return false; if (parentLi.classList.contains('current')) return true; const hasCompleteIcon = parentLi.querySelector('i.iconfont.icon-iconfontyuan[title*="已完成"]') !== null; const hasCompleteText = (link.title || '').includes('已完成') || link.textContent.includes('已完成'); return hasCompleteIcon || hasCompleteText; } // --- 查找并点击第一个未浏览的章节(含作业链接)--- function findAndClickUnstudiedSection() { expandAllFolder(); const linkNodes = document.querySelectorAll( 'ul.list-order li a[href*="/study/html/content/studying/"]:not([href*="javascript:void(0)"])' ); const allLinks = Array.from(linkNodes); if (allLinks.length === 0) { log("❌ 未扫描到任何课程链接"); return false; } const unstudiedLink = allLinks.find(link => !isSectionStudied(link)); if (unstudiedLink) { log(`🔍 找到未浏览内容:${unstudiedLink.title || unstudiedLink.textContent.trim()}`); unstudiedLink.click(); return true; } else { log("✅ 目录内所有内容均已浏览完成"); return false; } } // --- 核心:目录顺序跳转(纯链接跳转,无任何提交操作)--- function jumpFromDirectory() { expandAllFolder(); const linkNodes = document.querySelectorAll( 'ul.list-order li a[href*="/study/html/content/studying/"]:not([href*="javascript:void(0)"])' ); const allLinks = Array.from(linkNodes); if (allLinks.length === 0) { log("❌ 未扫描到任何课程链接"); return false; } // 双重定位当前页面 let currIndex = -1; const currentLi = document.querySelector('li.current'); if (currentLi) { const currA = currentLi.querySelector('a[href*="/study/html/content/studying/"]'); if (currA) { currIndex = allLinks.findIndex(link => link.href === currA.href); } } if (currIndex === -1) { const nowUrl = location.href; currIndex = allLinks.findIndex(link => link.href === nowUrl); } // 定位失败 / 当前已是最后一节 → 自动找未浏览内容 if (currIndex === -1 || currIndex >= allLinks.length - 1) { log("当前位置异常/已到末尾,自动查找未浏览内容"); return findAndClickUnstudiedSection(); } const nextLink = allLinks[currIndex + 1]; // 下一节已浏览,继续查找 if (isSectionStudied(nextLink)) { log(`⚠️ 下一项 ${nextLink.title} 已浏览,继续查找未浏览内容`); return findAndClickUnstudiedSection(); } log(`➡ 顺序跳转至下一项:${nextLink.title || nextLink.textContent.trim()}`); nextLink.click(); return true; } // --- 统一跳转入口 --- function jumpNextManually() { expandAllFolder(); const nextBtn = document.querySelector('#focus > div.preNext.next') || Array.from(document.querySelectorAll('a, button')).find(el => el.textContent.includes('下一单元') || el.textContent.includes('下一节') ); if (nextBtn) { log("点击页面内置【下一节】按钮"); nextBtn.click(); return; } log("页面无内置跳转按钮,使用目录顺序跳转"); jumpFromDirectory(); } // --- 取消待执行的文本页跳转(复查发现视频时调用)--- function cancelPendingJump() { if (state.textConfirmTimer) { clearTimeout(state.textConfirmTimer); state.textConfirmTimer = null; } if (state.textJumpTimer) { clearTimeout(state.textJumpTimer); state.textJumpTimer = null; } state.hasProcessedTextPage = false; } // --- 构建控制面板 --- function createPanel() { const panel = document.createElement('div'); panel.id = 'gemini-panel'; if (state.isCollapsed) panel.classList.add('collapsed'); panel.style.left = state.pos.left; panel.style.top = state.pos.top; panel.innerHTML = `