Greasy Fork is available in English.
智慧树自动刷课程序,支持自动获取课程信息和控制功能,优化日志显示和进度显示
当前为
// ==UserScript==
// @name 智慧树刷课脚本(增强版-优化进度显示) -by这是哪头猪?
// @namespace http://tampermonkey.net/
// @version 2.2
// @description 智慧树自动刷课程序,支持自动获取课程信息和控制功能,优化日志显示和进度显示
// @author Anony
// @match http://www.learning.mil.cn/student/study
// @grant GM_xmlhttpRequest
// @connect armystudy.zhihuishu.com
// @connect www.learning.mil.cn
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
let courses = [];
let currentTask = null;
// 添加控制面板
function addPanel() {
const panel = document.createElement('div');
panel.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: #fff;
padding: 15px;
border: 1px solid #ccc;
border-radius: 5px;
z-index: 9999;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
width: 300px;
`;
const panelHTML = `
<div style="margin-bottom: 10px;">
<h3 style="margin: 0 0 10px 0;">智慧树课程列表</h3>
<div id="courseList" style="max-height: 300px; overflow-y: auto;"></div>
</div>
<div id="status" style="margin-top: 10px; color: #666; font-size: 12px;"></div>
<div id="log" style="margin-top: 10px; max-height: 150px; overflow-y: auto; overflow-x: clip; font-size: 12px; border-top: 1px solid #eee; padding-top: 10px;"></div>
`;
panel.innerHTML = panelHTML;
document.body.appendChild(panel);
// 添加日志头部
addLogHeader();
}
// 格式化日志条目
function formatLogEntry(chapterName, progress, result) {
return `
<div style="display: grid; grid-template-columns: 40% 30% 30%; gap: 10px; padding: 8px 0; border-bottom: 1px solid #eee;">
<div style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">${chapterName}</div>
<div>${progress}</div>
<div style="color: ${result.success ? '#4CAF50' : '#ff4444'}">${result.msg || '完成'}</div>
</div>
`;
}
// 添加日志头部
function addLogHeader() {
const logElement = document.getElementById('log');
if (logElement) {
const header = document.createElement('div');
header.className = 'log-header';
header.style.cssText = `
display: grid;
grid-template-columns: 40% 30% 30%;
gap: 10px;
padding: 8px 0;
font-weight: bold;
border-bottom: 2px solid #ddd;
background: #f5f5f5;
position: sticky;
top: 0;
`;
header.innerHTML = `
<div>课程章节</div>
<div>观看进度</div>
<div>观看结果</div>
`;
logElement.insertBefore(header, logElement.firstChild);
}
}
// 添加日志
function addLog(entry) {
const logElement = document.getElementById('log');
if (logElement) {
// 如果是文本日志(比如状态更新),添加到最顶部
if (typeof entry === 'string') {
const textEntry = document.createElement('div');
textEntry.style.cssText = `
padding: 5px 0;
border-bottom: 1px solid #eee;
color: #666;
`;
textEntry.textContent = `[${new Date().toLocaleTimeString()}] ${entry}`;
// 将文本日志添加到标题行的后面
if (logElement.children.length > 1) {
logElement.insertBefore(textEntry, logElement.children[1]);
} else {
logElement.appendChild(textEntry);
}
}
// 如果是课程观看记录,添加到文本日志后面
else if (entry.type === 'watch') {
const logEntry = document.createElement('div');
logEntry.innerHTML = formatLogEntry(entry.chapter, entry.progress, entry.result);
// 确保课程记录添加到文本日志的后面
logElement.appendChild(logEntry);
}
}
}
// 获取课程列表
async function fetchCourseList() {
try {
const response = await makeRequest('http://www.learning.mil.cn/api/web/student/enrollment/course/?limit=7&offset=0', {
method: 'GET',
headers: {
'Cookie': document.cookie
}
});
courses = response.results.filter(course => course.platform === 33);
updateCourseList();
} catch (error) {
addLog('获取课程列表失败: ' + error.message);
}
}
// 更新课程列表显示
function updateCourseList() {
const courseListElement = document.getElementById('courseList');
if (!courseListElement) return;
courseListElement.innerHTML = courses.map((course, index) => `
<div style="padding: 10px; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center;">
<div style="flex: 1;">
<div style="font-weight: bold;">${course.course_title}</div>
<div style="font-size: 12px; color: #666;">进度: ${course.learned_process}</div>
</div>
<button
id="courseBtn_${index}"
data-index="${index}"
style="padding: 5px 10px; border-radius: 3px; cursor: pointer; border: none; background: ${currentTask && currentTask.courseIndex === index ? '#ff4444' : '#4CAF50'}; color: white;"
>
${currentTask && currentTask.courseIndex === index ? '停止' : '开始'}
</button>
</div>
`).join('');
courses.forEach((_, index) => {
const btn = document.getElementById(`courseBtn_${index}`);
if (btn) {
btn.addEventListener('click', () => toggleCourse(index));
}
});
}
// 切换课程状态
function toggleCourse(index) {
if (currentTask && currentTask.courseIndex === index) {
currentTask = null;
updateCourseList();
addLog(`停止处理课程: ${courses[index].course_title}`);
} else {
if (currentTask) {
currentTask = null;
updateCourseList();
}
const course = courses[index];
currentTask = {
courseIndex: index,
userId: course.user_id,
courseId: course.course_id
};
updateCourseList();
addLog(`开始处理课程: ${course.course_title}`);
zhihuishu(course.user_id, course.course_id);
}
}
// 更新状态显示
function updateStatus(message) {
const statusElement = document.getElementById('status');
if (statusElement) {
statusElement.textContent = message;
}
addLog(message);
}
// 使用GM_xmlhttpRequest进行请求
function makeRequest(url, options) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: options.method || 'GET',
url: url,
headers: options.headers || {},
data: options.body,
responseType: 'json',
onload: function(response) {
if (response.status >= 200 && response.status < 300) {
resolve(response.response);
} else {
reject(new Error('请求失败: ' + response.status));
}
},
onerror: function(error) {
reject(error);
}
});
});
}
// 主处理函数
async function zhihuishu(userId, courseId) {
if (!currentTask) return;
const queryUrl = `http://armystudy.zhihuishu.com/armystudy/queryChapterInfos?userId=${userId}&courseId=${courseId}&ts&token`;
const setWichTime = 'http://armystudy.zhihuishu.com/armystudy/stuRecord';
try {
updateStatus('正在获取课程信息...');
const chapterInfo = await makeRequest(queryUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
userId: userId.toString(),
courseId: courseId.toString()
}).toString()
});
if (!chapterInfo.chapterInfoDtoList) {
throw new Error('获取课程信息失败,请检查ID是否正确');
}
const chapterInfoDtoList = chapterInfo.chapterInfoDtoList;
let totalLessons = 0;
let completedLessons = 0;
chapterInfoDtoList.forEach(chapter => {
totalLessons += chapter.lessonInfoDtos.length;
});
for (const chapter of chapterInfoDtoList) {
if (!currentTask) return;
for (const lesson of chapter.lessonInfoDtos) {
if (!currentTask) return;
completedLessons++;
updateStatus(`正在处理: ${lesson.lessonName} (${completedLessons}/${totalLessons}课)`);
const videoTime = lesson.videoTime;
let s = videoTime.split(':')[0];
let watchTime = 0;
if (s.startsWith('0')) {
watchTime = (parseInt(s.replace('0', '')) + 1) * 60;
} else {
watchTime = (parseInt(s) + 1) * 60;
}
let hh = Math.floor(watchTime / 3);
let lastResult = null;
// 执行三次观看,但只记录最后一次的结果
for (let i = 0; i < 3; i++) {
if (!currentTask) return;
const formData = new URLSearchParams({
userId: userId.toString(),
courseId: courseId.toString(),
videoId: lesson.videoId.toString(),
exitwatchTime: '0',
lessonId: lesson.lessonId.toString(),
measureId: lesson.measureId.toString(),
videoNum: '53',
watchTime: hh.toString()
}).toString();
lastResult = await makeRequest(setWichTime, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: formData
});
hh++;
await new Promise(resolve => setTimeout(resolve, 2000 + Math.random() * 2000));
}
// 只在完成三次观看后添加一次日志
addLog({
type: 'watch',
chapter: lesson.lessonName,
progress: `${completedLessons}/${totalLessons}`,
result: lastResult
});
}
}
addLog('课程处理完成!');
updateStatus('完成!');
currentTask = null;
updateCourseList();
} catch (error) {
console.error('处理过程中出错:', error);
addLog('处理过程中出错: ' + error.message);
updateStatus('出错: ' + error.message);
currentTask = null;
updateCourseList();
}
}
// 初始化
addPanel();
fetchCourseList();
})();