EWT Killer Box

1.32倍开启测试,限制改为1-32. 2.增强跳课稳定性.

当前为 2023-07-22 提交的版本,查看 最新版本

// ==UserScript==
// @name         EWT Killer Box
// @namespace    EWTKILL
// @version      1.0.3
// @description    1.32倍开启测试,限制改为1-32. 2.增强跳课稳定性.
// @author       bash@startup
// @connect      *
// @license      GPL2
// @match        https://web.ewt360.com/mystudy/
// @match        https://teacher.ewt360.com/ewtbend/bend/index/index.html
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @require      https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js
// @require      https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/core.js
// @require      https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/hmac.js
// @require      https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/sha1.js
// ==/UserScript==

//代码写的太乱了,太难以维护了

const GET_USER_URL = "https://gateway.ewt360.com/api/usercenter/user/login/getUser?platform=1";
const DAY_URL = "https://gateway.ewt360.com/api/homeworkprod/homework/student/studentHomeworkDistribution";
const HOMEWORK_URL = "https://gateway.ewt360.com/api/homeworkprod/homework/student/getStudentHomeworkInfo";
const SCHOOL_URL = "https://gateway.ewt360.com/api/eteacherproduct/school/getSchoolUserInfo";
const COURSE_URL = "https://gateway.ewt360.com/api/homeworkprod/homework/student/pageHomeworkTasks";
const GET_LESSON_DETAIL_URL = "https://gateway.ewt360.com/api/homeworkprod/player/getLessonDetail";
const LESSON_HOMEWORK_URL = "https://gateway.ewt360.com/api/homeworkprod/player/getPlayerLessonConfig";
const HOMEWORK_DOING_URL = "https://web.ewt360.com/mystudy/#/exam/answer/?paperId={%s}&bizCode=204&platform=1"
const COURSE_BATCH_URL = "https://bfe.ewt360.com/monitor/web/collect/batch?TrVideoBizCode=1013&TrFallback=0&TrUserId={userId}&TrUuId={uuid}&TrLessonId={lessonid}&sdkVersion={sdkVersion}&_={timestamp}";
const HMAC_SECRET_ID_URL = "http://bfe.ewt360.com/monitor/hmacSecret?userId={%s}"
const HOMEWORK_GET_ANSWER_URL = "https://web.ewt360.com/customerApi/api/studyprod/web/answer/webreport?reportId={reportid}&bizCode={bizCode}&platform=1"
const HOMEWORK_INFO_URL = "https://web.ewt360.com/customerApi/api/studyprod/web/answer/report?&platform=1&isRepeat=1&paperId={paperId}&bizCode={bizCode}"
const SUBMIT_ANSWER_URL = "https://web.ewt360.com/customerApi/api/studyprod/web/answer/submitanswer"
const MISSION_INFO_URL = "https://gateway.ewt360.com/api/homeworkprod/homework/student/studentHomeworkSummaryInfo?sceneId=0&homeworkId={hid}&schoolId={sid}"
const QUES_PARSE_URL = "https://web.ewt360.com/customerApi/api/studyprod/web/answer/simple/question/info";
const SCHOOL_COURSE_URL = "https://gateway.ewt360.com/api/netschool/sbrvideo/listVideoInfoById";

let header = {
                "Origin": "https://web.ewt360.com",
                "Referer": "https://web.ewt360.com/mystudy/"
            };

let headerCourse = {
    "Origin": "https://teacher.ewt360.com",
    "Referer": "https://teacher.ewt360.com/",
    "Referurl" : "https://teacher.ewt360.com/ewtbend/bend/index/index.html#/homework/play-videos"
};

let headerCourseWithToken = headerCourse;

let headerJump = {
    "Origin": "https://teacher.ewt360.com",
    "Referer": "https://teacher.ewt360.com/",
    "Host": "bfe.ewt360.com",
    "Accept-Encoding": "gzip,deflate,br",
    "Accept": "*/*",
    "Content-Type": "application/json; charset=utf-8"
}

