Greasy Fork

Greasy Fork is available in English.

智慧树刷课脚本(增强版)

智慧树自动刷课程序,支持自动获取课程信息和控制功能

当前为 2024-11-09 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         智慧树刷课脚本(增强版)
// @namespace    http://tampermonkey.net/
// @version      2.0
// @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; font-size: 12px; border-top: 1px solid #eee; padding-top: 10px;"></div>
        `;

        panel.innerHTML = panelHTML;
        document.body.appendChild(panel);
    }

    // 获取课程列表
    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 addLog(message) {
        const logElement = document.getElementById('log');
        if (logElement) {
            const logEntry = document.createElement('div');
            logEntry.style.marginBottom = '5px';
            logEntry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
            logElement.insertBefore(logEntry, logElement.firstChild);
        }
    }

    // 更新状态显示
    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; // 检查是否已停止

                    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);

                    // 处理每个视频
                    for (let i = 0; i < 3; i++) {
                        if (!currentTask) return; // 检查是否已停止

                        updateStatus(`正在处理: ${lesson.lessonName} (${++completedLessons}/${totalLessons}课)`);
                        addLog(`视频--${lesson.lessonName}--观看进度: ${i + 1}/3`);

                        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();

                        const result = await makeRequest(setWichTime, {
                            method: 'POST',
                            headers: {
                                'Content-Type': 'application/x-www-form-urlencoded'
                            },
                            body: formData
                        });

                        addLog(`视频--${lesson.lessonName}--观看结果: ${JSON.stringify(result)}`);

                        hh++;
                        // 添加随机延时(2-4秒)
                        await new Promise(resolve => setTimeout(resolve, 2000 + Math.random() * 2000));
                    }
                }
            }

            addLog('课程处理完成!');
            updateStatus('完成!');
            currentTask = null;
            updateCourseList();
        } catch (error) {
            console.error('处理过程中出错:', error);
            addLog('处理过程中出错: ' + error.message);
            updateStatus('出错: ' + error.message);
            currentTask = null;
            updateCourseList();
        }
    }

    // 初始化
    addPanel();
    fetchCourseList();

})();