中国大学mooc自动刷网课JavaScript代码(详细篇)

代码如下:

// ==UserScript==
// @name         中国大学慕课mooc答题/自动播放脚本(domooc)
// @namespace    https://lolzyx.xyz/
// @version      1.6.5
// @description  自动完成你的mooc考试测验客观题,开启刷课后自动看视频、看课件、自动讨论。使用过程中会上传您的mooc账户信息(包括昵称、ID、邮箱等)以识别用户。觉得好用请点击捐赠作者按钮捐赠我。
// @author       Democrazy
// @match        https://www.icourse163.org/learn/*
// @match        http://www.icourse163.org/learn/*
// @match        http://www.icourse163.org/spoc/learn/*
// @match        https://www.icourse163.org/spoc/learn/*
// @connect      lolzyx.xyz
// @connect      localhost
// @grant        unsafewindow
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @require      http://cdn.staticfile.org/jquery/3.4.1/jquery.min.js
// @run-at       document-start
// ==/UserScript==
(function () {
    let usersetting = {
        timeout: 800,       //答题延时,每两道题之间的时间间隔
        autoanswer: true,   //是否开启自动答题,如果设置为false,正确答案会被标记为绿色,或在填空题旁边显示答案
        learnCourse: {     //刷课时的配置
            video: true,    //是否刷视频
            doc: true,      //是否刷文档
            test: true,     //是否刷随堂测验(不消耗答题次数)
            discuss: true,  //是否刷讨论(将自动从当前页面选一条最长的评论复制粘贴,如果当前讨论还没有人发表评论则跳过)
            playrate: 0,    //视频倍速,0表示不改变播放器的倍速
        }
    };
    let version = "165";
    let qqgroup = null;
    let window = unsafeWindow;
    let baseurl = 'https://lolzyx.xyz/api/';
    //let baseurl = 'https://localhost/api/';
    let debug = false;
    let domooc = {
        get csrf() {
            let name = 'NTESSTUDYSI';
            var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
            if (arr = document.cookie.match(reg))
                return unescape(arr[2]);
            else
                return null;
        },
        url: {
            getanswer: baseurl + 'getanswer',
            check: baseurl + 'checkcourse',
            userMessage: baseurl + 'userMessage',
            upsertQuizpaper: baseurl + 'upsertquizpaper',
            fastGetCourse: baseurl + 'fastGetCourse',
            getQuizInfo: "https://www.icourse163.org/dwr/call/plaincall/MocQuizBean.getQuizInfo.dwr",
            getLastLearnedMocTermDto: "https://www.icourse163.org/dwr/call/plaincall/CourseBean.getLastLearnedMocTermDto.dwr",
            getQuizPaper: "https://www.icourse163.org/dwr/call/plaincall/MocQuizBean.getQuizPaperDto.dwr"
        },
        console: {
            log: (msg) => { if (!!debug) window.console.log(msg) },
            error: (msg) => { if (!!debug) window.console.error(msg) },
        },
        utils: {
            trim: function (str) { return str.replace(/\s+/g, ""); },
            getBatchID: function () {
                let batchId = new Date().getTime();
                return batchId - 500 - (Math.random() * 500 | 0);
            },
        },
        $: $
    };
    if (window.scriptloaded) {
        return;
    }
    if (!!debug) {
        window.domooc = domooc;
    }
    $(function () {
        let utils = domooc.utils;
        let tnames = {};
        window.handledomoocRPC = (batchId, status, obj) => {
            if (obj && obj.mocTermDto && obj.mocTermDto.exams && obj.mocTermDto.exams.length) {
                let exams = obj.mocTermDto.exams;
                for (let i = 0; i < exams.length; i++) {
                    window.setTimeout(() => {
                        if (exams[i].objectTestId) {
                            if (utils.shouldUpload(exams[i].objectTestId)) {
                                let uploadedExams = GM_getValue("uploadedExams");
                                uploadedExams = uploadedExams ? uploadedExams : [];
                                if (uploadedExams.indexOf(exams[i].objectTestId) < 0) {
                                    tnames[exams[i].objectTestId] = exams[i].name;
                                    domooc.utils.getExamInfo(exams[i].objectTestId);
                                }
                            }
                        }
                    }, i * 1000 * 5);
                }
                console.log('first stage finised');
            } else if (obj && obj.targetAnswerform && obj.targetAnswerform.aid) {
                window.setTimeout(() => {
                    domooc.utils.getQuizPaper(obj.tid, obj.targetAnswerform.aid);
                }, 2000);
                console.log('second stage finised');
            } else {
                if (obj && obj.objectiveQList && obj.objectiveQList.length) {
                    obj.isExam = true;
                    obj.tname = tnames[obj.tid];
                    domooc.analysisAnswer(obj);
                }
                domooc.console.log(obj);
            }
        };
        utils.shouldUpload = (id) => {
            let shouldUpload = true;
            if (domooc.quizbank instanceof Array) {
                domooc.quizbank.forEach(quiz => {
                    if (quiz.id === id && !quiz.get) {
                        shouldUpload = false;
                    }
                });
            }
            return shouldUpload;
        }
        utils.getLastLearnedMocTermDto = function (coursedto) {
            if (!coursedto) {
                coursedto = window.courseCardDto;
            }

            let requestPayload = "callCount=1\n" + "scriptSessionId=${scriptSessionId}190\n" +
                "httpSessionId=" + domooc.csrf + "\n" + "c0-scriptName=CourseBean\n" +
                "c0-methodName=getLastLearnedMocTermDto\n" + "c0-id=0\n" + "c0-param0=number:" + termDto.id + "\n" +
                "batchId=" + this.getBatchID();
            let res = null;
            $.ajax({
                url: domooc.url.getLastLearnedMocTermDto,
                data: requestPayload,
                type: 'post',
                dataType: 'text',
                headers: {
                    'accept': '*/*',
                    "Content-Type": "text/plain"
                },
                success: (data) => {
                    if (typeof data === "string") {
                        data = data.replace(/dwr\.engine\._[\w]+\(/, 'handledomoocRPC(');
                        window.eval(data);
                    }
                }
            });
            return res;
        };
        utils.getExamInfo = async function (objectTestId, aid) {
            let requestPayload = `callCount=1\nscriptSessionId=\${scriptSessionId}190\nhttpSessionId=${domooc.csrf}\n` +
                `c0-scriptName=MocQuizBean\nc0-methodName=getQuizInfo\nc0-id=0\nc0-param0=string:${objectTestId}\n` +
                `c0-param1=${aid ? ("string:" + aid) : "null:null"}\nc0-param2=boolean:false\nbatchId=${this.getBatchID()}`;
            $.ajax({
                url: domooc.url.getQuizInfo,
                data: requestPayload,
                type: 'post',
                dataType: 'text',
                headers: {
                    'accept': '*/*',
                    "Content-Type": "text/plain"
                },
                success: (data) => {
                    if (typeof data === "string") {
                        data = data.replace(/dwr\.engine\._[\w]+\(/, 'handledomoocRPC(');
                        window.eval(data);
                    }
                }
            });
        };
        utils.getQuizPaper = async function (quizid, aid) {
            if (aid === undefined) {
                aid = 0;
            }
            let requestPayload = "callCount=1\n" +
                "scriptSessionId=${scriptSessionId}190\n" +
                "httpSessionId=" + domooc.csfr + "\n" +
                "c0-scriptName=MocQuizBean\n" +
                "c0-methodName=getQuizPaperDto\n" + "c0-id=0\n" +
                "c0-id=0\n" +
                "c0-param0=string:" + quizid + "\n" +
                "c0-param1=number:" + aid + "\n" +
                "c0-param2=boolean:" + (aid === 0 ? "false" : "true") + "\n" +
                "batchId=" + this.getBatchID();
            $.ajax({
                url: domooc.url.getQuizPaper,
                data: requestPayload,
                type: 'post',
                dataType: 'text',
                headers: {
                    'accept': '*/*',
                    "Content-Type": "text/plain"
                },
                success: (data) => {
                    if (typeof data === "string") {
                        data = data.replace(/dwr\.engine\._[\w]+\(/, 'handledomoocRPC(');
                        window.eval(data);
                    }
                }
            });
        };
        utils.format = function (str) {
            let htmlDecode = function (_str) {
                var s = "";
                if (_str.length == 0) return "";
                s = _str.replace(/</g, "<");
                s = s.replace(/>/g, ">");
                s = s.replace(/ /g, " ");
                s = s.replace(/'/g, "\'");
                s = s.replace(/"/g, "\"");
                s = s.replace(/&/g, "&");
                return s;
            }
            var regx = /<[img ]{3,}[\S]+?[https]{3,4}:\/\/([\S]+?\.[pngjeifbm]{3,4})[\S]+?>/gi;
            var regx2 = /\<[\S ]+?\>/ig;
            return domooc.utils.trim(htmlDecode(str)).replace(regx, "$1").replace(regx2, "");
        }
        utils.remove = function (arr, val) {
            var index = arr.indexOf(val);
            while (index > -1) {
                arr.splice(index, 1);
                index = arr.indexOf(val);
            }
            return arr;
        };
        utils.unique = function (arr, compareFn) {
            arr.sort(compareFn);
            var re = [arr[0]];
            for (var i = 1; i < arr.length; i++) {
                if (compareFn(arr[i], re[re.length - 1]) !== 0) {
                    re.push(arr[i]);
                }
            }
            return domooc.utils.remove(re, undefined);
        };


        function initParams() {
            domooc.quizs = null;
            domooc.exceptionflag = false;
            domooc.quizpaper = {};
            domooc.qb = {};
            domooc.quiztests = [];
            domooc.termid = 0;
            domooc.courseid = 0;
            domooc.answerAll = false;
            domooc.getAnswerflag = false;
        }



        function userMessage(msg) {
            view.addInfo("正在留言...");
            let data = getInitialData();
            data.message = msg;
            GM_xmlhttpRequest({
                method: 'POST',
                url: domooc.url.userMessage,
                data: JSON.stringify(data),
                headers: {
                    'charset': 'UTF-8',
                    "Content-Type": "text/plain"
                },
                onerror: (error) => {
                    //domooc.console.log({ onerror: error });
                    view.addInfo("留言失败!", "网络或服务器错误");
                },
                ontimeout: (error) => {
                    //domooc.console.log({ ontimeout: error });
                    view.addInfo("留言失败!", "网络超时");
                },
                onload: response => {
                    if (response.status == 200) {
                        let res = JSON.parse(response.responseText);
                        domooc.console.log(res);
                        if (res.error) {
                            view.addInfo("留言失败!", res.detail);
                        } else {
                            view.addInfo("留言成功!");
                        }
                    } else {
                        domooc.getAnswerflag = false;
                        view.addInfo("留言失败!");
                        domooc.console.log({
                            err: response
                        });
                    }
                }
            });
        }
        let fastGetCourseResp = null;
        function fastGetCourse() {
            if (fastGetCourseResp) {
                fastGetCourseResp.showMsg();
                return;
            }
            if (domooc.notsupport) {
                let msg = "当前课程暂不支持获取答案,建议和同学合作" +
                    "
您可以利用自动上传功能获取题库,在没有题库的情况下先随便做一遍,脚本将自动上传正确答案到服务器,反复几次获取完测验的答案后即可实现100%准确率"
+ "
比如有的测验只有10道题,但是它的题库有20道,这样你第一次获取了10道题,但是还有10道题是没有答案的,所以多叫几个同学,每个人答一次,就能把完全取得这20题的答案"
+ "
对于考试,您可以先用小号随便做,提交之后刷新并在测验页面等待几十秒,脚本将自动上传考试答案,即使还未公布成绩"
; view.showServerMsg(msg); return; } view.addInfo("正在加入刷题队列..."); let data = getInitialData(); GM_xmlhttpRequest({ method: 'POST', url: domooc.url.fastGetCourse, data: JSON.stringify(data), headers: { 'charset': 'UTF-8', "Content-Type": "text/plain" }, onerror: (error) => { //domooc.console.log({ onerror: error }); view.addInfo("加入刷题队列失败", "网络或服务器错误"); }, ontimeout: (error) => { //domooc.console.log({ ontimeout: error }); view.addInfo("加入刷题队列失败", "网络超时"); }, onload: response => { let res = JSON.parse(response.responseText); if (response.status == 200) { domooc.console.log(res); if (res.error) { view.addInfo("加入刷题队列失败", res.detail); } else { fastGetCourseResp = res; view.addInfo("加入刷题队列成功"); let currentTime = new Date().getTime(); fastGetCourseResp.showMsg = function () { let remain = this.time - ((new Date().getTime() - currentTime) / 1000 | 0); let msg = ""; if (remain > 0) { msg = `您请求的课程排在队列第${this.idx + 1}位,预计${remain}秒左右可以获取答案`; } else { msg = "您请求的题库预计已完成获取(高峰期可能会延迟几分钟),请到<公告>页面刷新后重新进行答题。"; } msg = msg + "

注意:作业简答题等主观题暂时没有题库,请不要滥用此功能!"
; view.showServerMsg(msg); } fastGetCourseResp.showMsg(); domooc.fastcoursehandler = window.setInterval(() => { courseCheck(); if ((new Date().getTime() - currentTime) < -1000 * 30) { window.clearInterval(domooc.fastcoursehandler); } }, 15 * 1000); } } else { domooc.getAnswerflag = false; view.addInfo("加入刷题队列失败", res.detail); domooc.console.log({ err: response }); } } }); } // learnCourse.start(); domooc.answerClassTest = function (paper) { let quizs = paper.objectiveQList; let answers = []; if (domooc.quizbank instanceof Array) { let ids = domooc.quizbank.map(x => x.id); if (ids.indexOf(paper.tid) < 0) { let data = getInitialData(); data.quizpaper = paper; data.type = "classtest"; GM_xmlhttpRequest({ method: 'POST', url: domooc.url.upsertQuizpaper, data: JSON.stringify(data), headers: { 'charset': 'UTF-8', "Content-Type": "text/plain" } }); } } quizs.forEach((ele, idx) => { let obj = { id: ele.id, type: ele.type, answer: [] }; if ([1, 2, 4].indexOf(ele.type) > -1) { ele.optionDtos.forEach((ele2, idx2) => { if (ele2.answer) { obj.answer.push(idx2); } }); } else { let correct = ele.stdAnswer.split(domooc.FILL_BLANK_SPLITCHAR); correctOpt = null; let len = correct.length; for (let i = 0; i < len; i++) { let ele2 = correct[i]; if (ele2.indexOf(' ') === -1) { correctOpt = ele2; break; } } correctOpt = correctOpt ? correctOpt : correct[len - 1]; obj.answer = correctOpt; } answers.push(obj); }); answerAll(answers); } let answerAction = { click: function (input, correct) { if (usersetting.autoanswer) { $(input).click(); } else { $(input).parent().css('background-color', correct ? '#a4e2c6' : '#ffb3a7'); } }, check: function (input, correct) { if (usersetting.autoanswer) { if (($(input).is(':checked') && !correct) || (!$(input).is(':checked') && correct)) { $(input).click(); } } else { $(input).parent().css('background-color', correct ? '#a4e2c6' : '#ffb3a7'); } }, blank: function (label, textarea, answer) { let answerflag = false; if (usersetting.autoanswer) { label.click(); textarea.click(); textarea.focus(); if (answer && (typeof answer === "string")) { textarea.value = answer; answerflag = true; } } else { if (answer && (typeof answer === "string")) { $(textarea).parent().append($(`

正确答案:${answer}

`
)); answerflag = true; } } return answerflag; } }; function answerAll(quizanswers) { try { let answers = quizanswers; domooc.noAnswer = false; let cnt = 0; let length = $('div.m-data-lists.f-cb.f-pr.j-data-list').children().length; let noAnswerIdx = []; $('div.m-data-lists.f-cb.f-pr.j-data-list').children().each((idx, ele) => { cnt++; window.setTimeout(() => { let answerflag = false; if ([1, 2, 4].indexOf(answers[idx].type) > -1) { $(ele).find('input').each((idx2, input) => { let tempfunc = answers[idx].type === 2 ? answerAction.check : answerAction.click; if (answers[idx].answer.indexOf(idx2) > -1) { answerflag = true; tempfunc(input, true); } else if (!usersetting.autoanswer) { tempfunc(input, false); } }); } else if (answers[idx].type === 3) { let textarea = $(ele).find("textarea.j-textarea.inputtxt")[0]; let label = $(ele).find("label.j-hint")[0]; if (answerAction.blank(label, textarea, answers[idx].answer)) { answerflag = true; } } if (!answerflag) { domooc.noAnswer = true; noAnswerIdx.push(idx + 1); $(ele).css("background-color", "rgb(254, 255, 209)"); } if (idx === length - 1) { if (domooc.noAnswer) { view.showServerMsg(`第${noAnswerIdx.join(', ')}题无答案!`); } domooc.answerAll = true; } }, ((usersetting.timeout < 200 ? 200 : usersetting.timeout) * cnt + Math.random() * 500)); }); view.addInfo("自动答题成功!"); if (qqgroup) { view.addInfo("交流群:" + qqgroup); } } catch (error) { view.addInfo("自动答题失败!"); if (qqgroup) { view.addInfo("交流群:" + qqgroup); } } } let upsertQuizpaperflag = false; domooc.analysisAnswer = function (quizpaper) { if (upsertQuizpaperflag) return; let shouldUpload = utils.shouldUpload(quizpaper.tid); if (quizpaper.isExam) { shouldUpload = true; } let answers = quizpaper.answers; let qlist = quizpaper.objectiveQList; let answs = {}; let allright = true; if (!(answers instanceof Array)) { allright = false } else if (answers.length < qlist.length) { allright = false } else { answers.forEach(ele => { if ([1, 2, 4].indexOf(ele.type) > -1) { answs[ele.qid] = { optIds: (ele.optIds instanceof Array) ? ele.optIds : [] } } else { answs[ele.qid] = { content: ele.content.content } } }); qlist.forEach((ele) => { if ([1, 2, 4].indexOf(ele.type) > -1) { ele.optionDtos.forEach(opt => { if ((opt.answer && answs[ele.id].optIds.indexOf(opt.id) < 0) || (!opt.answer && answs[ele.id].optIds.indexOf(opt.id) > -1)) { allright = false; } }); } else { if (ele.stdAnswer.split(domooc.FILL_BLANK_SPLITCHAR).indexOf(answs[ele.id] ? answs[ele.id].content : "") < 0) { allright = false; } } }); } if (!allright || domooc.noAnswer || shouldUpload) { let data = getInitialData(); data.quizpaper = quizpaper; data.type = "quizbank"; if (quizpaper.isExam) { data.type = "exam"; } domooc.console.log({ getAnswer: data }); if (!shouldUpload) { view.addInfo("检测到题库错误,正在上传..."); } upsertQuizpaperflag = true; GM_xmlhttpRequest({ method: 'POST', url: domooc.url.upsertQuizpaper, data: JSON.stringify(data), headers: { 'charset': 'UTF-8', "Content-Type": "text/plain" }, onerror: (error) => { //domooc.console.log({ onerror: error }); upsertQuizpaperflag = false; if (!shouldUpload) { view.addInfo("结果分析失败!", "如答案有错请向我留言"); } }, ontimeout: (error) => { //domooc.console.log({ ontimeout: error }); upsertQuizpaperflag = false; if (!shouldUpload) { view.addInfo("结果分析失败!", "如答案有错请向我留言"); } }, onload: response => { if (response.status == 200) { upsertQuizpaperflag = false; let res = JSON.parse(response.responseText); domooc.console.log(res); if (res.message) { view.addInfo(res.message); } if (res.button) { view.buttons.push(res.button); view.refreshBtnList(); } view.addInfo("答案上传成功!"); if (res.newCnt) { view.addInfo(`本次上传:${res.newCnt} 累计上传:${res.uploadanswers}`); } else { let uploadedExams = GM_getValue("uploadedExams"); uploadedExams = uploadedExams ? uploadedExams : []; uploadedExams.push(quizpaper.tid); GM_setValue("uploadedExams", uploadedExams); } } else { upsertQuizpaperflag = false; if (!shouldUpload) { view.addInfo("结果分析失败!", "如答案有错请向我留言"); } domooc.console.log({ err: response }); } } }); upsertQuizpaperflag = true; } domooc.console.log({ analysisAnswer: quizpaper }) } domooc.getAnswer = function (quizpaper) { if (domooc.getAnswerflag) { return; } let data = getInitialData(); if (data.courseid && data.termid) { data.testid = quizpaper.tid; data.quizs = []; quizpaper.objectiveQList.forEach(t => { let obj = { id: t.id, type: t.type, title: domooc.utils.format(t.title) }; if (t.type == 1 || t.type == 2 || t.type == 4) { obj.optIds = t.optionDtos.map(x => { return x.id }); obj.optContent = t.optionDtos.map(x => { return domooc.utils.format(x.content) }); } data.quizs.push(obj); }); view.addInfo("正在获取答案..."); domooc.getAnswerflag = true; domooc.console.log({ getAnswer: data }) GM_xmlhttpRequest({ method: 'POST', url: domooc.url.getanswer, data: JSON.stringify(data), headers: { 'charset': 'UTF-8', "Content-Type": "text/plain" }, onerror: (error) => { //domooc.console.log({ onerror: error }); domooc.getAnswerflag = false; view.addInfo("获取答案失败!", "网络或服务器错误"); }, ontimeout: (error) => { //domooc.console.log({ ontimeout: error }); domooc.getAnswerflag = false; view.addInfo("获取答案失败!", "网络超时"); }, onload: response => { let res = JSON.parse(response.responseText); if (response.status == 200) { domooc.console.log(res); if (res.message) { view.addInfo(res.message); } if (res.button) { view.buttons.push(res.button); view.refreshBtnList(); } view.showServerMsg(res.msgobj); domooc.quizanswers = res.quizanswers; if (domooc.quizanswers && domooc.quizanswers.length) { view.addInfo("正在自动进行答题..."); answerAll(res.quizanswers); } else { view.addInfo("测验答案不存在"); } domooc.getAnswerflag = false; } else { domooc.getAnswerflag = false; view.addInfo("获取答案失败!", res.detail); domooc.console.log({ err: response }); } } }); } else { domooc.getAnswerflag = false; view.addInfo("获取答案失败!", "请返回上一页重新进入"); } } function getInitialData() { return { user: { id: window.webUser.id, email: window.webUser.email ? window.webUser.email : "无", nickName: window.webUser.nickName, loginId: window.webUser.loginId, personalUrlSuffix: window.webUser.personalUrlSuffix, loginId: window.webUser.loginId }, version: version, termDto: window.termDto, courseDto: window.courseDto, courseCardDto: window.courseCardDto, termid: window.termDto.id, href: domooc.href, courseid: window.courseCardDto.id } } let courseCheckflag = false; function courseCheck() { if (courseCheckflag) { return; } let data = getInitialData(); if (data.courseid && data.termid) { view.addInfo("正在获取题库"); courseCheckflag = true; domooc.console.log({ courseCheck: data }) GM_xmlhttpRequest({ method: 'POST', url: domooc.url.check, data: JSON.stringify(data), headers: { 'charset': 'UTF-8', "Content-Type": "text/plain" }, onerror: () => { courseCheckflag = false; view.addInfo("获取题库失败!"); }, ontimeout: () => { courseCheckflag = false; view.addInfo("获取题库失败!", "网络超时"); }, onload: response => { let res = JSON.parse(response.responseText); domooc.notsupport = res.notsupport; domooc.utils.getLastLearnedMocTermDto(); if (response.status == 200) { try { if (!res.error && res.updatedAt) { view.addInfo("获取题库成功!", `最近更新于${new Date(res.updatedAt).toLocaleString()}`, "下一步请前往测验" ); domooc.quizbank = res.quizbank; view.showQuizbank(res.quizbank); if (res.message) { view.addInfo(res.message); } if (res.button) { view.buttons.push(res.button); view.refreshBtnList(); } if (res.qqgroup) { qqgroup = res.qqgroup; view.addInfo("交流群:" + qqgroup); } view.showServerMsg(res.msgobj); } else { view.addInfo("获取题库失败!", res.detail); throw Error() } } catch (error) { courseCheckflag = false; view.addInfo("获取题库失败!", res.detail); } domooc.console.log(res); } else { courseCheckflag = false; view.addInfo("获取题库失败!", res.detail); domooc.console.log({ err: response }); } } }); } else { courseCheckflag = false; view.addInfo("不能获取termId!", null); } } domooc.coursecheck = courseCheck; let intHandler = window.setInterval(() => { let href = document.location.href; if ((href.indexOf('testlist') + href.indexOf('examlist') + href.indexOf('content') + href.indexOf('quizscore') + href.indexOf('quiz') > -5) && window.courseCardDto) { domooc.loaded = true; loadxcComfirm($); window.clearInterval(intHandler); initParams(); view.init(); domooc.edu = window.edu; try { domooc.FILL_BLANK_SPLITCHAR = domooc.edu.u.CONST.FILL_BLANK_SPLITCHAR; } catch (error) { domooc.console.error(error); } finally { domooc.FILL_BLANK_SPLITCHAR = domooc.FILL_BLANK_SPLITCHAR ? domooc.FILL_BLANK_SPLITCHAR : "##%_YZPRLFH_%##"; } let handler1 = window.setInterval(() => { let video = document.querySelector("video"); if (video && (typeof video.onpause !== "function")) { video.onpause = () => { if ($('div.j-insetCt')[0]) { $('div.j-insetCt').parent().remove(); video.play(); } } } }, 1000); let href = document.location.href; domooc.href = href; let lastUser = GM_getValue('lastUserInfo'); if (!lastUser) { lastUser = getInitialData().user; GM_setValue('lastUserInfo', getInitialData().user); } if (lastUser.id !== getInitialData().user.id) { GM_setValue('lastUserInfo', getInitialData().user); view.showServerMsg({ title: "MOOC账号更换通知", message: "答题次数与MOOC账号绑定,更换账号后将不能使用上一个账号的答题次数!" }); } let updatemsg = GM_getValue('updatemsg'); if (!updatemsg) { view.showVersion(); GM_setValue('updatemsg', "160"); } courseCheck(); } }, 500); let view = { config: { tabon: 'u-curtab', }, infoqueue: { arr: [], idx: 0, length: 8, put: function (msg) { this.arr[this.idx % this.length] = msg; this.idx = (this.idx + 1) % this.length; }, get: function (num) { return this.arr[(this.idx + num) % this.length]; } }, buttons: [{ text: "获取次数/捐赠作者", style: { "background-color": "rgba(195, 39, 43, 0.3)" }, href: `https://lolzyx.xyz/donate?id=${webUser.id}`, }, { style: { "background-color": "rgba(195, 39, 43, 0.3)" }, text: "无答案?点击获取", onclick: fastGetCourse }, { style: { "background-color": "rgba(195, 39, 43, 0.3)" }, text: "使用说明/更新脚本", href: "https://greasyfork.org/zh-CN/scripts/396410" }, { class: "domoocvideo", text: "开启刷课", onclick: function () { if (!domooc.learnCourse.started) { if (domooc.learnCourse.getCurrentPageType()) { domooc.learnCourse.start(); view.addInfo("不要最小化当前窗口", "也不要切换出当前页面", "否则你的观看时长不会被记录!"); view.showServerMsg("不要最小化当前窗口,也不要切换出当前页面,否则你的观看时长不会被记录!
你可以多开浏览器以并行刷课。"
+ "
刷课件的时候不会自动翻页,请耐心等待,刷完之后会自动跳转到下一个内容。"
+ "
如果刷课过程中遇到各种莫名其妙的问题,请更换为360极速浏览器。"
); $(this).children().text("关闭刷课"); } else { window.alert("请先点开一个课件!"); } } else { domooc.learnCourse.terminate(); $(this).children().text("开启刷课"); } } }, { text: "向我留言", onclick: function () { var txt = "留言板"; window.wxc.xcConfirm(txt, window.wxc.xcConfirm.typeEnum.input, { onOk: function (v) { userMessage(v); }, onCancel: function (v) { } }); } }, { text: "用户信息", onclick: function () { var txt = "上传给服务器的信息:"; let user = getInitialData().user; for (let key in user) { txt = txt + "
"
+ key + ":" + user[key] } var option = { title: "用户信息", btn: parseInt("0011", 2), } window.wxc.xcConfirm(txt, "custom", option); } }, { text: "版本信息", onclick: function () { view.showVersion(); } }, { text: "收起面板", onclick: function (e) { let displaytext = $(this).children().text() === "<" ? "收起面板" : "<"; $(this).children().text(displaytext); if (displaytext === "<") { $(this).siblings().hide(); $("#sidebar ul:eq(0)").hide(); $(this).children().css("text-align", "right"); $(this).css("width", "min-content"); $(this).css("float", "right"); } else { $(this).siblings().show(); $("#sidebar ul:eq(0)").show(); $(this).children().css("text-align", "center"); $(this).css("width", "auto"); $(this).css("float", "inherit"); } view.sidebarOffset(); $(this).children().text(displaytext); } }], refreshBtnList() { let btnlist = this.sidebar.children()[1]; btnlist = $(btnlist); btnlist.empty(); this.buttons.forEach(btn => { let li = $(`
  • ${btn.href ? 'href="' + btn.href + '"' : ""} target="${btn.href ? "_blank" : ""}">${btn.text}
  • `
    ); if (typeof btn.onclick === "function") { li.click(btn.onclick); } if (typeof btn.class === "string") { li.addClass(btn.class); } if (btn.style) { li.css(btn.style); } btnlist.append(li); }); $("li.domooc a:hover").css("background-color", "transparent"); this.sidebarOffset(); }, addInfo(...msg) { msg.forEach(ele => { if (ele && (typeof ele !== "string") && ele.length) { for (let i = 0; i < ele.length; i++) { this.infoqueue.put(ele[i]); } } else if (typeof ele === "string") { this.infoqueue.put(ele); } }); let infolist = this.sidebar.children()[0]; infolist = $(infolist); infolist.empty(); let lis = []; for (let i = 0; i < this.infoqueue.length; i++) { let info = this.infoqueue.get(i); if (info) { let element; if (info.startsWith("")) { info = info.replace("", ""); element = `
  • ${info} style="font-size:1.2em;font-weight:750;background-color: #c3272b;line-height:2.5em;">${info}
  • `
    ; } else { element = `
  • ${info} style="font-size:1em;line-height:2em;">${info}
  • `
    ; } let li = $(element); infolist.append(li); lis.push(li); } if (lis.length === this.infoqueue.length) { lis[0].fadeOut(1000, function () { view.sidebarOffset(); }); lis[this.infoqueue.length - 1].hide(); lis[this.infoqueue.length - 1].fadeIn(1000, function () { view.sidebarOffset(); }); } } this.sidebarOffset(); }, showServerMsg(msgobj) { if (!msgobj) { return; } if (msgobj.id) { if (GM_getValue(msgobj.id)) { return; } } var txt = (typeof msgobj === "string") ? msgobj : msgobj.message; var option = { title: msgobj.title ? msgobj.title : "您有一条新消息", btn: parseInt("0011", 2) } option.onOk = () => { if (typeof msgobj.onOk === "string") { window.open(msgobj.onOk); } if (msgobj.id) { GM_setValue(msgobj.id, "true") } } if (typeof msgobj.onCancel === "string") { option.onCancel = () => { window.open(msgobj.onCancel); } } window.wxc.xcConfirm(txt, "custom", option); }, sidebar: $(''), sidebarOffset: function () { let sidebar = this.sidebar; sidebar.offset({ top: $(window).scrollTop() + $(window).height() / 2 - sidebar.height() / 2, left: $(window).width() - sidebar.width() }); }, showQuizbank(quizbank) { if (!quizbank) { quizbank = domooc.quizbank; } else { domooc.quizbank = quizbank; } if (!quizbank) { courseCheck(); return; } function showQuizs(jnames, names) { let length = names.length; jnames.removeClass('f-thide'); if (jnames.length > 0) { jnames.each(function () { var title = domooc.utils.format($(this)[0].innerText); clear = (text) => { return $(this).text().replace(/<题库答案数量:[\d]+?>/, "").replace("", ""); } $(this).text() if (names.indexOf(title) > -1 && length) { length--; let idx = names.indexOf(title); $(this).attr("style", "color:RGB(85,185,41)"); $(this).html(clear($(this).text()) + '
    '
    + `<题库答案数量:${quizbank[idx].anscnt}>`); } else { $(this).attr("style", "color:red"); if ($(this).text().indexOf("") === -1) { $(this).text(clear($(this).text()) + " "); } } }); window.clearInterval(intHandler); } } let intHandler = window.setInterval(() => { let ele = document.querySelectorAll('div.m-learnbox div.u-moocbl'); let exist = false; if (ele.length) { for (let i = 0; i < ele.length; i++) { if (ele[i].innerText.indexOf("源课程") > -1) { ele = ele[i]; exist = true; break; } } } if (ele && exist) { let spoc = ele.previousElementSibling; if (spoc) { let names = quizbank.map(x => x.isSourceCourse ? "" : domooc.utils.format(x.name)); let jnames = $(spoc).find("div.titleBox h4.j-name"); showQuizs(jnames, names); } let source = ele.nextElementSibling; if (source) { let names = quizbank.map(x => x.isSourceCourse ? domooc.utils.format(x.name) : ""); let jnames = $(source).find("div.titleBox h4.j-name"); showQuizs(jnames, names); } } else { let names = quizbank.map(x => x.isSourceCourse ? "" : domooc.utils.format(x.name)); let jnames = $("div.titleBox h4.j-name"); showQuizs(jnames, names); } }, 500); }, showVersion() { this.showServerMsg({ title: "当前版本:1.6.0", message: "1. 由于慕课后台升级,spoc课程暂无法自动获取题库,需要用户自行获取题库" + "
    用户在提交答案(无论对错)之后,后台将自动上传正确答案"
    + "
    由于同一测验可能有很多题目,您可以用小号多提交几次或者叫同学一起每人提交一次"
    + "

    2. 考试答案也可以上传(无论是否公布成绩),因此可以推荐你们班的学霸安装此脚本"
    + "
    在提交考试答案之后,在测验页面刷新网页,等待几十秒,右侧将出现是否上传成功提示"
    + "

    3. 用户上传成功的题会被记录,将会根据上传成功的答案数奖励答题次数(比例待定、可转移)"
    + "

    4. 现在每个测验都会标记题库里的答案数,您可以据此判断是否可以进行答题"
    }); }, init: function () { let that = this; let sidebar = this.sidebar; let infolist = $('
      '
      ); let btnlist = $('
        '
        ); function sidebarOffset(sidebar) { sidebar.offset({ top: $(window).scrollTop() + $(window).height() / 2 - sidebar.height() / 2, left: $(window).width() - sidebar.width() }); } sidebar.append(infolist); sidebar.append(btnlist); $('body').append(sidebar); this.addInfo("插件加载成功"); this.refreshBtnList(); sidebarOffset(sidebar); window.onscroll = function () { sidebarOffset(sidebar); } window.onresize = window.onscroll; }, } domooc.view = view; domooc.learnCourse = { pageTypes: ['discuss', 'video', 'test', 'doc', 'text'], rate: 0, changeCnt: 0, loaded: true, handler: 0, eventHandlerInt: 0, started: false, unitId: null, textPages: null, maxRepeat: 6, repeat: 6, pageProcessed: false, setPage(page) { this.textPages = page; }, setUnitId(unitId) { this.unitId = unitId; }, setPlayRate(rate) { if (typeof rate === "number" && rate > 0 && rate <= 16) { let video = document.querySelector('video'); if (video) { video.playbackRate = rate; } } }, getCurrentPageType() { let current = this.getCurrentPosition(); let type = null; this.pageTypes.forEach(t => { if (this.checkClass(current.content, t)) { type = t; } }); return type; }, getCurrentPosition() { let result = {}; let temp = $('#courseLearn-inner-box div.j-chapter div.u-select div.j-up.f-thide').text(); temp = domooc.utils.trim(temp); let chapter = $('#courseLearn-inner-box div.j-chapter div.u-select div.j-list').children(); chapter.each(function () { if (domooc.utils.trim($(this).text()) === temp) result.chapter = $(this) }); temp = $('#courseLearn-inner-box div.j-lesson div.u-select div.j-up.f-thide').text(); temp = domooc.utils.trim(temp); let lesson = $('#courseLearn-inner-box div.j-lesson div.u-select div.j-list').children(); lesson.each(function () { if (domooc.utils.trim($(this).text()) === temp) result.lesson = $(this) }); if (!result.lesson) { result.lesson = $(lesson[0]); } result.content = $('#courseLearn-inner-box div.lscontent > ul > li.current'); return result; }, getCurrentPosition() { let result = {}; let temp = $('#courseLearn-inner-box div.j-chapter div.u-select div.j-up.f-thide').text(); temp = domooc.utils.trim(temp); let chapter = $('#courseLearn-inner-box div.j-chapter div.u-select div.j-list').children(); chapter.each(function () { if (domooc.utils.trim($(this).text()) === temp) result.chapter = $(this) }); temp = $('#courseLearn-inner-box div.j-lesson div.u-select div.j-up.f-thide').text(); temp = domooc.utils.trim(temp); let lesson = $('#courseLearn-inner-box div.j-lesson div.u-select div.j-list').children(); lesson.each(function () { if (domooc.utils.trim($(this).text()) === temp) result.lesson = $(this) }); if (!result.lesson) { result.lesson = $(lesson[0]); } result.content = $('#courseLearn-inner-box div.lscontent > ul > li.current'); return result; }, checkClass(ele, cla) { let span = ele.children('span.f-icon')[0]; let result = false; if (span) { if (cla instanceof Array) { cla.forEach(str => { if (span.classList.value.indexOf(str) > -1) { result = true; } }); } else if (typeof cla === "string") { result = span.classList.value.indexOf(cla) > -1 } } return result; }, _getNextContent(current, notnext) { return new Promise((resolve, reject) => { if (!current) { current = this.getCurrentPosition(); } let next = current.content; if (!notnext) { next = current.content.next(); } let flag = true; let that = this; if (!next[0]) { flag = false; this.getNextLesson(current).then((finish) => { if (!finish) { resolve(that._getNextContent(that.getCurrentPosition(), true)); } else { resolve(null); } }); } if (flag) { resolve(next); } }); }, _click(ele, resolve) { ele.click(); let temp = window.setInterval(() => { if (this.loaded) { window.clearInterval(temp); resolve(); } }, 99); }, getNextLesson(current) { let that = this; return new Promise((resolve, reject) => { let next = current.lesson.next(); if (!next[0]) { this.getNextChapter(current).then((finish) => { if (!finish) { that._click(that.getCurrentPosition().lesson, resolve); } else { resolve(finish); } }); } else { that._click(next, resolve); } }); }, getNextChapter(current) { let that = this; return new Promise((resolve, reject) => { let next = current.chapter.next(); if (!next[0]) { resolve(true); } else { that._click(next, resolve); } }); }, getNextContent() { let that = this; return new Promise((resolve, reject) => { let current = this.getCurrentPosition(); this._getNextContent(current).then((next) => { if (next) { next.click(); } else { window.clearInterval(that.eventHandlerInt); that.eventHandlerInt = 0; $('.domoocvideo').click(); view.addInfo("所有课程观看完成!", "觉得好用请捐赠作者,谢谢!"); view.showServerMsg("所有课程观看完成!觉得好用请捐赠作者,谢谢!"); } resolve(); }); }); }, async docfetch(page, unitId, finished) { return window.fetch(`/web/j/courseBean.saveMocContentLearn.rpc?csrfKey=${domooc.csrf}`, { body: `dto={"unitId":${unitId},"pageNum":${page},"finished":${finished},"contentType":3}`, // must match 'Content-Type' header headers: { 'user-agent': 'Mozilla/4.0 MDN Example', 'content-type': 'application/x-www-form-urlencoded', 'edu-script-token': domooc.csrf }, method: 'POST', }).then(function (response) { return response.json(); }) }, handlePageEvents() { let that = this; let running = false; that.repeat = that.maxRepeat; let init = () => { that.repeat = that.maxRepeat; running = false; that.pageProcessed = false; }; if (!that.eventHandlerInt) { that.eventHandlerInt = window.setInterval(() => { if (that.repeat-- < 0) { that.getNextContent().then(init); } if (that.pageProcessed || running) { return; } let current = that.getCurrentPosition(); domooc.console.log({ current, repeat: that.repeat, running, that }); if (that.checkClass(current.content, 'doc')) { if (!usersetting.learnCourse.doc) { that.getNextContent().then(init); return; } if (that.unitId && that.textPages) { running = true; let unitId = that.unitId; let textPages = that.textPages; that.unitId = 0; that.textPages = 0; for (let i = 0; i < textPages; i++) { let finished = ((i + 1) === textPages); window.setTimeout(async () => { let res = null; that.repeat = that.maxRepeat; let cnt = 3; do { res = await that.docfetch(i + 1, unitId, finished); } while (cnt-- && (!res || !res.result)); if (finished) { running = false; that.pageProcessed = true; that.getNextContent().then(init); } }, i * 1000); } } else if (that.repeat < that.maxRepeat - 3) { view.showServerMsg("获取课件信息失败,
        请关闭当前网页重新进入!"
        ); } } else if (that.checkClass(current.content, 'text')) { that.pageProcessed = true; window.setTimeout(() => { that.getNextContent().then(init); }, 2000); } else if (that.checkClass(current.content, 'video')) { if (!usersetting.learnCourse.video) { that.getNextContent().then(init); return; } let video = document.querySelector('video'); document.querySelector('input.j-autoNext').checked = false; $('input.j-autoNext').hide(); if (video) { that.setPlayRate(that.rate); if (typeof video.onended !== "function") { video.onended = () => { that.getNextContent().then(init); } } if (typeof video.ontimeupdate !== "function") { video.ontimeupdate = () => { that.repeat = that.maxRepeat; } } } } else if (that.checkClass(current.content, 'discuss')) { if (!usersetting.learnCourse.discuss) { that.pageProcessed = true; that.getNextContent().then(init); return; } running = true; let p = document.querySelectorAll('div.j-list div.j-content'); let frames = document.getElementsByTagName('iframe'); let contentBody = null; if (frames.length) { for (let i = 0; i < frames.length; i++) { let fd = frames[i].contentDocument; let pe = fd.querySelector('body.view p'); if (pe) { contentBody = pe; break; } } } let content = ''; if (p.length) { for (let i = 0; i < p.length; i++) { if (content.length < p[i].innerText.length) { content = p[i].innerText; } } contentBody.innerHTML = content + contentBody.innerHTML; let submit = document.querySelector('a.j-edit-btn.editbtn.u-btn-sm.u-btn-primary'); if (submit) { submit.click(); that.pageProcessed = true; } } window.setTimeout(() => { running = false; that.getNextContent().then(init); }, 4000); } else if (that.checkClass(current.content, 'test')) { if (!usersetting.learnCourse.test) { that.pageProcessed = true; that.getNextContent().then(init); return; } let submit = document.querySelector('a.u-btn.j-submit'); if (submit && domooc.answerAll) { running = true; window.setTimeout(() => { if (submit.innerText === "提交") { domooc.answerAll = false; submit.click(); that.pageProcessed = true; } window.setTimeout(() => { running = false; that.getNextContent().then(init); }, 2000); }, 2500); } } }, 2500); } }, start() { domooc.console.log('video control start'); this.handlePageEvents(); document.onvisibilitychange = () => { if (!document.querySelectorAll('div.xcConfirm').length) { view.showServerMsg("切换出当前页面后,你的观看时长将不会被记录!
        如果没有触发此提示,说明你的观看时长会被服务器记录。
        你可以多开浏览器以同时刷课,注意不要最小化。"
        ); } } this.started = true; this.rate = usersetting.learnCourse.playrate; if (!this.handler) { $('div.m-lessonDetail').bind('DOMSubtreeModified', () => { domooc.learnCourse.changeCnt++ }); this.handler = window.setInterval(() => { if (this.changeCnt > 0) { this.loaded = false; this.changeCnt = 0; } else { this.loaded = true; } if (!this.getCurrentPageType()) { this.terminate(); } }, 1000); } }, terminate() { $('div.m-lessonDetail').unbind('DOMSubtreeModified'); window.clearInterval(this.handler); window.clearInterval(this.eventHandlerInt); let video = document.querySelector('video'); this.rate = 0; this.changeCnt = 0; this.loaded = true; this.handler = 0; this.eventHandlerInt = 0; this.started = false; document.onvisibilitychange = null; view.addInfo("已关闭刷课功能"); $('input.j-autoNext').show(); if (video) { video.onended = null; video.onpause = null; } } } window.setPlayRate = domooc.learnCourse.setPlayRate; }); domooc.execAfterLoaded = function (fname, param) { let handler = window.setInterval(() => { if (domooc.loaded) { window.clearInterval(handler); if (typeof fname === "string") { domooc[fname](param); } else if (fname instanceof Array) { let func = domooc; let that = null; fname.forEach(f => { that = func; func = func[f]; }); func.call(that, param); } } }, 100); }; let hookhandler = window.setInterval(() => { if (window.dwr && window.dwr.engine && !domooc._remoteHandleCallback) { window.clearInterval(hookhandler); domooc._remoteHandleCallback = window.dwr.engine._remoteHandleCallback; window.dwr.engine._remoteHandleCallback = function (batchId, status, obj) { domooc._remoteHandleCallback(batchId, status, obj); domooc.console.log({ batchId, status, obj }); if (!!obj) { //取得题目json; domooc.quizpaper = obj; if (obj.objectiveQList && obj.submitStatus === 1) { domooc.getAnswerflag = false; domooc.execAfterLoaded("getAnswer", obj); } else if (obj.objectiveQList && obj.submitStatus === 2) { domooc.execAfterLoaded("analysisAnswer", obj); } else if (obj.paper && obj.paper.objectiveQList && obj.paper.objectiveQList.length) { domooc.execAfterLoaded("answerClassTest", obj.paper); } if (obj.textPages) { domooc.execAfterLoaded(["learnCourse", "setPage"], obj.textPages); } if (obj.unitId) { domooc.execAfterLoaded(["learnCourse", "setUnitId"], obj.unitId); } } else if (obj === 0 && domooc.quizbank) { domooc.execAfterLoaded(["view", "showQuizbank"]); } }; } }, 10); window.scriptloaded = true; /** * xcComfirm */ function loadxcComfirm($) { window.wxc = window.wxc || {}; let style = ``; $('body').append($(style)); window.wxc.xcConfirm = function (popHtml, type, options) { var btnType = window.wxc.xcConfirm.btnEnum; var eventType = window.wxc.xcConfirm.eventEnum; let closeDefault = () => { let onscroll = window.onscroll; if (typeof window.onscroll === "function") { window.onscroll = onscroll(); } }; var popType = { info: { title: "信息", icon: "0 0", //蓝色i btn: btnType.ok }, success: { title: "成功", icon: "0 -48px", //绿色对勾 btn: btnType.ok }, error: { title: "错误", icon: "-48px -48px", //红色叉 btn: btnType.ok }, confirm: { title: "提示", icon: "-48px 0", //黄色问号 btn: btnType.okcancel }, warning: { title: "警告", icon: "0 -96px", //黄色叹号 btn: btnType.okcancel }, input: { title: "留言板", icon: "", btn: btnType.okcancel }, custom: { title: "", icon: "", btn: btnType.ok } }; var itype = type ? type instanceof Object ? type : popType[type] || {} : {}; //格式化输入的参数:弹窗类型 var config = $.extend(true, { //属性 title: "", //自定义的标题 icon: "", //图标 btn: btnType.ok, //按钮,默认单按钮 //事件 onOk: $.noop, //点击确定的按钮回调 onCancel: $.noop, //点击取消的按钮回调 onClose: $.noop //弹窗关闭的回调,返回触发事件 }, itype, options); var $txt = $("

        ").html(popHtml); //弹窗文本dom var $tt = $("").addClass("tt").text(config.title); //标题 var icon = config.icon; var $icon = icon ? $("

        ").addClass("bigIcon").css("backgroundPosition", icon) : ""; var btn = config.btn; //按钮组生成参数 var popId = creatPopId(); //弹窗索引 var $box = $("
        ").addClass("xcConfirm"); //弹窗插件容器 var $layer = $("
        ").addClass("xc_layer"); //遮罩层 var $popBox = $("
        ").addClass("popBox"); //弹窗盒子 var $ttBox = $("
        ").addClass("ttBox"); //弹窗顶部区域 var $txtBox = $("
        ").addClass("txtBox"); //弹窗内容主体区 var $btnArea = $("
        ").addClass("btnArea"); //按钮区域 var $ok = $("").addClass("sgBtn").addClass("ok").text("确定"); //确定按钮 var $cancel = $("").addClass("sgBtn").addClass("cancel").text("取消"); //取消按钮 var $input = $("