let style = `
#close-btn {
    font-size: 12px;
    height: 16px;
    width: 16px;
    border-radius: calc(50%);
    background-color: red;
    margin-right: 0;
    font-weight: bolder;
    display: flex;
    align-items: center;
    justify-content: center;
}

#close-btn:hover > .close-btn-label {
    display: flex;
    align-items: center;
    justify-content: center;
}

#close-btn > .close-btn-label {
    display: none;
}

.kewt-tscol-right {
    margin-left: auto;
    margin-right:5px;
    text-align: right;
}

#window-main {
    border-radius: 10px;
    width: 600px;
    max-height: 600px;
    opacity: 0;
    margin-bottom: 100px;
    background-color: white;
    position: relative;
}

#window-bg {
    position:fixed;
    top:0;
    left:0;
    width:100%;
    height:100%;
    background-color:rgb(128,128,128,0.6);
    z-index:99999;
    display:flex;
    align-items: center;
    justify-content: center;
}

.kewt-course-text,.kewt-homework-text {
    font-size: 25px;
    font-weight: bolder;
}

.kewt-window-nav {
    position: relative;
    width:100%;
    padding-left: 10px;
    padding-right: 10px;
    padding-top: 5px;
    padding-bottom: 0;
    display: flex;
    align-items: center;
}

.kewt-tscol {
    line-height: 14px;
}

.kewt-subject {
    font-size: 12px;
    color:gray;
    scale: 0.9;
    transform-origin: 0 100%;
}

.kewt-subject-right {
    transform-origin: 100% 50%;
}

.kewt-title {
    font-weight: bolder;
}

.kewt-window-body {
    width:100%;
    padding:10px;
    overflow-y: auto;
}

.kewt-subject {
    font-size:12px;
}

.kewt-course-detail,.kewt-homework-detail {
    line-height: 15px;
    margin-top: 1px;
}

.kewt-course-col,.kewt-homework-col {
    color: #666;
    scale:0.85;
    transform-origin: 0 50%;
}

.kewt-course-funcbtns {
    margin-top: 5px;
    display: flex;
    align-items: cent6er;
}

.kewt-common-btn {
    font-size: 12px;
    padding: 5px 15px;
    background-color: #ca0404;
    color: white;
    border-radius: 5px;
    transition: background-color 200ms;
    margin-right: 20px;
    box-shadow: 0 0 5px gray;
    display: inline-block;
}

.kewt-course-top,.kewt-homework-top {
    margin-top: 7px;
}

.kewt-log-box {
    width: 100%;
    padding: 7px;
    border-radius: 5px;
    line-height: 15px;
    font-size: 12px;
    box-shadow: 0 0 5px black;
    overflow-y: auto;
}

#kewt-logbox-0 {
    margin-top: 10px;
}

.btn-red {
    background-color: #ca0404;
    color:white;
}

.btn-red:hover {
    background-color: #a20101;
}

.btn-green {
    color: white;
    background-color: green;
}

.btn-green:hover {
    background-color: #025c02;
}

.btn-yellow {
    background-color: orange;
}

.btn-yellow:hover {
    background-color: #b97800;
}

.btn-unclick {
    background-color: gray;
}

.kewt-course-container {
    margin-top:5px;
    height:200px;
    display:flex;
}

.kewt-course-c-left {
    width:25%;
    border-radius: 5px;
    background-color: rgba(0,0,0,0);
    box-shadow: 0 0 5px 1px gray;
    box-sizing: border-box;
    padding:10px 0;
    margin-right: 10px;
    overflow-y: auto;
}

.kewt-course-c-right {
    flex: 1;
    box-shadow: 0 0 5px 1px gray;
    border-radius: 5px;
    overflow-y:auto;
    box-sizing: border-box;
    padding:5px;
}

.kewt-course-l-date {
    padding:5px;
    width:100%;
    font-weight:bolder;
}

.kewt-course-l-date-sel {
    background-color: #0aa5ff;
    color:white;
}

.kewt-course-c-right-ele {
    display: flex;
    padding: 5px;
    margin-bottom: 3px;
    width:100%;
    background-color: #87838365;
    border-radius: 5px;
    transition: background-color 200ms;
    box-sizing:border-box;
}

.kewt-course-c-right-ele:hover {
    background-color: #6b5a5a65;
}

.kewt-cci-i {
    width:70px;
    height:45px;
}

.kewt-cci-title {
    font-size: 13px;
    font-weight:bolder;
}

.kewt-course-c-info {
    margin-left: 5px;
    display:flex;
    flex-direction: column;
    flex: 1;
}

.kewt-course-c-major {
    margin-top: 3px;
    flex: 1;
    display: flex;
}

.kewt-mission-fn-btn {
    color:white;
    padding: 5px 10px;
    display: inline-block;
    border-radius: 5px;
    font-size: 12px;
    margin-top: auto;
    margin-bottom: 0;
    margin-left: auto;
    margin-right:0;
    scale: 0.75;
    transform-origin: 100% 100%;
}

.kewt-course-wfunc {
    margin-top: 5px;
    display: flex;
}

.kewt-cci-id {
    margin-top: 5px;
    font-size:12px;
    scale:0.9;
    transform-origin: 0% 50%;
    color: gray;
}

.kewt-course-c-img {
    display:flex;
    align-items: center;
    justify-content: center;
}

.kewt-homework-container {
    margin-top: 5px;
    max-height: 350px;
    border-radius: 5px;
    box-shadow:0 0 5px 1px gray;
    padding: 5px;
    box-sizing: border-box;
    overflow-y: auto;
}

.kewt-ques-container,.ques-answer-container {
    padding: 5px;
    box-shadow: border-box;
    box-shadow:0 0 3px 1px gray;
}

.ques-answer-container {
    margin-top: 10px;
}

.kewt-ques-container {
    margin-bottom: 10px;
}

.ques-status-bar {
    display: flex;
    width: 100%;
    align-items: center;
}

.ques-c-info {
    margin-left: 7px;
}

.orange-container,.red-container,.blue-container {
    height:15px;
    border-radius: 8px;
    font-size: 12px;
    color: white;
    padding: 8px 12px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.orange-container {
    background-color: orange;
}

.red-container {
    background-color: #d52727;
}

.blue-container {
    background-color: #00ff9db0;
    color: black;
}

.ques-options-choice-dot,.ques-options-choice-dot-heart{
    height: 25px;
    width: 25px;
    border-radius: 50%;
    font-size: 15px;
    display: flex;
    justify-content: center;
    align-items: center;
    border: 1px solid purple;
}

.ques-options-choice-dot-heart {
    background-color: purple;
    font-weight: bolder;
    color: white;
}

.ques-option-content {
    margin-left: 4px;
    flex:1;
}

.ques-options-option {
    padding: 3px;
    margin: 2px 0;
    border: 1px solid black;
    border-radius: 5px;
    display: flex;
    align-items: center;
}

.ques-opt-container {
    font-size: 20px;
    font-weight: bolder;
    margin-top: 5px;
    margin-bottom: 5px;
}

.ques-opt-container-title-up {
    margin-top: 0;
    margin-bottom: 0;
}
.ques-parse-container {
    font-size: 12px;
    line-height: 15px;
}

.loading {
    display: flex;
    padding: 10px 10px;
    box-shadow: 0 0 2px gray;
    background-color: white;
    font-size: 20px;
    font-weight: bolder;
    border-radius: 5px;
    opacity: 0;
    marginBottom: 100px;
    width: 600px;
    flex-direction:column;
    align-items: center;
    box-sizing: border-box;
}

.load-tips {
    font-size: 12px;
    color: gray;
    text-align:center;
}

.load-error-comp {
    width: 100%;
    margin-top: 5px;
    border-radius: 5px;
    border: 3px solid red;
    padding: 5px 8px;
    box-sizing: border-box;
    font-size: 15px;
    font-weight: normal;
    line-height: 17px;
}

.circle-dot {
    height: 20px;
    width: 20px;
    border-radius: 50%;
    border: 2px solid #c10b0b;
    background-color: red;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: bolder;
    color: white;
}

.err-title {
    font-size: 15px;
    font-weight: bolder;
}

.load-error-msg-title {
    display: flex;
    align-items: center;
}

.speed-input {
    height: 16px;
    border: 1px solid black;
    border-radius: 5px;
    font-size: 12px;
    outline-style: none;
    padding: 5px 0;
    width:45px;
    text-align: center;
    margin-left: 5px;
}

.kewt-course-speed {
    display: flex;
    align-items: center;
}
`;

let basicUserInfo = undefined;
let CourseSideBarCanClick = true;
let ip = "";

(function() {'use strict';
class LogSystem {
    constructor() {
        this.dic = {
            0: "[Message]",
            1: "[Warning]",
            2: "[Error]",
            3: "[Fatal]"
        }
    }

    info(text) {
        return this.info(0,text)
    }

    info(level,text) {
        console.log(this.dic[level] + " "+text);
        return this.dic[level] + " "+text;
    }

    async upload(level,text) {
        let url = "http://ap-guangzhou.cls.tencentcs.com/track?topic_id=366f597e-ce5a-4b8d-90bd-ee084e1dff17"
        url += "&usertk="+String(getUserTk())+"&level=5"+"&msg="+String(this.info(level,text))
        try {
           await request("GET",url)
           this.info(1,"日志上传成功.")
        } catch {
            this.info(1,"日志上传失败.")
        }
    }

    uploadWithUserId(level,text) {
        this.upload(level,"id为"+basicUserInfo["data"]["userId"]+"的用户"+text)
    }

    put(id,text) {
        let component = $("#"+id);
        if(component!=undefined) component.append($("<div>"+new Date().toLocaleTimeString()+" "+text+"</div>"));
    }
}

let logSystem = new LogSystem();
let courseTags = {
    "课程讲": {
        "method": getCourseInfo,
        "lessonid": "lessonId",
        "courseid": "courseId",
        "videoType": 1
    },
    "校本视频": {
        "method": getSchoolClassInfoUrl,
        "lessonid": "id",
        "courseid": "id",
        "videoType": 6
    }
}

const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay))

async function renderGUI() {
    headerCourseWithToken["token"] = getUserTk();
    await preRender();
    renderGuiOnListAndCourse()
    renderGuiOnPractisePage();
}

