// ==UserScript== // @name 中小学网络党校_学习公社云平台自动刷课 // @namespace http://tampermonkey.net/ // @version 1.3 // @description 自动进入视频学习,自动播放所有未完成课程,全部完成后自动切换下一门 // @match https://study.enaea.edu.cn/* // @grant none // ==/UserScript== (function () { 'use strict'; // ==================== 配置 ==================== const CONFIG = { playbackRate: 1, // 播放倍速(1=正常速度,不加速) checkInterval: 2000, // 视频页检查间隔(ms) listRefreshInterval: 20000, // 课程列表页刷新间隔(ms) enableMuted: false, // 静音播放 }; // ==================== 工具函数 ==================== function log(msg) { console.log('%c[自动刷课] ' + msg, 'color:#4CAF50;font-weight:bold;'); } function getProgressFromText(text) { var m = String(text).match(/(\d+)%/); return m ? parseInt(m[1]) : 0; } // ==================== 课程列表页逻辑 ==================== function isListPage() { return location.href.indexOf('circleIndexRedirect.do') > -1 && location.href.indexOf('type=course') > -1; } function getCourseRows() { // 获取所有课程行(有 golearn 按钮的行) var links = document.querySelectorAll('a.golearn'); var rows = []; links.forEach(function (a) { var tr = a.closest('tr'); if (tr) rows.push(tr); }); return rows; } function getCourseProgress(tr) { var p = tr.querySelector('.progressvalue'); return p ? getProgressFromText(p.innerText) : 0; } function getCourseId(tr) { var a = tr.querySelector('a.golearn'); return a ? a.getAttribute('data-id') : null; } function getCourseTitle(tr) { var span = tr.querySelector('.course-title'); return span ? span.getAttribute('title') || span.innerText : ''; } function runListPage() { log('=== 课程列表页 ==='); // 读取当前正在学习的课程ID(来自 localStorage) var currentId = localStorage.getItem('autoLearn_currentId'); // 找到所有课程 var rows = getCourseRows(); if (rows.length === 0) { log('未找到课程列表,3秒后重试...'); setTimeout(runListPage, 3000); return; } // 找第一个未完成的课程 var firstIncomplete = null; var currentRow = null; for (var i = 0; i < rows.length; i++) { var progress = getCourseProgress(rows[i]); var id = getCourseId(rows[i]); if (id === currentId) { currentRow = rows[i]; } if (progress < 100 && !firstIncomplete) { firstIncomplete = rows[i]; } } // 如果有正在学习的课程 if (currentId && currentRow) { var curProgress = getCourseProgress(currentRow); log('当前学习课程进度: ' + curProgress + '% (ID=' + currentId + ')'); if (curProgress >= 100) { // 已完成,清除记录,继续找下一个 log('课程已完成,切换下一门'); localStorage.removeItem('autoLearn_currentId'); // 延迟刷新,加载最新列表 setTimeout(function () { location.reload(); }, 2000); return; } else { // 还在学习中,等待刷新 log('等待视频播放完成,' + CONFIG.listRefreshInterval / 1000 + '秒后刷新...'); setTimeout(function () { location.reload(); }, CONFIG.listRefreshInterval); return; } } // 没有正在学习的课程,找第一个未完成的 if (firstIncomplete) { var id = getCourseId(firstIncomplete); var title = getCourseTitle(firstIncomplete); log('找到未完成课程: ' + title + ' (ID=' + id + ')'); localStorage.setItem('autoLearn_currentId', id); var btn = firstIncomplete.querySelector('a.golearn'); if (btn) { btn.click(); log('已点击学习按钮,等待视频页加载...'); } } else { log('🎉 当前页所有课程均已完成!'); // 尝试点击下一页 var nextBtn = document.querySelector('a.next, li.next a, [id*="next"] a'); if (nextBtn && !nextBtn.parentElement.classList.contains('disabled')) { log('翻到下一页...'); nextBtn.click(); } else { log('全部课程已完成!'); } } } // ==================== 视频播放页逻辑 ==================== function isVideoPage() { return location.href.indexOf('viewerforccvideo.do') > -1; } function getEpisodes() { return document.querySelectorAll('li.cvtb-MCK-course-content'); } function getEpisodeProgress(li) { var p = li.querySelector('.cvtb-MCK-CsCt-studyProgress'); return p ? getProgressFromText(p.innerText) : 0; } function isEpisodeCurrent(li) { return li.className.indexOf('current') > -1; } function getVideo() { return document.querySelector('video'); } function runVideoPage() { log('=== 视频播放页 ==='); // 等待视频元素加载 var waitCount = 0; var timer = setInterval(function () { waitCount++; var video = getVideo(); var episodes = getEpisodes(); if (!video || episodes.length === 0) { if (waitCount > 30) { log('等待超时,未找到视频或分集列表'); clearInterval(timer); } return; } clearInterval(timer); // 开始自动播放循环 log('视频已加载,共 ' + episodes.length + ' 集'); startAutoPlayLoop(video, episodes); }, 1000); } // ==================== 弹窗自动关闭 ==================== function handlePopups() { // 1. 阻止原生alert/confirm/prompt弹窗 if (!window.__alertOverridden) { window.alert = function (msg) { log('拦截alert弹窗: ' + msg); }; window.confirm = function (msg) { log('自动确认confirm弹窗: ' + msg); return true; }; window.prompt = function (msg) { log('自动关闭prompt弹窗: ' + msg); return ''; }; window.__alertOverridden = true; } // 2. 检测 layer.js 弹窗 var layers = document.querySelectorAll('.layui-layer, .layui-layer-dialog, .layui-layer-page'); layers.forEach(function (layer) { if (layer.offsetParent !== null) { // 可见 log('检测到layer弹窗,自动关闭'); // 优先点击"确定"按钮 var confirmBtn = layer.querySelector('.layui-layer-btn0, .layui-layer-btn a:first-child'); if (confirmBtn) { confirmBtn.click(); } else { // 点击关闭按钮 var closeBtn = layer.querySelector('.layui-layer-close, .layui-layer-ico'); if (closeBtn) closeBtn.click(); else layer.style.display = 'none'; } } }); // 3. 检测自定义确认弹窗(包含"继续学习"、"确定"等字样的按钮) var allBtns = document.querySelectorAll('button, a.btn, input[type="button"], input[type="submit"]'); var popupTexts = ['继续学习', '确定', '确认', '知道了', '是', '继续观看', '继续播放', 'OK', 'Yes']; allBtns.forEach(function (btn) { if (btn.offsetParent === null) return; // 不可见 var text = (btn.innerText || btn.value || '').trim(); // 检查按钮是否在弹窗容器内(fixed定位的父元素) var parent = btn.parentElement; var inPopup = false; while (parent) { var style = window.getComputedStyle(parent); if (style.position === 'fixed' || parent.className.indexOf('modal') > -1 || parent.className.indexOf('dialog') > -1 || parent.className.indexOf('popup') > -1) { inPopup = true; break; } parent = parent.parentElement; if (parent === document.body) break; } if (inPopup) { for (var i = 0; i < popupTexts.length; i++) { if (text.indexOf(popupTexts[i]) > -1) { log('自动点击弹窗按钮: ' + text); btn.click(); break; } } } }); // 4. 检测遮罩层(黑色半透明背景),直接移除 var masks = document.querySelectorAll('.layui-layer-shade, .modal-backdrop, .mask, .overlay, [class*="shade"]'); masks.forEach(function (mask) { if (mask.offsetParent !== null) { log('移除弹窗遮罩层'); mask.remove(); } }); } function checkAndSwitchEpisode(video) { // 先处理弹窗 handlePopups(); var eps = getEpisodes(); if (eps.length === 0) return; // 找到当前正在播放的集 var currentEp = null; for (var i = 0; i < eps.length; i++) { if (isEpisodeCurrent(eps[i])) { currentEp = eps[i]; break; } } if (!currentEp) { // 没有当前集,找第一个未完成的 for (var i = 0; i < eps.length; i++) { if (getEpisodeProgress(eps[i]) < 100) { log('切换到未完成的集: ' + eps[i].getAttribute('title')); eps[i].click(); return; } } // 全部完成 log('🎉 本课程所有集已完成!'); localStorage.removeItem('autoLearn_currentId'); setTimeout(function () { window.close(); }, 3000); return; } var currentProgress = getEpisodeProgress(currentEp); var currentTitle = currentEp.getAttribute('title'); // 当前集已完成 → 找下一个未完成的 if (currentProgress >= 100) { log('当前集已完成(100%): ' + currentTitle); var nextEp = null; for (var i = 0; i < eps.length; i++) { if (getEpisodeProgress(eps[i]) < 100) { nextEp = eps[i]; break; } } if (nextEp) { log('切换到下一集: ' + nextEp.getAttribute('title')); nextEp.click(); } else { // 全部完成 log('🎉 本课程所有集已完成!'); localStorage.removeItem('autoLearn_currentId'); setTimeout(function () { window.close(); setTimeout(function () { if (!window.closed) { log('请手动关闭此标签页,回到课程列表继续学习'); } }, 1000); }, 3000); } return; } // 当前集未完成 → 如果视频播完了就重新播放 if (video.ended || video.currentTime >= video.duration - 1) { log('当前集未完成(' + currentProgress + '%),重新播放'); video.currentTime = 0; video.play(); } } function startAutoPlayLoop(video, episodes) { // 尝试自动播放(先静音,绕过浏览器自动播放限制) function tryPlay() { try { video.muted = true; // 静音才能自动播放 if (video.paused) { video.play().catch(function (e) { log('自动播放被拦截,重试中...'); }); } } catch (e) {} } // 播放结束事件 → 检查进度,未完成则重播 video.addEventListener('ended', function () { log('本集播放完毕,检查进度...'); setTimeout(function () { checkAndSwitchEpisode(video); tryPlay(); }, 1000); }); // 视频可以播放的事件(loadeddata, canplay)→ 立即触发播放 video.addEventListener('loadeddata', tryPlay); video.addEventListener('canplay', tryPlay); video.addEventListener('playing', function() { log('视频开始播放'); }); // 每 N 秒检查一次 setInterval(function () { // 确保视频在播放(静音自动播放) tryPlay(); checkAndSwitchEpisode(video); }, CONFIG.checkInterval); // 立即执行一次 log('启动自动播放(静音自动播放模式)'); tryPlay(); } // ==================== 启动 ==================== log('脚本已加载'); // 等待页面加载完成 function boot() { if (isListPage()) { // 课程列表页,延迟1秒等DOM渲染 setTimeout(runListPage, 1500); } else if (isVideoPage()) { setTimeout(runVideoPage, 1500); } else { log('当前页面不是课程学习页或视频播放页,脚本不执行操作'); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', boot); } else { boot(); } })();