// ==UserScript==
// @name 智能刷课助手
// @namespace http://tampermonkey.net/
// @version 1.3
// @description 使用须知:目前版本只适用于超星学习通,支持自动播放视频、倍数播放和自动跳章;脚本暂不支持章节测试,不支持窗口页面最小化运行;⚠️⚠️在运行脚本时务必将笔记本电脑的睡眠模式关闭,防止电脑息屏。
// @author 天天
// @match https://mooc1.chaoxing.com/mycourse/studentstudy*
// @grant GM_addStyle
// @grant GM_log
// @grant GM_xmlhttpRequest
// @license MIT
// @run-at document-end
// @downloadURL https://update.greasyfork.icu/scripts/524824/%E6%99%BA%E8%83%BD%E5%88%B7%E8%AF%BE%E5%8A%A9%E6%89%8B.user.js
// @updateURL https://update.greasyfork.icu/scripts/524824/%E6%99%BA%E8%83%BD%E5%88%B7%E8%AF%BE%E5%8A%A9%E6%89%8B.meta.js
// ==/UserScript==
(function() {
'use strict';
// 检查是否已存在控制窗口
if (document.querySelector('.course-helper')) {
return;
}
// 创建样式
const style = document.createElement('style');
style.textContent = `
.course-helper {
position: fixed;
top: 20px;
right: 20px;
width: 320px;
min-height: 220px;
background: #1e1e1e; /* 深灰色背景 */
border: 1px solid #444;
border-radius: 10px;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
z-index: 9999;
resize: both;
overflow: auto;
font-family: 'Roboto', sans-serif; /* 现代字体 */
color: #f0f0f0; /* 浅色文字 */
}
.helper-header {
padding: 15px;
background: #2b2b2b; /* 深色头部 */
border-bottom: 1px solid #444;
cursor: move;
border-radius: 10px 10px 0 0;
user-select: none;
display: flex;
justify-content: space-between;
align-items: center;
}
.helper-content {
padding: 20px; /* 增加内边距 */
}
.control-group {
margin-bottom: 20px; /* 增加底部间距 */
}
.control-label {
display: block;
margin-bottom: 10px;
font-weight: bold;
color: #e0e0e0;
}
.control-input {
width: 100%;
padding: 10px; /* 增加内边距 */
margin-bottom: 12px;
border: 1px solid #555;
border-radius: 5px;
background: #2b2b2b; /* 深色输入框 */
color: #f0f0f0;
}
.btn {
padding: 10px 20px; /* 增加按钮内边距 */
background-color: #4CAF50; /* 绿色按钮 */
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
margin-right: 10px; /* 增加右边距 */
transition: background-color 0.3s ease;
}
.btn:hover {
background-color: #45a049; /* 深绿色 */
}
.btn-danger {
background-color: #dc3545; /* 红色按钮 */
}
.btn-danger:hover {
background-color: #c82333; /* 深红色 */
}
.log-area {
width: 100%;
height: 120px;
border: 1px solid #555;
border-radius: 5px;
padding: 10px;
font-size: 12px;
font-family: 'Consolas', monospace;
resize: vertical;
background: #1a1a1a; /* 深色日志区域 */
color: #ffffff;
overflow-y: auto;
}
.progress-bar {
width: 100%;
height: 20px;
background-color: #2b2b2b; /* 深灰色进度条 */
border-radius: 5px;
margin-bottom: 10px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background-color: #4CAF50; /* 绿色进度 */
width: 0%;
transition: width 0.3s ease;
}
.status-text {
font-size: 12px;
color: #e0e0e0;
margin-bottom: 10px;
}
del {
position: relative;
color: #666;
font-style: italic;
font-weight: bold;
}
del::after {
content: '';
position: absolute;
left: 0;
right: 0;
top: 50%;
border-bottom: 2px solid #ff4444;
}
.support-text {
color: #fff;
font-weight: normal;
font-style: normal;
}
.content {
padding: 20px;
background-color: #1e1e1e;;
}
.content img:hover {
transform: scale(1.05);
}
`;
document.head.appendChild(style);
// 创建助手窗口
const helperWindow = document.createElement('div');
helperWindow.className = 'course-helper';
helperWindow.innerHTML = `
`;
document.body.appendChild(helperWindow);
// 状态变量
let isPlaying = false;
let currentVideoIndex = 0;
let totalVideos = 0;
// 窗口拖拽功能
let isDragging = false;
let offsetX, offsetY;
helperWindow.querySelector('.helper-header').addEventListener('mousedown', (e) => {
isDragging = true;
offsetX = e.clientX - helperWindow.offsetLeft;
offsetY = e.clientY - helperWindow.offsetTop;
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
let newX = e.clientX - offsetX;
let newY = e.clientY - offsetY;
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
const helperWidth = helperWindow.offsetWidth;
const helperHeight = helperWindow.offsetHeight;
newX = Math.max(0, Math.min(newX, windowWidth - helperWidth));
newY = Math.max(0, Math.min(newY, windowHeight - helperHeight));
helperWindow.style.left = `${newX}px`;
helperWindow.style.top = `${newY}px`;
});
document.addEventListener('mouseup', () => {
isDragging = false;
});
// 日志功能
function log(message) {
const logArea = document.getElementById('logArea');
if (!logArea) return;
const timestamp = new Date().toLocaleTimeString();
const logEntry = document.createElement('div');
logEntry.textContent = `[${timestamp}] ${message}`;
logArea.appendChild(logEntry);
logArea.scrollTop = logArea.scrollHeight;
}
// 更新状态显示
function updateStatus(message) {
const statusText = document.getElementById('statusText');
if (statusText) {
statusText.textContent = message;
}
}
// 更新进度条
function updateProgress(current, total) {
const progressBar = document.getElementById('progressBar');
if (progressBar) {
const percentage = (current / total) * 100;
progressBar.style.width = `${percentage}%`;
}
}
// 获取iframe元素
function getIframes() {
try {
const mainFrame = document.getElementById("iframe");
if (!mainFrame) {
log("未找到主iframe");
return [];
}
const iframeDoc = mainFrame.contentWindow.document;
return Array.from(iframeDoc.getElementsByTagName('iframe'));
} catch (error) {
log("获取iframe失败: " + error.message);
return [];
}
}
// 控制单个视频
function controlVideo(video, playbackRate) {
return new Promise((resolve) => {
const handleVideoEnd = () => {
video.removeEventListener('ended', handleVideoEnd);
log("视频播放完成");
resolve();
};
video.addEventListener('ended', handleVideoEnd);
video.muted = true;
video.playbackRate = playbackRate;
video.play().catch(error => {
log("播放失败: " + error.message);
resolve(); // 即使失败也继续下一个
});
});
}
// 视频控制主函数
async function controlAllVideos(action, params = {}) {
const iframes = getIframes();
const videos = [];
for (let iframe of iframes) {
try {
const iframeVideos = Array.from(iframe.contentWindow.document.getElementsByTagName('video'));
videos.push(...iframeVideos);
} catch (error) {
log(`获取视频失败: ${error.message}`);
}
}
totalVideos = videos.length;
if (totalVideos === 0) {
log("未找到可播放的视频");
// 如果没有视频,直接跳转下一章
skipChapter();
return;
}
for (let i = 0; i < videos.length && isPlaying; i++) {
currentVideoIndex = i;
updateStatus(`正在播放第 ${i + 1}/${totalVideos} 个视频`);
updateProgress(i + 1, totalVideos);
try {
const video = videos[i];
switch(action) {
case 'play':
await controlVideo(video, params.playbackRate);
break;
case 'setPlaybackRate':
video.playbackRate = params.playbackRate;
log(`设置播放速度: ${params.playbackRate}x`);
break;
}
} catch (error) {
log(`控制视频失败: ${error.message}`);
}
}
if (currentVideoIndex >= totalVideos - 1) {
log("所有视频播放完成");
isPlaying = false;
updateStatus("播放完成");
document.getElementById('autoPlayBtn').textContent = "开始播放";
// 增加延时确保视频完全结束
setTimeout(() => {
log("准备跳转到下一章节");
skipChapter();
}, 3000); // 等待3秒后跳转
}
}
function skipChapter() {
try {
log("尝试跳转到下一章节");
const nextButton = window.top.document.querySelector("#prevNextFocusNext");
if (nextButton) {
nextButton.click();
log("已点击下一章节按钮");
// 第一次延时:等待完成提示出现
setTimeout(() => {
try {
const tip = window.top.document.querySelector(".maskDiv.jobFinishTip.maskFadeOut");
if (tip) {
const nextChapterBtn = window.top.document.querySelector(".jb_btn.jb_btn_92.fr.fs14.nextChapter");
if (nextChapterBtn) {
nextChapterBtn.click();
log("已确认进入下一章节");
// 第二次延时:等待新页面加载
setTimeout(() => {
log("等待新页面加载完成...");
// 第三次延时:确保新页面完全加载
setTimeout(() => {
try {
// 重新初始化视频播放
isPlaying = false; // 重置播放状态
currentVideoIndex = 0; // 重置视频索引
const autoPlayBtn = document.getElementById('autoPlayBtn');
if (autoPlayBtn) {
log("触发自动播放");
autoPlayBtn.click();
} else {
log("未找到播放按钮,可能需要刷新页面");
}
} catch (error) {
log(`自动播放失败: ${error.message}`);
}
}, 2000);
}, 2000);
} else {
log("未找到确认下一章节按钮");
}
} else {
log("未找到任务点完成提示,直接尝试开始播放");
setTimeout(() => {
const autoPlayBtn = document.getElementById('autoPlayBtn');
if (autoPlayBtn) {
isPlaying = false;
currentVideoIndex = 0;
autoPlayBtn.click();
log("直接开始播放新章节");
}
}, 3000);
}
} catch (error) {
log(`处理完成提示时出错: ${error.message}`);
}
}, 1500);
} else {
log("未找到下一章节按钮");
}
} catch (error) {
log(`跳转章节失败: ${error.message}`);
}
}
//暂停函数
function pauseVideo(){
const iframes = getIframes();
for (let iframe of iframes) {
try {
const videos = iframe.contentWindow.document.getElementsByTagName('video');
for (let video of videos) {
video.pause();
}
} catch (error) {
log(`暂停视频失败: ${error.message}`);
}
}
log('已暂停所有视频');
}
//更新播放速度的函数
function updatePlaybackRate(rate) {
try {
const iframes = getIframes();
for (let iframe of iframes) {
try {
const videos = Array.from(iframe.contentWindow.document.getElementsByTagName('video'));
videos.forEach(video => {
video.playbackRate = rate;
});
} catch (error) {
log(`设置视频速度失败: ${error.message}`);
}
}
} catch (error) {
log(`更新播放速度失败: ${error.message}`);
}
}
// 事件监听
document.getElementById('autoPlayBtn').addEventListener('click', () => {
const button = document.getElementById('autoPlayBtn');
if (!isPlaying) {
isPlaying = true;
button.textContent = "停止播放";
const rate = parseFloat(document.getElementById('playbackRate').value);
controlAllVideos('play', { playbackRate: rate });
log('开始自动播放');
} else {
isPlaying = false;
button.textContent = "开始播放";
log('停止播放');
pauseVideo();
}
});
document.getElementById('playbackRate').addEventListener('change', () => {
const rate = parseFloat(document.getElementById('playbackRate').value);
updatePlaybackRate(rate);
log(`播放速度已调整为 ${rate}x`);
});
// 初始化
setTimeout(() => {
try {
log('刷课助手已加载');
const iframes = getIframes();
log(`当前页面任务点数量:${iframes.length}`);
} catch (error) {
log(`初始化失败: ${error.message}`);
}
}, 1000); // 延迟1秒执行
})();