async function preRender() {
    GM_addStyle(style);
    
    basicUserInfo = await getBasicUserInfo()
    let schoolInfo = await getSchoolInfo();
    basicUserInfo["data"]["schoolId"]=schoolInfo["data"]["schoolId"];
}

function renderBackground() {
    let rootE = $("#app").length!=0 ? $("#app") : $($(".mst-ewt-common-header")[0]);
    let bg = $("<div id='window-bg'></div>");
    let loading = $("<div class='loading'>同学,请耐心等待亿下,正在狠命加载窗口中...</div>");
    loading.append("<span class='load-tips'>如果长时间卡在这个界面,请尝试刷新并重新打开工具箱!</span>")
    bg.append(loading)
    rootE.append(bg)
    const windowAnimation = loading.animate({opacity:1,marginBottom: "-=100px"},200);
}

function insertErrorMsg(msg) {
    let errorbox = $("<div class='load-error-comp'></div>");
    errorbox.append("<div class='load-error-msg-title'><div class='circle-dot' style='margin-right: 5px'>E</div><div class='err-title'>Oops,EWT Killer 程序挂了!</div></div>")
    errorbox.append("<div style='font-size: 12px'>程序临死前的遗言:"+msg+".</div>");
    logSystem.upload(2,basicUserInfo["data"]["userId"]+"出现错误而无法启动,原因是:"+msg)
    errorbox.append(`<div style='font-size: 12px'>
            <a href='https://gf.qytechs.cn/zh-CN/scripts/470096-ewt-killer-box/feedback'>点击这儿反馈给作者(需要GreasyFork账号)?</a>
            或者,加入QQ群 884551108?
        </div>`);
    $(".loading").append(errorbox);

}

//以下均是是渲染界面的函数
function renderGuiOnPractisePage() {
    let navFunction = $(".ewt-common-header-nav");
    if(navFunction.length==0) return;
    let navFnUl = navFunction.find("ul")[0];
    let appendedElement = '<li><a style="color:red;text-decoration:underline" id="ewt-toolbox-btn"> 点我展开ewt扩展工具箱 </a></li>';
    $(navFnUl).append($(appendedElement));
    $("#ewt-toolbox-btn").click(async ()=> {
        renderBackground();
        try {
            let comp = await drawWindowBody_Homework();
            await renderWindow(comp);
            logSystem.put("kewt-logbox-0","现在时间为:"+new Date().toLocaleString())
            logSystem.put("kewt-logbox-0","登录(不可用)的账户ID:"+basicUserInfo["data"]["userId"])
        }catch(e) {
            insertErrorMsg(e.message)
        }

    });
}

function renderGuiOnListAndCourse() {
    let navFunctions = [$(".right-31MZp"),$(".navs-5oieR")];
    let navFunction = null;
    navFunctions.forEach(element => {
        if(element.length != 0) {
            navFunction = element;
            return;
        }
    });
    if(navFunction == null)
        return;

    let courseLstEle = $("[class^='page-wrapper']").length == 0 && $("[class^='course_package_container']").length == 0
    if(courseLstEle) return;
    navFunction.prepend('<a class="home-2cCGb" id="ewt-toolbox-btn"><div class="big-circle-area-atdoI" style="background-color:rgba(255,0,0,0.6)">ewt扩展工具箱</div></a>');
    $("#ewt-toolbox-btn").click(async ()=> {
        renderBackground();
        try {
            let comp = undefined;
            if($("[class^='course_package_container']").length != 0)
                comp = await drawWindowBody_Course();
            else comp = await drawWindowBody_Courses();
            await renderWindow(comp);
            logSystem.put("kewt-logbox-0","现在时间为:"+new Date().toLocaleString())
            logSystem.put("kewt-logbox-0","登录(不可用)的账户ID:"+basicUserInfo["data"]["userId"])
        } catch (e) {
            insertErrorMsg(e.message)
        }
    });
}


async function renderWindow(content) {
    GM_addStyle(style);
    let bg = $("#window-bg");
    let windowMain = $("<div id='window-main'></div>");
    windowMain.append(await navComponent());
    let kewtWindowBody = $("<div class='kewt-window-body'></div>");
    kewtWindowBody.append(content);
    windowMain.append(kewtWindowBody)
    let closeBtn = windowMain.find("#close-btn")
    closeBtn.mouseup(()=>{
        closeWindow();
    });
    $("#window-bg").empty();
    bg.prepend(windowMain);
    const windowAnimation = windowMain.animate({opacity:1,marginBottom: "-=100px"},200);
}

//以下都是组件系统
async function navComponent() {
    let root = $(`<div class='kewt-window-nav'>
                 </div>`);
    root.prepend($(`<div id='close-btn'><label class='close-btn-label'>C</label></div>`));
    let userCol = $("<div class='kewt-tscol'></div>");
    userCol.append($(`<div class='kewt-title'>`+basicUserInfo["data"]["realName"]+`</div>`));
    userCol.append($("<div class='kewt-subject'>ID:"+basicUserInfo["data"]["userId"]+"</div>"));

    let authorCol = $("<div class='kewt-tscol kewt-tscol-right'></div>");
    authorCol.append("<div class='kewt-title'>讨论群:884551108</div>")
    authorCol.append("<div class='kewt-subject kewt-subject-right'>本程序具有超级牛力(Super Cow Powers)!</div>")
    root.prepend(authorCol);
    root.prepend(userCol);
    return root;
}

function logComponent(uniqueId,height) {
    let root = $("<div class='kewt-log-box' id='"+uniqueId+"' style='height: "+height+"px'></div>")
    return root;
}

