超星学习通小助手-视频专版

超星视频后台挂机,文档自动完成。

// ==UserScript==
// @name         超星学习通小助手-视频专版
// @namespace    http://tampermonkey.net/
// @version      2.1.4
// @description  超星视频后台挂机,文档自动完成。
// @author       爱吃蛋炒饭
// @match        *://*.chaoxing.com/*
// @match        *://*.edu.cn/*
// @match        *://*.nbdlib.cn/*
// @match        *://*.hnsyu.net/*
// @run-at       document-end
// @connect      sso.chaoxing.com
// @connect      mooc1-api.chaoxing.com
// @connect      mooc1-1.chaoxing.com
// @connect      mooc1-2.chaoxing.com
// @connect      fystat-ans.chaoxing.com
// @connect      api.dbask.net
// @grant        unsafeWindow
// @grant        GM_xmlhttpRequest
// @grant        GM_info
// @require      https://lib.baomitu.com/jquery/3.6.0/jquery.min.js
// @require      https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.18.0/js/md5.min.js
// @require https://greasyfork.org/scripts/456170-hacktimerjs/code/hacktimerjs.js?version=1125728
// ==/UserScript==
(function() {
    'use strict';
    var $=unsafeWindow.$,layui,layer,form,courseList,cpi,clazzid,uid,ua_str=str_z("32"),script_info=GM_info.script;
    //请求封装
    function requests(url,data="",type="get"){
        return new Promise((resolve, reject) => {
            var headers={
                "User-Agent": "User-Agent: Dalvik/2.1.0 (Linux; U; Android 11; M3121K1AB Build/SKQ1.211006.001) (device:M3121K1AB) Language/zh_CN com.chaoxing.mobile/ChaoXingStudy_3_5.1.4_android_phone_614_74 (@Kalimdor)_"+ua_str,
                'X-Requested-With': 'XMLHttpRequest',
                'Sec-Fetch-Site': 'same-origin',
                "Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",
                "host": "mooc1-1.chaoxing.com",
            };

            GM_xmlhttpRequest({
                method: type,
                url: url,
                data:data,
                headers: headers,
                onload: function (xhr) {
                    try {
                        let obj=$.parseJSON(xhr.responseText) || {};
                        if(obj.error){
                            layer.msg("请输入验证码");
                            layer.open({
                                type: 1,
                                title:"【官方验证】请输入验证码",
                                skin: 'layui-layer-rim', //加上边框
                                area: ['420px', '240px'], //宽高
                                content: '<img src="'+obj.verify_png_path+'"/> <input type="text" class="code_input" placeholder="请输入图中的验证码" /><button id="code_btn">验证</button>'
                            });
                            $("#code_btn").on('click',function(){
                                let code=$(".code_input").val();
                                if(code.length!==4){
                                    layer.msg("你觉得对吗");
                                }else{
                                    let url=obj.verify_path+"&ucode="+code;
                                    console.log(url);
                                    window.open(url);
                                }
                            });
                        }
                        resolve(obj);
                    }
                    catch(err){
                        resolve(xhr.responseText);
                    }
                }
            });
        })
    }
    function get_enc(clazzid,uid,jobid,objectId,playingTime,duration){
        var str = "["+clazzid+"]["+uid+"]["+jobid+"]["+objectId+"]["+(playingTime * 1000)+"][d_yHJ!$pdA~5]["+(duration * 1000)+"][0_"+duration+"]";
        var hash = md5(str);
        return hash;
    }
    function sleep(time) {
        return new Promise(resolve =>
                           setTimeout(resolve,time)
                          ) }
    function str_z(len) {
        len = len || 32;
        let $chars = 'qwertyuioplkjhgfdsazxcvbnm1234567890';
        let maxPos = $chars.length;
        let pwd = '';
        for (let i = 0; i < len; i++) {
            pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
        }
        return pwd;
    }
    //刷视频用的
    async function video_s(objectId,knowledgeId,cpi,clazzid, jobid,uid,otherInfo,rt="0.9",module){
        console.log("开始");
        let url = "https://mooc1-1.chaoxing.com/ananas/status/" + objectId + "?k=&flag=normal&"
        let obj=await requests(url);
        console.log(obj);
        let duration=obj.duration;//视频总长度
        let dtoken=obj.dtoken;
        let clipTime = "0_" + duration;
        let ztype=obj
        let timer;
        $("#app2").append('<div id="jdf" style="width:500px" class="layui-progress layui-progress-big" lay-filter="demo" lay-showPercent="true">当前视频进度<div id="jd" class="layui-progress-bar layui-bg-blue" lay-percent="0%"></div></div>');
        let beisu=$("#beisu").val()||1;
        let num =0;
        for(let playingTime=0;playingTime<=duration;playingTime=playingTime+~~beisu){
            beisu=$("#beisu").val()||1;
            layui.element.progress('demo', ~~(playingTime/duration*100)+"%");
            add_log("视频挂机ing..."+playingTime+" - "+duration+"s");
            console.log($("#beisu").val()||1,playingTime);
            let out = await sleep(1000);
            if(num%~~(60/beisu)==0){
                add_log("视频进度提交(每60s提交一次)");
                let req=await video_p(clazzid,uid,jobid,objectId,playingTime,duration,cpi,dtoken,otherInfo,rt,module);
                if(req&&$("#pattern").val()!=="2"){
                    add_log("当前视频已完成,正在跳转下一个");
                    break;
                }
            }
            num=num+1
        }

        let req=await video_p(clazzid,uid,jobid,objectId,duration,duration,cpi,dtoken,otherInfo,rt,module);
        console.log(123,req);
        while(!req&&$("#pattern").val()!=="2"){
            let req=await video_p(clazzid,uid,jobid,objectId,duration,duration,cpi,dtoken,otherInfo,rt,module);
            add_log("进度提交中...");
            let out = await sleep(1000);
        }
        if(req){
            add_log("当前视频已完成,正在跳转下一个");
        }
        $("#jdf").remove();
    }
    async function video_p(clazzid,uid,jobid,objectId,playingTime,duration,cpi,dtoken,otherInfo,rt,module){
        let enc=get_enc(clazzid,uid,jobid,objectId,playingTime,duration);
        let type=module.includes('audio')?"Audio":"Video";
        let url = "https://mooc1-api.chaoxing.com/multimedia/log/a/"+cpi+"/"+dtoken+"?otherInfo="+otherInfo+"&playingTime="+playingTime+"&duration="+duration+"&akid=null&jobid="+jobid+"&clipTime=0_"+duration+"&clazzId="+clazzid+"&objectId="+objectId+"&userid="+uid+"&isdrag=4&enc="+enc+"&rt="+rt+"&dtype="+type+"&view=json";
        let obj=await requests(url);
        console.log(url);
        if(obj.isPassed===undefined){
            add_log("进度保存失败!请联系作者反馈","err");
        }
        return obj.isPassed;
    }
    //刷直播用的
    async function live_s(streamName,vdoid,jobid,uid,knowledgeId,clazzid,courseid){
        let url='https://live.chaoxing.com/courseLive/newpclive?streamName=' + streamName + '&vdoid=' + vdoid + '&width=630&height=530&jobid=' + jobid + '&userId='+uid+'&knowledgeid='+knowledgeId+'&ut=s&clazzid='+clazzid+'&courseid='+courseid;
        let obj=await requests(url);
        console.log(obj);
    }
    //刷文档
    async function document_s(jobid,knowledgeId,courseid,clazzid,jtoken){
        let url='https://mooc1-2.chaoxing.com/ananas/job/document?jobid='+jobid+'&knowledgeid='+knowledgeId+'&courseid='+courseid+'&clazzid='+clazzid+'&jtoken='+jtoken+'&_dc=1607066762782';
        let obj=await requests(url);
        if(obj.status===true){
            add_log("文档-"+obj.msg);
        }else{
            console.log(url);
            add_log("文档-"+obj.msg,"err");
        }
    }
    //学习次数
    async function log_s(courseid,clazzid,cpi){
        let url = "https://mooc1-2.chaoxing.com/visit/stucoursemiddle?courseid="+courseid+"&clazzid="+clazzid+"&vc=1&cpi="+cpi;
        let obj=await requests(url);
        url="https://fystat-ans.chaoxing.com/log/setlog"+obj.split("/log/setlog")[1].split('">')[0];
        obj=await requests(url);
        console.log(url);
        if(obj=="'success'"){
            add_log("成功增加学习次数");
        }
    }
    //章节
    async function task(workId,courseId,clazzId,knowledgeId,jobId,enc,cpi){
        let url="https://mooc1-api.chaoxing.com/work/phone/work?workId="+workId+"&courseId="+courseId+"&clazzId="+clazzId+"&knowledgeId="+knowledgeId+"&jobId="+jobId+"&enc="+enc+"&cpi="+cpi;
        console.log(url);
        let obj=await requests(url);
        console.log(obj);
    }
    async function know_start(courseStartData){
        //获取课程知识点
        let courseKnowData={};
        for(let courseData of courseStartData){
            add_log("正在获取【"+courseData[0]+"】课程任务点");
            let debug=false;
            let url="https://mooc1-api.chaoxing.com/gas/clazz?id="+courseData[2]+"&personid="+courseData[3]+"&fields=id,bbsid,classscore,isstart,allowdownload,chatid,name,state,isthirdaq,isfiled,information,discuss,visiblescore,begindate,coursesetting.fields(id,courseid,hiddencoursecover,hiddenwrongset,coursefacecheck),course.fields(id,name,infocontent,objectid,app,bulletformat,mappingcourseid,imageurl,teacherfactor,jobcount,expandreadstate,knowledge.fields(id,name,indexOrder,parentnodeid,status,layer,label,jobcount,begintime,endtime,attachment.fields(id,type,objectid,extension).type(video)))&view=json"
            let obj=await requests(url);
            debug&&console.log(obj);
            let knowlist=obj.data[0].course.data[0].knowledge.data.filter(function(value){
                if(value.parentnodeid===0){
                    courseKnowData[value.id]=[];
                }else{
                    if(courseKnowData[value.parentnodeid]===undefined){
                        courseKnowData[value.parentnodeid]=[]
                    }
                    courseKnowData[value.parentnodeid].push(value)
                }
                return true;
                return value.status==="open";
            });
            let knowlistId=[];
            for(let keys in courseKnowData){
                for(let ids in courseKnowData[keys]){
                    knowlistId.push(courseKnowData[keys][ids].id);
                }
            }
            let data ="courseid="+courseData[1]+"&clazzid="+courseData[2]+"&cpi="+courseData[3]+"&nodes="+knowlistId.join(",")+"&time="+(new Date()).valueOf()+"&userid="+uid+"&view=json";
            $("#pattern").val()==="2"?add_log("已选择复习模式,开始补时长"):add_log("正在过滤已完成和未解锁的任务点..");
            //筛选未完成知识点
            obj=await requests("https://mooc1-api.chaoxing.com/job/myjobsnodesmap",data,"post");
            debug&&console.log(obj);
            let unfinishlist=knowlist.filter(function(value){
                if((value.jobcount!==0&&obj[value.id].unfinishcount!==0)||$("#pattern").val()==="2"){
                    return true;
                }
            });
            debug&&console.log(unfinishlist);
            let unfinishlists=unfinishlist.map(function(value){
                return value.id;
            });
            //console.log(unfinishlists);
            //开整
            add_log("start 开整!");
            for(let val of knowlistId){
                //取章节内的知识点
                //console.log(val);
                if(!unfinishlists.includes(val)){
                    continue;
                }
                add_log("取任务点中的视频");
                url = "https://mooc1-api.chaoxing.com/gas/knowledge?id="+val+"&courseid="+courseData[1]+"&fields=id,parentnodeid,indexorder,label,layer,name,begintime,createtime,lastmodifytime,status,jobUnfinishedCount,clickcount,openlock,card.fields(id,knowledgeid,title,knowledgeTitile,description,cardorder).contentcard(all)&view=json";
                obj=await requests(url);
                let out = await sleep(1000);
                let cardData=obj.data[0].card.data.map(function(value){
                    try {
                        return [value.cardorder,value.knowledgeid,$(value.description).find("iframe").attr("module")];
                    } catch(err){
                        add_log("module不存在!","err");
                        return [];
                    }
                });
                log_s(courseData[1],courseData[2],courseData[3]);
                for(let cardData1 of cardData){
                    url = "https://mooc1-api.chaoxing.com/knowledge/cards?clazzid="+courseData[2]+"&courseid="+courseData[1]+"&knowledgeid="+cardData1[1]+"&num="+cardData1[0]+"&isPhone=0&control=true&cpi="+courseData[3];
                    //console.log(url);
                    let text=await requests(url);
                    console.log(url);
                    let out = await sleep(1000);
                    let result_json;
                    try {
                        result_json=$.parseJSON("{" + text.split("mArg = {")[1].split("};")[0] + "}").attachments;
                    } catch(err){
                        add_log("不出意外的话章节未开放");
                        break;
                    }
                    console.log(result_json);
                    debug&&console.log(result_json);
                    for(let val1 of result_json){
                        debug&&console.log(val1);
                        let objectid,enc,workid,streamName,vdoid,jtoken,jobid,workenc,module;

                        switch(val1.type){
                            case "video"://视频
                                add_log("正在看视频 : "+val1.property.name);
                                objectid=val1.objectId;
                                jobid=val1.jobid;
                                module=val1.property.module
                                await video_s(objectid,cardData1[1],courseData[3],courseData[2], jobid,uid,val1.otherInfo,val1.property.rt||"0.9",module);
                                break;
                            case "live"://直播
                                add_log("直播任务点,暂时不做 ps:有号提供给作者可以加速上线","err");
                                streamName=val1.property.streamName;
                                vdoid=val1.property.vdoid;
                                break;
                            case "document"://文档
                                add_log("正在看文档: "+val1.property.name);
                                jtoken=val1.jtoken
                                jobid=val1.jobid||val1.property._jobid;
                                document_s(jobid,cardData1[1],courseData[1],courseData[2],jtoken)
                                break;
                            case "bookname"://阅读
                                add_log("book任务点,暂时不做 ps:有号提供给作者可以加速上线","err");
                                jtoken=val1.jtoken
                                break;
                            case "workid"://章节作业
                                workenc = val1.enc;
                                workid = val1.property.workid;
                                jobid=val1.jobid;
                                //task(workid,courseData[1],courseData[2],cardData1[1],jobid,workenc,courseData[3])
                                add_log("当前知识点 : 章节测验- "+val1.property.title+" ps:章节请使用答题专版完成","err");
                                //好好学习天天向上
                                break
                            default:
                                break
                        }
                        debug&&console.log(val1);
                    }
                }
                //break;
            }
        };
        add_log("end 任务已完成!");

    }
    function dateFormat(fmt, date) {
        let ret;
        const opt = {
            "Y+": date.getFullYear().toString(),
            "m+": (date.getMonth() + 1).toString(),
            "d+": date.getDate().toString(),
            "H+": date.getHours().toString(),
            "M+": date.getMinutes().toString(),
            "S+": date.getSeconds().toString()
        };
        for (let k in opt) {
            ret = new RegExp("(" + k + ")").exec(fmt);
            if (ret) {
                fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
            };
        };
        return fmt;
    }
    function add_log(text,type="succ"){
        if($("#log").find("div").length>12){
            $("#log").find("div")[0].remove()
        }
        let date = new Date();
        if(type==="succ"){
            $("#log").append('<div>'+dateFormat("YYYY-mm-dd HH:MM", date)+"  "+text+'</div>');
        }else{
            $("#log").append('<div style="color:red;">'+dateFormat("YYYY-mm-dd HH:MM", date)+"  "+text+'</div>');
        }
    }
    async function init(){
        document.body.innerHTML = '<div><div class="layui-row layui-col-space15"><div class="layui-col-md6 layui-col-md-offset3"><div style="padding:50px;border-radius:20px" class="layui-panel" id="app"></div></div></div></div>';
        $("#app").append('<h1>超星网课小助手-视频专版 v'+script_info.version+'</h1>');
        $("#app").append("<div>近期遭到频繁DDOS攻击,若出现不能使用,请耐心等待<br /> 交流群: 633087348</div>");
        //获取用户个人信息
        $("#app").append("<div>脚本仅供学习研究,请勿用于非法用途</div><form  class='layui-form'  id='app2'></form>");
        $("#app2").append('<div><label class="layui-form-label">学习模式</label><div class="layui-input-block"><select id="pattern""><option value="1">正常模式</option><option value="2">复习模式(用于补时长)</option></select></div></div>');
        $("#app2").append('<div><label class="layui-form-label">学习速度</label><div class="layui-input-block"><select id="beisu"><option value="1">1倍速</option><option value="2">2倍速</option><option value="4">4倍速</option><option value="8">8倍速</option><option value="16">16倍速</option><option value="9999">秒刷</option></select><span style="color:red">请一倍速使用,目前其他倍速均会被打回。</span></div></div>');
        $("#app2").append('<label class="layui-form-label">科目选择</label><div class="layui-input-block"><select id="course_choose"><option value="0">全刷</option></select><button class="layui-btn layui-btn-primary layui-border-blue" type="button" id="start_btn">开始</button>');
        $("#app2").append('<div id="log" style="color: blue;"></div>');
        let debug=true;
        add_log("正在尝试获取课程信息...(长时间无动静为加载失败,请退出超星后重新登录)");
        // 从cookie获取uid
        try{
            uid = document.cookie.match(/UID=([^;]+)/)[1];
        }
        catch(e){
            add_log("获取UID失败,请退出超星后重新登录","err");
            return;
        }
        //获取课程列表
        let obj=await requests('https://mooc1-api.chaoxing.com/mycourse/backclazzdata?view=json&mcode=');
        console.log(obj);
        courseList=obj.channelList.map( function(value,index){
            if(value.content.course){
                $("#course_choose").append('<option value="'+value.content.course.data[0].id+'">'+value.content.course.data[0].name+'</option>');
                form.render('select');
                return [value.content.course.data[0].name,value.content.course.data[0].id,value.key,value.cpi];
            }else{
                return [0,0,0,0];
            }
        });
        debug&&console.log(courseList);
        add_log("共获取"+courseList.length+"门课程");
        $("body").append("<h3 id='msg'></h3>");
        $("#start_btn").on('click',function(){
            let courseStartData=courseList.filter(function (value){
                if(value[0]===0){
                    return false;
                }
                if(value[1].toString()===$("#course_choose").val()||$("#course_choose").val()==="0"){
                    return true;
                }
                return false;
            })

            know_start(courseStartData);
        });

    }
    $('head').append('<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"><link href="https://lib.baomitu.com/layui/2.6.8/css/layui.css" rel="stylesheet" type="text/css" />');
    $.getScript("https://lib.baomitu.com/layui/2.6.8/layui.js", function(data, status, jqxhr) {
        layui=unsafeWindow.layui;
        layer=unsafeWindow.layer;
        form = layui.form;
        $(".root").remove();
        if(location.href.indexOf("base/settings")!=-1){
            init();
        }else if(location.href.indexOf("visit/interaction")!=-1){
            $(".btn_group").append('<a id="addCourse" class="jb_btn jb_btn_104 fs14" href="https://i.chaoxing.com/base/settings" target="_top">打开挂机页面</a>');
        }
    });
})();