您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
党旗飘飘学习助手,自动刷课,跳转控制,JLU
当前为
// ==UserScript== // @name 在线培训助手 // @namespace http://tampermonkey.net/ // @version 1.0 // @description 党旗飘飘学习助手,自动刷课,跳转控制,JLU // @author bugo // @match *://*/jjfz/play* // @match *://*/*/jjfz/play* // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_notification // @run-at document-start // @license MIT // ==/UserScript== (function() { 'use strict'; console.log("在线培训助手已加载"); // 工具函数 const utils = { getVideo: () => document.querySelector("video"), getRid: () => { const html = document.documentElement.innerHTML; const match = html.match(/rid[\s:="']*(\d+)["'\s]/); return match ? match[1] : null; }, // 清除所有定时器 clearAllTimers: () => { // 清除原页面定时器 clearInterval(window.timer); window.clearInterval(window.loop_flag); window.clearInterval(window.flag); // 清除我们自己的定时器 if (window.autoInterval) { clearInterval(window.autoInterval); window.autoInterval = null; } }, // 处理各种弹窗,包括继续观看和关闭 handleDialogs: () => { // .public_close .public_cancel .public_submit public_cont1这三种按钮 并且要判断内容 document.querySelectorAll(".public_close, .public_cancel, .public_submit, .public_cont1").forEach(btn => { if (btn) { // 继续观看 、我知道了 、继续 if (btn.textContent?.includes("继续观看") || btn.textContent?.includes("我知道了") || btn.textContent?.includes("继续")) { btn.click(); } } }); } }; // 防止页面切换时暂停 const originAddListener = Document.prototype.addEventListener; Document.prototype.addEventListener = function(type, listener, options) { if (type === "visibilitychange") return; return originAddListener.call(this, type, listener, options); }; Object.defineProperty(document, 'hidden', { configurable: true, get: () => false }); Object.defineProperty(document, 'visibilityState', { configurable: true, get: () => 'visible' }); // 添加样式 GM_addStyle(` .jjfz-helper-panel { position: fixed; top: 110px; left: 10px; background: #fff; border-radius: 0 0 4px 4px; box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.2); z-index: 9999; padding: 12px; width: 280px; font-size: 14px; margin-top: -1px; } .jjfz-helper-panel h3 { margin: 0 0 12px 0; padding-bottom: 8px; border-bottom: 1px solid #eee; text-align: center; font-size: 16px; color: #e61d1d; } .jjfz-helper-option { margin-bottom: 10px; } .jjfz-helper-option label { display: block; margin-bottom: 5px; font-weight: bold; } .checkbox-wrapper { display: flex; align-items: center; margin: 5px 0; } .checkbox-wrapper input[type="checkbox"] { width: auto; margin: 0; cursor: pointer; } .jjfz-helper-panel select, .jjfz-helper-panel input, .jjfz-helper-panel button { width: 100%; padding: 6px; border: 1px solid #ddd; border-radius: 3px; margin-bottom: 6px; cursor: pointer; } .jjfz-helper-panel select, .jjfz-helper-panel input[type="text"] { cursor: auto; } .jjfz-helper-panel button { background: #2196F3; color: white; border: none; font-weight: bold; } .jjfz-helper-panel button:hover { background: #1976D2; } .jjfz-helper-panel button.stop { background: #F44336; } .jjfz-helper-panel button.stop:hover { background: #D32F2F; } .jjfz-helper-toggle { position: fixed; top: 80px; left: 10px; background: #2196F3; color: white; border: none; border-radius: 4px; padding: 6px 12px; cursor: pointer; z-index: 10000; font-weight: bold; width: 80px; box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.05); } .jjfz-helper-toggle.expanded { border-radius: 4px 4px 0 0; } .jjfz-helper-toggle:hover { background: #1976D2; } `); // 设置 const settings = { autoPlay: GM_getValue('autoPlay', true), autoNext: true, panelExpanded: GM_getValue('panelExpanded', true), // 保存设置 save: function() { Object.keys(this).forEach(key => { if (typeof this[key] !== 'function' && key !== 'autoNext') { GM_setValue(key, this[key]); } }); } }; // 核心功能 const core = { // 添加学习时长 - 参数为要添加的秒数 addStudyTime: (seconds) => { const rid = utils.getRid(); const video = utils.getVideo(); if (!video || !rid || seconds <= 0) return false; // 计算目标时间 const currentTime = video.currentTime || 0; const duration = video.duration || 600; // 减少2秒,等待网址自动上报完成事件 const targetTime = Math.min(duration-2, currentTime + seconds); // 发送请求并设置视频时间 let success = false; $.ajax({ type: "POST", cache: false, dataType: "json", url: "/jjfz/lesson/current_time", data: { rid: rid, time: targetTime, _xsrf: $(":input[name='_xsrf']").val() }, async: false, success: function(data) { if (data && data.code === 1) { try { video.currentTime = targetTime; success = true; } catch (e) { success = false; } } else { success = false; } }, error: function() { success = false; } }); return success; }, // 自动播放下一集 playNextVideo: () => { const current = document.querySelector('.video_red1')?.closest('li'); const next = current?.nextElementSibling; if (next && next.querySelector('a')) { next.querySelector('a').click(); return true; } else { GM_notification({ text: '✅ 本章播放完成,跳转课程列表页~', timeout: 4000 }); location.href = `${location.protocol}//${location.host}/jjfz/lesson`; return false; } }, // 处理视频结束事件 handleVideoEnded: () => { utils.clearAllTimers(); if (settings.autoNext) { // 等待2秒,确保视频结束事件触发 setTimeout(core.playNextVideo, 2000); } }, // 启动自动学习 startAutoLearning: () => { if (!settings.autoPlay || window.autoInterval) return; // 处理弹窗 utils.handleDialogs(); // 监听视频结束事件 const video = utils.getVideo(); if (video && !video.hasEndedListener) { video.addEventListener('ended', function() { console.log("视频播放结束"); core.handleVideoEnded(); }); video.hasEndedListener = true; } // 启动定时器 window.autoInterval = setInterval(() => { const video = utils.getVideo(); if (!video) return; // 尝试点击播放按钮 if (video.paused) { const playButton = document.querySelector('.plyr__controls [data-plyr="play"], .plyr__play-large, [aria-label="播放"]'); if (playButton) { playButton.click(); } else { // 触发点击事件 video.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })); } video.play(); } // 自动处理弹窗 utils.handleDialogs(); // 更新界面 ui.update(); // 检测视频是否接近结束但尚未触发ended事件 if (video.currentTime > video.duration * 0.98 && !video.ended) { video.currentTime = video.duration; // 强制跳到结尾触发ended事件 } }, 1500); } }; // UI 相关功能 const ui = { create: () => { // 创建切换按钮 const toggleButton = document.createElement('button'); toggleButton.className = 'jjfz-helper-toggle' + (settings.panelExpanded ? ' expanded' : ''); toggleButton.textContent = settings.panelExpanded ? '收起' : '展开'; toggleButton.onclick = function() { const panel = document.querySelector('.jjfz-helper-panel'); settings.panelExpanded = !settings.panelExpanded; panel.style.display = settings.panelExpanded ? 'block' : 'none'; this.textContent = settings.panelExpanded ? '收起' : '展开'; // 根据展开状态更新按钮样式 this.classList.toggle('expanded', settings.panelExpanded); settings.save(); }; document.body.appendChild(toggleButton); // 创建控制面板 const panel = document.createElement('div'); panel.className = 'jjfz-helper-panel'; panel.style.display = settings.panelExpanded ? 'block' : 'none'; panel.innerHTML = ` <h3>培训助手</h3> <div class="jjfz-helper-option"> <button id="jjfz-toggle-auto" class="${settings.autoPlay ? 'stop' : ''}">${settings.autoPlay ? '⏸️ 暂停刷课' : '▶️ 开始刷课'}</button> </div> <div class="jjfz-helper-option"> <label>跳转控制</label> <div style="display:flex;gap:5px;"> <input type="number" id="jjfz-jump-time" value="30" min="1" max="3600" style="flex:2;"> <button id="jjfz-jump-btn" style="flex:1;">快进(秒)⏩</button> </div> </div> <div class="jjfz-helper-status"> <p>当前视频: <span id="jjfz-current-video">获取中...</span></p> <p>学习进度: <span id="jjfz-progress">0/0</span></p> </div> `; document.body.appendChild(panel); // 添加事件监听 ui.setupEventListeners(); }, // 设置事件监听 setupEventListeners: () => { document.getElementById('jjfz-toggle-auto').addEventListener('click', function() { settings.autoPlay = !settings.autoPlay; this.textContent = settings.autoPlay ? '⏸️ 暂停刷课' : '▶️ 开始刷课'; this.className = settings.autoPlay ? 'stop' : ''; settings.save(); if (settings.autoPlay) { core.startAutoLearning(); } else { utils.clearAllTimers(); } }); document.getElementById('jjfz-jump-btn').addEventListener('click', function() { const seconds = parseInt(document.getElementById('jjfz-jump-time').value) || 30; core.addStudyTime(seconds); // 快进 }); }, // 更新UI update: () => { const video = utils.getVideo(); if (!video) return; // 更新当前视频信息 const videoTitle = document.querySelector('.video_red1 a')?.textContent.trim() || "未知"; const currentVideoEl = document.getElementById('jjfz-current-video'); if (currentVideoEl) { currentVideoEl.textContent = videoTitle; } // 更新课程进度 const total = document.querySelectorAll('.video_lists ul li').length; const current = Array.from(document.querySelectorAll('.video_lists ul li')).findIndex(li => li.classList.contains('video_red1')) + 1; const progressEl = document.getElementById('jjfz-progress'); if (progressEl) { progressEl.textContent = `${current}/${total}`; } } }; // 主函数 function main() { // 创建UI ui.create(); // 监听视频加载 let checkCount = 0; const videoCheckInterval = setInterval(() => { const video = utils.getVideo(); checkCount++; if (video) { clearInterval(videoCheckInterval); // 监听播放进度 video.addEventListener('timeupdate', ui.update); // 自动学习模式 if (settings.autoPlay) { core.startAutoLearning(); } ui.update(); } else if (checkCount > 20) { // 20秒后仍未找到视频,停止检查 clearInterval(videoCheckInterval); console.log("未能找到视频元素"); } }, 1000); } // 启动脚本 main(); })();