async function drawWindowBody_Course() {
    let courseInfo = getUrlInfo(window.location.href);
    let courseTag = null;
    let result = (await getCourseInfo(courseInfo["lessonId"],basicUserInfo["data"]["schoolId"],courseInfo["homeworkId"]))["data"]
    if(result == null) {
        result = (await getSchoolClassInfoUrl(courseInfo["id"],basicUserInfo["data"]["schoolId"],courseInfo["homeworkId"]))["data"][0]
        courseTag= "校本视频"
    } else courseTag = "课程讲"
    //这段代码有待优化(万一下次这个既不是课程讲也不是校本,只能够无限的if-else下去吗?我不想当R星的程序员[狗头])
    let homework = await getPractiseOrExamPaperInfo(courseInfo["homeworkId"],[parseInt(courseInfo["lessonId"])],basicUserInfo["data"]["schoolId"]);

    let root = $("<div class='window-root'>")
    let courseTxt = $("<div class='kewt-course-text'>课程</div>");
    let courseDetail = $("<div class='kewt-course-detail'></div>");
    let courseName = $("<div class='kewt-course-col'>课程名:"+result["lessonName"]+"</div>");
    let courseSubject = $("<div class='kewt-course-col'>课程学科:"+result["subjectName"]+"</div>");
    let courseId = $("<div class='kewt-course-col'>课程id:"+result[courseTags[courseTag]["courseid"]]+"</div>");
    let courseDesc = $("<div class='kewt-course-col'>课程介绍:"+result["description"]+"</div>");
    let playTime = $("<div class='kewt-course-col'>完整播放时间:"+(result["playTime"] || (result["videoPlayTime"]+"秒"))+"</div>");
    let homeworkDoing = $("<div class='kewt-course-col'>作业网址:</div>");
    let speedE = $("<div class='kewt-course-col kewt-course-speed'>跳课倍速(翻10倍填写,例如1倍填写10,1.5倍填写15):<input class='speed-input' type='number' value='10'/></div>")
    for(let i=0;i<homework["data"].length;i++) {
        homeworkDoing.append($("<a href='"+HOMEWORK_DOING_URL.replace('{%s}',homework["data"][i]["studyTest"]["paperId"])+"'>点击我去做作业</a>&nbsp;&nbsp;"))
    }
    root.append(courseTxt);
    courseDetail.append(courseName);
    courseDetail.append(courseSubject);
    courseDetail.append(courseId);
    courseDetail.append(courseDesc);
    courseDetail.append(playTime);
    courseDetail.append(homeworkDoing);
    courseDetail.append(speedE);
    root.append(courseDetail);

    let func = $("<div class='kewt-course-text kewt-course-top'>工具</div>");
    let funcbtns = $("<div class='kewt-course-funcbtns'></div>")
    root.append(func);

    let jcBtn = $("<div class='kewt-common-btn btn-red' id='jc-btn'><label>点击跳课</label></div>")
    let fhBtn = $("<div class='kewt-common-btn btn-green' id='fh-btn'><label>点击填充作业的选择题</label></div>")


    jcBtn.mouseup(async function(){
        await JumpCourseClicked(jcBtn,courseInfo["lessonId"] == undefined ? courseInfo["id"] : courseInfo["lessonId"],courseInfo["courseId"],
            courseInfo["homeworkId"],
            courseInfo["lessonId"] == undefined ? "校本视频" : "课程讲",
            parseInt($(".speed-input").val()));
    });
    fhBtn.mouseup(async function() {
        await FillHomeworkOptionBtnClicked($("#fh-btn"),homework["data"]);
    })

    funcbtns.append(jcBtn);
    funcbtns.append(fhBtn);

    root.append(funcbtns);

    let log = $("<div class='kewt-course-text kewt-course-top'>日志</div>")
    root.append(log)
    root.append(logComponent("kewt-logbox-0",200));
    return root;

}

//获取日期和作业接口
async function drawWindowBody_Courses() {
    let uinfo = getUrlInfo(window.location.href);
    let dayinfo = await getDayData([uinfo["homeworkId"]]);
    let missionInfo = await getMissionInfo(uinfo["homeworkId"],basicUserInfo["data"]["schoolId"]);

    let root = $("<div class='window-root'></div>");
    let log = $("<div class='kewt-course-text kewt-course-top'>日志</div>")
    let coursetxt = $("<div class='kewt-course-text'>课程列表</div>");
    let missionName = $("<div class='kewt-course-col'>任务名:"+missionInfo["data"]["homeworkTitle"]+"</div>");
    let missionId = $("<div class='kewt-course-col'>任务ID:"+uinfo["homeworkId"]+"</div>");
    let speedE = $("<div class='kewt-course-col kewt-course-speed'>跳课倍速(翻10倍填写,例如1倍填写10,1.5倍填写15):<input class='speed-input' type='number' value='10'/></div>")
    let coursesContainer = $("<div class='kewt-course-container'></div>")
    let courseLeft = $("<div class='kewt-course-c-left'></div>")
    let courseRight = $("<div class='kewt-course-c-right'></div>")
    let missions = undefined;
    for(let i=0;i<dayinfo["data"]["days"].length;i++) {
        let s = $("<div class='kewt-course-l-date'><label>"+new Date(dayinfo["data"]["days"][i]["day"]).toLocaleDateString()+"</label></div>");
        s.click(async ()=>{
            if(!CourseSideBarCanClick) return;
            $(document.getElementsByClassName("kewt-course-l-date-sel")[0]).removeClass("kewt-course-l-date-sel");
            s.addClass("kewt-course-l-date-sel");

            courseRight.empty();

            missions = await getMissionHomeworks(
                dayinfo["data"]["days"][i]["dayId".toString()],
                dayinfo["data"]["days"][i]["day"],
                [parseInt(uinfo["homeworkId"])]);

            for(let j = 0;j < missions["data"]["data"].length;j++) {
                let urlinfo = getUrlInfo(missions["data"]["data"][j]["contentUrl"]);
                let lessonid = courseTags[missions["data"]["data"][j]["contentTypeName"]] != undefined ?
                    urlinfo[courseTags[missions["data"]["data"][j]["contentTypeName"]]["lessonid"]] : undefined ;
                let courseid = courseTags[missions["data"]["data"][j]["contentTypeName"]] != undefined ?
                urlinfo[courseTags[missions["data"]["data"][j]["contentTypeName"]]["courseid"]] : undefined
                let homeworkid = urlinfo["homeworkId"]
                let eleRoot = $("<div class='kewt-course-c-right-ele'></div>")

                eleRoot.append("<div class='kewt-course-c-img'><img src='"
                    +missions["data"]["data"][j]["imgUrl"]+"' class='kewt-cci-i'/></div>")

                let info = $("<div class='kewt-course-c-info'></div>");
                let major = $("<div class='kewt-course-c-major'></div>");
                if(missions["data"]["data"][j]["contentTypeName"] in courseTags) {
                    let btn = $("<div class='kewt-mission-fn-btn btn-red'>跳过课程</div>")
                    btn.click( async function() {
                        await JumpCourseClicked(btn,
                            lessonid,
                            courseid,
                            homeworkid,
                            missions["data"]["data"][j]["contentTypeName"],
                            parseInt($(".speed-input").val())
                            )
                    });
                    major.append(btn);
                }
                if((missions["data"]["data"][j]["studyTest"] != null && missions["data"]["data"][j]["contentTypeName"] == "课程讲")
                || missions["data"]["data"][j]["contentTypeName"] == "试卷") {
                    let btnFoPaper = $("<div class='kewt-mission-fn-btn btn-green'>填充选择题</div>")
                    btnFoPaper.click(async function(){
                        await FillOptionBtnClicked(btnFoPaper,missions["data"]["data"][j]["studyTest"] != null ?
                            [missions["data"]["data"][j]["studyTest"]] :
                            [missions["data"]["data"][j]],missions["data"]["data"][j]["contentTypeName"] == "试卷" ? 205 : 204);
                    })
                    major.append(btnFoPaper);
                }
                info.append("<div class='kewt-cci-title'>["+missions["data"]["data"][j]["subjectName"]+"]"+missions["data"]["data"][j]["title"]+"</div>")

                if(missions["data"]["data"][j]["contentTypeName"] in courseTags)
                    info.append("<div class='kewt-cci-id'>课程ID:"+courseid+"</div>")
                else if(missions["data"]["data"][j]["contentTypeName"] == "试卷")
                    info.append("<div class='kewt-cci-id'>试卷报告ID:"+missions["data"]["data"][j]["reportId"]+"</div>")

                info.append(major);
                eleRoot.append(info)
                courseRight.append(eleRoot);
            }

        })
        courseLeft.append(s);
    }

    coursesContainer.append(courseLeft);
    coursesContainer.append(courseRight);
    root.append(coursetxt);
    root.append(missionName);
    root.append(missionId);
    root.append(speedE);
    root.append(coursesContainer);
    root.find(".kewt-course-l-date")[0].click();

    let wholeFunc = $("<div class='kewt-course-wfunc'></div>")

    let jcbtn = $("<div class='kewt-common-btn btn-red' id='jc-whole-btn'><label>点击跳过当天的全部课程</label></div>");
    let fobtn = $("<div class='kewt-common-btn btn-green' id='fo-whole-btn'><label>点击填充当天全部练习的选择题</label></div>");

    jcbtn.click(async ()=>{
        await JumpDayCourseClicked(missions,uinfo["homeworkId"],parseInt($(".speed-input").val()))
    })

    fobtn.click(async ()=>{
        await FillDayOptionBtnClicked(missions,uinfo["homeworkId"]);
    })

    wholeFunc.append(jcbtn);
    wholeFunc.append(fobtn);
    root.append(wholeFunc);
    root.append(log);
    root.append(logComponent("kewt-logbox-0",200));
    return root;
}

async function drawWindowBody_Homework() {
    let urlInfo = getUrlInfo(window.location.href);
    let paperid = urlInfo["paperId"];
    let bizCode = urlInfo["bizCode"];

    let paperBasicInfo = await getHomeworkInfo(paperid,parseInt(bizCode));
    let paperContent = await getHomeworkPaper(paperBasicInfo["data"]["reportId"],parseInt(bizCode));

    let root = $("<div class='window-root'></div>");
    let homeworktxt = $("<div class='kewt-homework-text'>作业</div>");
    let haveChooseQues = false;
    root.append(homeworktxt);

    let homeworkInfo = $("<div class='kewt-homework-detail'></div>")
    let homeworkId = $("<div class='kewt-homework-col'>作业ID:"+paperBasicInfo["data"]["reportId"]+"</div>")
    let homeworkName = $("<div class='kewt-homework-col'>作业名称:"+paperContent["data"]["title"]+"</div>")
    let homeworkContainer = $("<div class='kewt-homework-container'></div>")

    await drawQuestions(homeworkContainer,paperContent["data"]["questions"],null)

    async function drawQuestions(parentContainer,questionList,parseArray) {
        let quesIndex = 1;
        for(let i of questionList) {
            let parse = await getQuestionParse(bizCode,paperid,i["id"],paperBasicInfo["data"]["reportId"])
            let quesContainer = $("<div class='kewt-ques-container'></div>")
            quesContainer.append("<div>"+i["questionContent"]+"</div>")

            let statusBar = $("<div class='ques-status-bar'></div>")
            statusBar.append($("<div class='blue-container'>"+quesIndex+"</div>"))
            statusBar.append($("<div class='ques-c-info orange-container'>"+i["cateName"]+"</div>"))
            statusBar.append($("<div class='ques-c-info red-container'>试题ID:"+i["id"]+"</div>"))
            if(i["options"].length != 0) {
                haveChooseQues = true
                let choices = i["options"];
                let rightAnswer = i["rightAnswer"];
                let optionContainer = $("<div class='ques-answer-container''></div>")
                for(let j of choices) {
                    let element = $(`<div class='ques-options-option'>
                    <div class='ques-options-choice-dot'>`+j["choice"]+`
                    </div><div class='ques-option-content'>`+j["option"]+`</div></div>
                    `);
                    if(rightAnswer.indexOf(j["choice"]) != -1) {
                        console.log(element.children(".ques-options-choice-dot"))
                        let answer = element.children(".ques-options-choice-dot")
                        answer.removeClass("ques-options-choice-dot")
                        answer.addClass("ques-options-choice-dot-heart")
                    }
                    optionContainer.append(element);
                }

                quesContainer.append(optionContainer);
                let parseContainer = $("<div class='ques-answer-container'></div>")
                parseContainer.append("<div class='ques-opt-container'>解析</div>")
                parseContainer.append(parseArray==null ? parse["data"]["method"]: parseArray[quesIndex-1]["method"])
                quesContainer.append(parseContainer);
            } else {
                let rightAnswer = i["rightAnswer"];
                let answerContainer = $("<div class='ques-answer-container ques-answer-parse'></div>")
                answerContainer.append("<div class='ques-opt-container'>"+(i["childQuestions"].length==0 ? "答案": "小题部分")+"</div>")
                let answerParseContainer = $("<div class='ques-parse-container'></div>")
                if(i["childQuestions"].length != 0) {
                    await drawQuestions(answerParseContainer,i["childQuestions"],parse["data"]["childQuestions"]);
                }
                else {
                    for(let j of rightAnswer) {
                        answerParseContainer.append(j);
                        answerParseContainer.append("&nbsp;&nbsp;&nbsp;");
                    }
                    answerParseContainer.append("<div class='ques-opt-container'>解析</div>")
                    answerParseContainer.append(parseArray==null? parse["data"]["method"] : parseArray[quesIndex-1]["method"])
                }
                answerContainer.append(answerParseContainer);
                quesContainer.append(answerContainer)
            }
            quesContainer.prepend(statusBar);
            parentContainer.append(quesContainer);
            quesIndex ++;
        }
    }

    homeworkInfo.append(homeworkId)
    homeworkInfo.append(homeworkName);
    root.append(homeworkInfo);
    root.append(homeworkContainer)

    root.append($("<div class='kewt-homework-text kewt-homework-top'>工具</div>"));
    root.append("<div class='kewt-hwk-menu'></div>")
    let fhBtn = undefined;
    if(haveChooseQues) {
        fhBtn = $("<div class='kewt-common-btn btn-green'><label>点击填充作业的选择题</label></div>")
        fhBtn.mouseup(async ()=>{
            await FillOptionBtnClicked(fhBtn,[paperBasicInfo["data"]],bizCode);
        })
    } else
        fhBtn = $("<div class='kewt-common-btn btn-unclick'><label>抱歉,这张试卷没有选择题</label></div>")

    root.append(fhBtn);
    logSystem.put(null,"")
    return root;
}

//以下均是跟窗口有关的函数
function closeWindow() {
    let bg = $("#window-bg");
    let wm = $("#window-main");
    CourseSideBarCanClick = true;
    wm.animate({opacity:0,marginBottom: "+=100px"},200);
    setTimeout(()=>{
        wm.css("display","none");
        bg.remove();
    },220);
}

//以下均是跟事件绑定有关的函数
async function JumpCourseClicked(jcbtn,lessonid,courseid,homeworkId,courseTag,speed) {
    try {
        let cannotClick = jcbtn.hasClass("btn-unclick");
        if(cannotClick == true) return;
        jcbtn.removeClass("btn-red");
        jcbtn.addClass("btn-unclick");
        logSystem.put("kewt-logbox-0","")
        logSystem.put("kewt-logbox-0","===== 欢迎使用ewt跳课程序!")
        logSystem.put("kewt-logbox-0","开始跳课..")

        let courseInfo = await getCourseInfo(lessonid,basicUserInfo["data"]["schoolId"],homeworkId)
        logSystem.put("kewt-logbox-0","课程名:"+courseInfo["data"]["lessonName"])
        await finishCourseFn(lessonid,jcbtn,courseid,courseTag,speed)
        logSystem.uploadWithUserId(0,"跳课进程完成.课程ID为:"+courseId)
        jcbtn.text("跳课成功!");
        logSystem.put("kewt-logbox-0","All done,have fun!")
    } catch(e) {
        logSystem.put("kewt-logbox-0",e.message)
        logSystem.uploadWithUserId(2,"跳课进程失败,原因是"+e.message)
        logSystem.put("kewt-logbox-0","跳课进程失败,请刷新以重试.")
    }

}

async function JumpDayCourseClicked(missions,homeworkId,speed) {
    try {
        if(CourseSideBarCanClick == false) return;
        CourseSideBarCanClick = false;

        $("#fo-whole-btn").css("visibility","hidden");
        let lessonid,courseid,phomeworkid;
        let ele = document.getElementsByClassName("kewt-course-c-right-ele");
        logSystem.put('kewt-logbox-0','=== 欢迎使用ewt跳课程序!')
        logSystem.put('kewt-logbox-0',"=== 开始跳过当天的所有课程...")
        logSystem.put('kewt-logbox-0','使命任务ID:'+homeworkId);
        for(let j = 0;j < missions["data"]["data"].length;j++) {
            let urlData = getUrlInfo(missions["data"]["data"][j]["contentUrl"]);
            if(missions["data"]["data"][j]["contentTypeName"] in courseTags) {
                lessonid = urlData[courseTags[missions["data"]["data"][j]["contentTypeName"]]["lessonid"]];
                courseid = getUrlInfo(missions["data"]["data"][j]["contentUrl"])["courseId"];
                phomeworkid = getUrlInfo(missions["data"]["data"][j]["contentUrl"])["homeworkId"];
                
                let courseInfo = await courseTags[missions["data"]["data"][j]["contentTypeName"]]["method"](lessonid,basicUserInfo["data"]["schoolId"],courseid)
                logSystem.put("kewt-logbox-0","==================")
                logSystem.put("kewt-logbox-0","开始跳课,课程名:"+courseInfo["data"]["lessonName"])

                let jcbtn = $(ele[j].getElementsByClassName("btn-red")[0])
                
                jcbtn.removeClass("btn-red");
                jcbtn.addClass("btn-unclick");
                await finishCourseFn(lessonid,jcbtn,courseid,courseInfo["data"]["id"] == undefined ? "校本视频" : "课程讲",speed);
                jcbtn.text("跳课成功!");
            }
        }
        $("#fo-whole-btn").css("visibility","visible");
        logSystem.put("kewt-logbox-0","All done,have fun!")
        logSystem.uploadWithUserId(2,"跳课进程完成.课程ID:"+courseId)
        CourseSideBarCanClick = true;
    }
    catch(e) {
        logSystem.put("kewt-logbox-0",e.message)
        logSystem.uploadWithUserId(2,"跳课进程失败,原因是"+e.message)
        logSystem.put("kewt-logbox-0","跳课进程失败,请刷新以重试.")
    }
}

async function FillOptionBtnClicked(fhBtn,homeworks,bizCode) {
    try {
        let cannotClick = fhBtn.hasClass("btn-unclick");
        if(cannotClick == true) return;
        fhBtn.removeClass("btn-green");
        fhBtn.addClass("btn-unclick");

        logSystem.put("kewt-logbox-0","")
        logSystem.put("kewt-logbox-0","===== 欢迎使用ewt选择题自动填充程序!")
        
        let fail = false;
        let paperid = null;
        for(let i=0;i<homeworks.length;i++) {

            logSystem.put("kewt-logbox-0","")
            logSystem.put("kewt-logbox-0","开始自动填充第 "+(i+1)+" 份(共 "+homeworks.length+" 份)作业/卷的选择题...")
            if(homeworks[i]["paperId"] != null)
                paperid = homeworks[i]["paperId"];
                //说实话可以直接用返回结果的reportId,但是为了兼容性和代码简洁性我还是先用paperId间接求取reportId
            else if(homeworks[i]["contentTypeName"] == "试卷")
                paperid = getUrlInfo(homeworks[i]["contentUrl"])["paperId"];

            if(await FillOptionBtnEvent(paperid,bizCode)) {
                logSystem.put("kewt-logbox-0","第 "+(i+1)+" 份作业/试卷选择题填写完毕.");
            }
            else {
                logSystem.put("kewt-logbox-0","第"+(i+1)+"份作业/试卷选择题填写失败.程序终止.");
                logSystem.uploadWithUserId(0,"的选择题填写失败.试卷ID:"+paperid)
                fhBtn.addClass("btn-green");
                fhBtn.removeClass("btn-unclick");
                fhBtn.text("重试填写选择题...")
                fail = true;
                break;
            }

        }
        if(!fail) {
            logSystem.uploadWithUserId(0,"填写选择题进程完成.试卷ID为:"+paperid)
            fhBtn.text("填写成功(如果你在作业界面请按F5刷新一下)!")
        } 
        logSystem.put("kewt-logbox-0","All done,have fun!");
    } catch(e) {
        logSystem.put("kewt-logbox-0",e.message)
        logSystem.uploadWithUserId(2,"选择题填写失败,原因为"+e.message)
        logSystem.put("kewt-logbox-0","跳课进程失败,请刷新以重试.")
    }

}

async function FillHomeworkOptionBtnClicked(fhBtn,data) {
    let hwkArr = [];
    for(let i = 0;i < data.length;i++)
        hwkArr.push(data[i]["studyTest"])
    FillOptionBtnClicked(fhBtn,hwkArr,204);
}

async function FillDayOptionBtnClicked(missions,homeworkId) {
    try {
        if(CourseSideBarCanClick == false) return;
        CourseSideBarCanClick = false;
        $("#jc-whole-btn").css("visibility","hidden");
        let ele = document.getElementsByClassName("kewt-course-c-right-ele");
        logSystem.put('kewt-logbox-0','=== 欢迎使用ewt自动填充选择题程序!')
        logSystem.put('kewt-logbox-0',"=== 开始填写当天课程附带练习/试卷上所有的选择题...")
        logSystem.put('kewt-logbox-0','使命任务ID:'+homeworkId);

        let eles = document.getElementsByClassName("kewt-course-c-right-ele");
        let data = missions["data"]["data"]
        for(let j=0;j<data.length;j++) {
            let success = false;
            logSystem.put('kewt-logbox-0','===============');
            if(data[j]["contentTypeName"] == "试卷") {
                let contentUrlArg = getUrlInfo(data[j]["contentUrl"])
                success = await FillOptionBtnEvent(contentUrlArg["paperId"],205);
            } else if(data[j]["studyTest"] != null)
                success = await FillOptionBtnEvent(data[j]["studyTest"]["paperId"],204)
            if(success) {
                $(eles[j].getElementsByClassName("btn-green")[0]).text("填写成功!")
                $(eles[j].getElementsByClassName("btn-green")[0]).addClass("btn-unclick")
                $(eles[j].getElementsByClassName("btn-green")[0]).removeClass("btn-green")
            } else {
                $(eles[j].getElementsByClassName("btn-green")[0]).html("重试")
            }
        }
        $("#jc-whole-btn").css("visibility","visible");
        logSystem.uploadWithUserId(0,"选择题填写成功.试卷ID:"+contentUrlArg["paperId"])
        logSystem.put("kewt-logbox-0","All done.Have fun!")
        CourseSideBarCanClick = true;
    }
    catch(e) {
        logSystem.put("kewt-logbox-0",e.message)
        logSystem.uploadWithUserId(2,"跳课进程失败,原因是"+e.message)
        logSystem.put("kewt-logbox-0","填写选择题进程失败,请重新按按钮以重试.")  
    }

}

async function FillOptionBtnEvent(paperId,bizCode) {
    let paperInfo = await getHomeworkInfo(paperId,bizCode);
    let reportId = paperInfo["data"]["reportId"];
    let paperContent = await getHomeworkPaper(reportId,bizCode);
    let finalAnswer = processSelectQuestionAnswer(paperContent["data"]["questions"])
    logSystem.put("kewt-logbox-0","试卷/作业标题:"+paperContent["data"]["title"])
    logSystem.put("kewt-logbox-0","试卷/作业ID:"+paperContent["data"]["paperId"])
    let res = await fillOption(paperId,reportId,finalAnswer,bizCode);

    if(res["success"] || finalAnswer.length == 0) {
        logSystem.put("kewt-logbox-0","自动填写选择题完成.")
        logSystem.uploadWithUserId(0,"选择题填写成功(试卷id为"+paperContent["data"]["paperId"]+")")
    }

    else {
        logSystem.put("kewt-logbox-0","填充选择题失败(错误代码:"+res["code"]+",错误原因:"+res["msg"]+")")
    }
        
    return res["success"] || finalAnswer.length == 0;
}

//以下均是跟请求网络接口有关的函数(即最底层网络访问接口)

//跳课接口

async function finishCourse(
        action,
        lessonid,
        courseId,
        beginTime,
        endTime,
        stayTime,
        duration,
        signature,
        status,
        uuid,
        videotype,
        speed
) {
    let data = {
        CommonPackage: {
            browser:"Chrome",
            browser_ver: "5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.76",
            ip: "100.117.34.235",
            mstid: getUserTk(),
            os: "macOS",
            playerType: 1,
            resolution: "1680*1050",
            sdkVersion: "3.0.7",
            userid: parseInt(basicUserInfo["data"]["userId"]),
            videoBizCode: "1013"
        },
        EventPackage: [{
            action: action,
            begin_time: beginTime,
            course_id: courseId,
            fallback: 0,
            lesson_id: lessonid,
            point_num: 1,
            point_time: 60000,
            point_time_id: 15,
            quality: "标清",
            report_time: endTime,
            speed: speed,
            status: status,
            stay_time: stayTime,
            uuid: uuid,
            video_type: videotype
            }],
        signature: signature,
        sn: "ewt_web_video_detail",
        _: duration
    }
    console.log(data)
    let res = await requestJson("POST",COURSE_BATCH_URL.replace("{userId}",basicUserInfo["data"]["userId"])
                    .replace("{timetamp}",duration)
                    .replace("{uuid}",uuid)
                    .replace("{lessonid}",lessonid)
                    .replace("{timestamp}",duration),headerJump,data);
    console.log(COURSE_BATCH_URL.replace("{userId}",basicUserInfo["data"]["userId"])
    .replace("{uuid}",uuid)
    .replace("{lessonid}",lessonid)
    .replace("{sdkVersion}","3.0.7")
    .replace("{timestamp}",duration))
    return JSON.parse(res["responseText"]);
}

async function getMissionInfo(hid,sid) {
    let res = await request("GET",MISSION_INFO_URL.replace("{hid}",hid).replace("{sid}",sid),header);
    return JSON.parse(res["responseText"]);
}
//选择题填涂接口
async function fillOption(paperId,reportId,answers,bizCode) {
    let data = {
        answers: answers,
        assignPoints: false,
        bizCode: bizCode.toString(),
        paperId: paperId.toString(),
        platform: "1",
        reportId: reportId.toString()
    }

    let res = await requestJson("POST",SUBMIT_ANSWER_URL,headerCourseWithToken,data);
    return JSON.parse(res["responseText"]);
}

//获取试卷题目接口
async function getHomeworkPaper(reportId,bizCode) {
    let res = await request("GET",HOMEWORK_GET_ANSWER_URL.replace("{reportid}",reportId).replace("{bizCode}",bizCode),header);
    return JSON.parse(res["responseText"]);
}

//获取作业接口
async function getHomeworkInfo(paperId,bizCode) { //
    let res = await request("GET",HOMEWORK_INFO_URL.replace("{paperId}",paperId).replace("{bizCode}",bizCode),header);
    return JSON.parse(res["responseText"]);
}

//获取基本用户信息
async function getBasicUserInfo() {
    let res = await request("GET",GET_USER_URL,header,null);
    return JSON.parse(res["responseText"]);
}


async function getQuestionParse(bizCode,paperId,questionId,reportId) {
    let data = {
        bizCode: parseInt(bizCode),
        paperId: paperId.toString(),
        questionId: questionId.toString(),
        platform: "1",
        reportId: reportId.toString()
    }
    let headerC = header;
    headerC["Content-Type"]="application/json";
    let res = await requestJson("POST",QUES_PARSE_URL,headerC,data);
    return JSON.parse(res["responseText"]);
}

//获取课程信息
async function getCourseInfo(lessonid,schoolid,homeworkid) {
    let data = {
        lessonId: parseInt(lessonid),
        schoolId: schoolid,
        homeworkId: parseInt(homeworkid)
    }
    let headerC = headerCourse;
    headerC["Content-Type"]="application/json";
    let res = await requestJson("POST",GET_LESSON_DETAIL_URL,headerC,data);
    return JSON.parse(res["responseText"]);
}

//获取学校信息
async function getSchoolInfo() {
    let res = await request("GET",SCHOOL_URL,headerCourseWithToken);
    return JSON.parse(res["responseText"])
}

//获取某个视频的练习链接接口
async function getPractiseOrExamPaperInfo(homeworkId,lessonIds,schoolId) {
    let data = {
        homeworkId: parseInt(homeworkId),
        lessonIdList: lessonIds,
        schoolId: schoolId
    }
    let res = await requestJson("POST",LESSON_HOMEWORK_URL,headerCourseWithToken,data);
    return JSON.parse(res["responseText"]);
}

//用于跳课部分的接口
async function getHMACSecret() {
    let res = await requestJson("GET",HMAC_SECRET_ID_URL.replace("{%s}",basicUserInfo["data"]["userId"]),header);
    return JSON.parse(res["responseText"]);
}

//获取作业日期接口
async function getDayData(homeworks) {
    let header = headerCourseWithToken;
    header["Content-Type"] = "application/json";
    let data = {
        homeworkIds: homeworks,
        sceneId: 0,
        taskDistributionTypeEnum: 1,
        schoolId: basicUserInfo["data"]["schoolId"]
    }
    let res = await requestJson("POST",DAY_URL,header,data);
    return JSON.parse(res["responseText"]);
}

async function getMissionHomeworks(dayid,days,homeworks) {
    let data = {
        day: days,
        dayId: dayid,
        homeworkIds: homeworks,
        pageIndex: 1,
        pageSize: 1000,
        sceneId: 0,
        schoolId: basicUserInfo["data"]["schoolId"]
    }
    let res = await requestJson("POST",COURSE_URL,headerCourseWithToken,data);
    return JSON.parse(res["responseText"]);
}

async function getSchoolClassInfoUrl(lessonid,schoolid) {
    let data = {
        idList: [lessonid],
        mockId: true,
        schoolId: schoolid
    }
    let res = await requestJson("POST",SCHOOL_COURSE_URL,headerCourseWithToken,data);
    return JSON.parse(res["responseText"]);
} //校本课程

function request(method,url,headers,data) {
    return new Promise(resolve => {GM_xmlhttpRequest({
        method: method,
        url: url,
        data: data,
        headers: headers,
        onload: (res) => {
            resolve(res)
        }})
    });
}

function requestJson(method,url,headers,data) {
    headers["Content-Type"]="application/json";
    return new Promise(resolve => {GM_xmlhttpRequest({
        method: method,
        url: url,
        data: JSON.stringify(data),
        dataType: "json",
        contentType: "application/json; charset=utf-8",
        headers: headers,
        onload: (res) => {
            resolve(res)
        }})
    });
}

//工具接口
function getUrlInfo(url) {
    let urlInfos = url.split("?")[url.split("?").length-1];
    let urlArgs = urlInfos.split("&");
    let result = {};
    for(let i = 0;i < urlArgs.length;i++) {
        let k = urlArgs[i].split("=")[0];
        let v = urlArgs[i].split("=")[1];
        result[k] = v;
    }
    return result;
}

function getUserTk() {
    let cookie = document.cookie.split(";");
    let result = {};
    for(let i = 0;i < cookie.length;i++) {
        let k = cookie[i].split("=")[0].substring(1);
        let v = cookie[i].split("=")[1];
        result[k] = v;
    }
    return result["token"];
}


//getSignature:详见ewt_player.js的第 9859 - 9884 行,那儿有权威的加密方案,我这儿只是做一个复刻
class getSignature {
    constructor(end,duration,action) {
        this.end = end
        this.duration = duration
        this.action = action
        this.param = "action={action}&duration={duration}&mstid={mstid}&signatureMethod=HMAC-SHA1&signatureVersion=1.0&timestamp={timestamp}&version=2022-08-02";
        this.sessionId = this.secret = undefined;
    }

    async getSecret() {
        let tk = await getHMACSecret();
        let sessionid = tk["data"]["sessionId"];
        this.secret = tk["data"]["secret"];
        headerJump["x-bfe-session-id"] = sessionid;
        console.log(sessionid)
        headerJump["token"] = getUserTk();
    }

    async getRealSignature() {
        await this.getSecret();
        logSystem.put("kewt-logbox-0","本次接口签名:"+this.secret);
        let rp = this.param.replace("{duration}",this.duration)
        .replace("{mstid}",getUserTk())
        .replace("{timestamp}",this.end)
        .replace("{action}",this.action);
        console.log(rp)
        return CryptoJS.HmacSHA1(rp,this.secret).toString();
    }
}

/* 摘自bundle.js 44165-44169行的randomString()函数*/
function randomString() {
    let randomStringChars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
    for (var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 8, t = randomStringChars.length, r = "", n = 0; n < e; n++)
        r += randomStringChars.charAt(Math.floor(Math.random() * t));
    return r
}

function processSelectQuestionAnswer(questions) {
    let res = [];

    getSelectQuestionAnswer(questions);
    function getSelectQuestionAnswer(questions) {
        for(let i=0;i<questions.length;i++) {
            let obj = {};
            if(questions[i]["childQuestions"].length != 0)  {
                getSelectQuestionAnswer(questions[i]["childQuestions"]);
            }
            if(questions[i]["cateName"] == "单选" || questions[i]["cateName"] == "多选") {
                obj["answers"] = questions[i]["rightAnswer"];
                obj["questionId"] = questions[i]["id"];
                obj["questionNo"] = questions[i]["questionNo"];
                obj["totalSeconds"] = 50;
                obj["cateId"] = questions[i]["cate"];
                res.push(obj);
            }
        }
    }
    return res;
}

async function finishCourseFn(lessonid,jcbtn,courseid,courseTag,speed) {
    let rspeed = (speed / 10) || 1;
    console.log(rspeed)
    if(rspeed < 1 || rspeed > 32) {
        rspeed = 1;
        logSystem.put("kewt-logbox-0","检测到非法数值,已经自动改为1倍.")
    }
        
    logSystem.put("kewt-logbox-0","跳课倍速:"+ rspeed)
    let vid = await courseTags[courseTag]["method"](lessonid,basicUserInfo["data"]["schoolId"],courseid)
    let duration = vid["data"]["videoPlayTime"] * 1000 * 0.8 / rspeed + 5000;

    let begin = Date.now();
    let uuid = randomString(8);

    let arr =[];
    let start = 0,time = 0;

    arr.push([1,0,1,uuid + "_" + 0]);
    
    while(start < duration) {
        if(duration - start >= 60000) arr.push([2,60000,1,uuid + "_" + (time+1)])
        else arr.push([2,duration - start,1,uuid + "_" + (time+1)])
        start += 60000;
        time ++;
    }

    arr.push([3,0,3,uuid + "_" + (time)]);
    arr.push([4,5,1,uuid + "_" + (time+1)]);

    for(let i=0;i<arr.length;i++) {
        let end = Date.now();
        logSystem.put("kewt-logbox-0","正在向服务器请求接口(第"+(i+1)+"个,共"+arr.length+"个)")
        let sign = new getSignature(end,arr[i][1],arr[i][0])
        let se = await sign.getRealSignature();
        let res = await finishCourse(
            arr[i][0],
            lessonid,
            courseid,
            begin.toString(),
            end,
            arr[i][1],
            Date.now(),
            se,
            arr[i][2],
            arr[i][3],
            courseTags[courseTag]["videoType"],
            rspeed
        );
        if(res["success"] != true) {
            logSystem.put("kewt-logbox-0","抱歉,跳课失败(错误代码:"+res["code"]+",错误原因:"+res["msg"]+").")
            jcbtn.removeClass("btn-unclick");
            jcbtn.addClass("btn-red");
            jcbtn.html("<label>重试</label>")
            return;
        }
        logSystem.put("kewt-logbox-0","第"+(i+1)+"个接口请求成功!");
        if(arr[i][0] == 1 || (arr[i][0] == 2)) {
            console.log(arr[i][1])
            if(arr[i][0]==2) {
                logSystem.put("kewt-logbox-0","需要等待"+arr[i][1] / 1000+"秒后才能继续操作.在此期间不要关闭窗口...")
                await sleep(arr[i][1] + 500);
            }
            else {
                logSystem.put("kewt-logbox-0","需要等待60秒后才能继续操作.在此期间不要关闭窗口...")
                await sleep(60500)
            }
        }
    }
}

$(function(){setTimeout(()=>{
    console.clear();
    renderGUI();
},1500)
});})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址