Icourse163 Downloader

add download button on icourse163.org to download videos

Install this script?
Author's suggested script

You may also like Study163 Downloader.

Install this script

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name              中国大学 MOOC 下载助手(需配合Aria2使用)
// @name:en           Icourse163 Downloader
// @namespace         http://mofiter.com/
// @version           0.3
// @description       在中国大学 MOOC 的课程学习页面添加批量下载按钮,方便将视频下载到本地学习
// @description:en    add download button on icourse163.org to download videos
// @author            mofiter
// @require           https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js
// @match             *://www.icourse163.org/learn/*
// @grant             unsafeWindow
// @grant             GM_getValue
// @grant             GM_setValue
// @grant             GM_xmlhttpRequest
// @grant             GM_openInTab
// ==/UserScript==

(function() {
    'use strict';
    var $ = $ || window.$;
    var log_count = 1;
    var hasOpenAriac2Tab = false;
    var video_quality = 2; //视频清晰度
    var video_format = 'mp4'; //视频格式
    var aria2_url = "http://127.0.0.1:6800/jsonrpc"; //Aria2 地址
    var course_save_path = '/Users/mofiter/Downloads/icourse163'; //课程保存路径
    var video_save_path; //每个视频保存路径
    var video_download_url = ""; //视频下载地址
    var course_info = {'course_id': {},'course_name': {},'chapter_info': []}; //课程信息
    var cookies = document.cookie;
    var sessionId = cookies.match(/NTESSTUDYSI=(\w+)/)[1];

    //自定义 log 函数
    function mylog(param1,param2){
        param1 = param1 ? param1 : "";
        param2 = param2 ? param2 : "";
        console.log("#" + log_count++ + "-Icourse163Downloader-log:",param1,param2);
    }

    setTimeout(function(){
        getCourseIdAndName();
        getCourseContentInfo();
        loadSetting();
        addDownloadAssistant();
        mylog("中国大学 MOOC 下载助手加载完成~");
    },2000); //页面加载完成后延时2秒执行

    //获取课程名称
    function getCourseIdAndName(){
        var courseCardDto = unsafeWindow.courseCardDto;
        course_info.course_name = courseCardDto.name.replace(/\/|:|\?|\*|"|<|>|\|/g," ");
        if(location.href.match(/tid=(\d+)/)[1]){
            course_info.course_id = location.href.match(/tid=(\d+)/)[1];
        }else{
            course_info.course_id = courseCardDto.currentTermId;
        }
    }

    //添加批量下载和下载设置按钮
    function addDownloadAssistant(){
        var batch_download_li = $("<li class='u-greentab'></li>");
        var batch_download = $("<a>批量下载</a>");
        batch_download_li.append(batch_download);
        var assistant_setting_li = $("<li class='u-greentab'></li>");
        var assistant_setting = $("<a>下载设置</a>");
        assistant_setting_li.append(assistant_setting);
        $('#j-courseTabList').append(batch_download_li).append(assistant_setting_li);
        batch_download_li.click(function(){
            loadSetting();
            if(course_save_path==""){
                alert("请点击下载设置去填写文件保存位置");
            }else if(aria2_url==""){
                alert("请点击下载设置去填写 Aria2 地址");
            }else{
                batchDownload();
            }
        });
        assistant_setting_li.click(function(){
            showSetting();
        });
    }

    //加载个人设置
    function loadSetting(){
        video_quality = GM_getValue('video_quality', 2);
        video_format = GM_getValue('video_format','mp4');
        aria2_url = GM_getValue('aria2_url','http://127.0.0.1:6800/jsonrpc');
        course_save_path = GM_getValue('course_save_path','');
    }

    //打开设置
    function showSetting(){
        if(document.querySelector('#dl-setting') == null){
            var container = document.createElement("div");
            container.id = "dl-setting";
            container.style = "position:fixed;z-index:999999;bottom:10%;right:40px;width:220px;height:auto;background-color:#f8f8f8;padding:5px 10px;font-size:14px;border:1px solid #ccc;";
            container.innerHTML =
            "<div style='line-height:25px;'>" +
            "<legend style='text-align:center;font-size:16px;'>下载设置</legend>" +
            "<ul>" +
            "<li>Aria2 地址:</li>" +
            "<li><input type='text' id='aria2_url' name='aria2_url' value='" + aria2_url + "' style='width:100%;background:#ffffff;'></input></li>" +
            "<li>文件保存位置:</li>\n" +
            "<li><input type='text' id='save_path' name='save_path' value='" + course_save_path + "' style='width:100%;background:#ffffff;'></input></li>" +
            "<li>清晰度:<label title='高清'><input id='video-quality-2' name='video-quality' value='2' type='radio' style='margin:0 5px;'" + (video_quality==2 ? "checked":"") + "></input>高清</label>\n" +
            "<label title='标清' style='padding:0 5px;'><input id='video-quality-1' name='video-quality' value='1' type='radio' style='margin:0 5px;'" + (video_quality==1 ? "checked":"") + "></input>标清</label></li>\n" +
            "<li>格式:<label title='mp4' style='padding:0 0 0 14px;'><input id='video-format-mp4' name='video-format' value='mp4' type='radio' style='margin:0 5px;'" + (video_format=='mp4' ? "checked":"") + "></input>mp4</label>" +
            "<label title='flv' style='padding:0 5px;'><input id='video-format-flv' name='video-format' value='flv' type='radio' style='margin:0 5px 0 10px;'" + (video_format=='flv' ? "checked":"") + "></input>flv</label></li>" +
            "</ul>\n" +
            "<input type='button' value='取消' id='cancel_button' style='position:relative;float:left;border:1px solid #ccc;padding:0 2px;background:#ffffff;'></input>\n" +
            "<input type='button' value='保存' id='save_button' style='position:relative;float:right;border:1px solid #ccc;padding:0 2px;background:#ffffff;'></input>\n" +
            "</div>";
            document.body.appendChild(container);
        }else{
            loadSetting();
            if(video_quality==2){
                $('#video-quality-2').prop('checked',true);
            }else{
                $('#video-quality-1').prop('checked',true);
            }
            if(video_format=='mp4'){
                $('#video-format-mp4').prop('checked',true);
            }else{
                $('#video-format-flv').prop('checked',true);
            }
            $('#aria2_url').value = aria2_url;
            $('#save_path').value = course_save_path;
            $('#dl-setting').show();
        }
        $('#save_button').click(function(){
            GM_setValue('video_quality',$('input[name="video-quality"]:checked').val());
            GM_setValue('video_format',$('input[name="video-format"]:checked').val());
            GM_setValue('aria2_url',$('input[name="aria2_url"]').val());
            GM_setValue('course_save_path',$('input[name="save_path"]').val());
            $('#dl-setting').hide();
        });
        $('#cancel_button').click(function(){
            $('#dl-setting').hide();
        });
    }

    //获取课程信息
    function getCourseContentInfo(){
        var timestamp = new Date().getTime();
        var params = {
            "callCount":"1",
            "scriptSessionId":"${scriptSessionId}190",
            "httpSessionId":sessionId,
            "c0-scriptName":"CourseBean",
            "c0-methodName":"getLastLearnedMocTermDto",
            "c0-id":"0",
            "c0-param0":"number:" + course_info.course_id,
            "batchId":timestamp
        };
        $.ajax({
            url:'https://www.icourse163.org/dwr/call/plaincall/CourseBean.getLastLearnedMocTermDto.dwr',
            method:'POST',
            async: true,
            data: params,
            success: function (response){
                var chapter1 = response.match(/chapters=(.*?);/)[1]; //保存全部章节的变量
                var reg1 = new RegExp(chapter1 + '\\[\\d+]=(.*?);','g');
                var chapter2 = response.match(reg1); //保存各章节的变量
                chapter2.forEach(function(value){
                    var chapter3 = value.match(/=(.*?);/)[1]; //保存各章节的变量名字
                    var reg2 = new RegExp(chapter3 + '.id=(.*?);' + chapter3 + '.lessons=(.*?);' + chapter3 + '.name="(.*?)";');
                    var chapter4 = response.match(reg2); //保存章节 id,lessons,name 的变量
                    var reg3 = new RegExp(chapter4[2] + '\\[\\d+]=(.*?);','g');
                    var lessons = response.match(reg3); //保存各小节的变量
                    var chapter = {'chapter_id':chapter4[1],'chapter_name':unescape(chapter4[3].replace(/\\u/gi, '%u').replace(/\/|:|\?|\*|"|<|>|\|/g," ")),'lesson_info':[]};
                    lessons.forEach(function(value){
                        var lesson1 = value.match(/=(.*?);/)[1]; //保存各小节的变量名字
                        var reg4 = new RegExp(lesson1 + '.chapterId=(.*?);.*?' + lesson1 + '.id=(.*?);.*?' + lesson1 + '.name="(.*?)";.*?' + lesson1 + '.units=(.*?);');
                        var lesson2 = response.match(reg4);
                        var reg5 = new RegExp(lesson2[4] + '\\[\\d+]=(.*?);','g');
                        var sections = response.match(reg5);
                        var lesson = {'chapter_id':lesson2[1],'lesson_id':lesson2[2],'lesson_name':unescape(lesson2[3].replace(/\\u/gi, '%u').replace(/\/|:|\?|\*|"|<|>|\|/g," ")),'section_info':[]};
                        sections.forEach(function(value){
                            var section1 = value.match(/=(.*?);/)[1];
                            var reg6 = new RegExp(section1 + '.chapterId=(.*?);.*?' + section1 + '.contentId=(.*?);.*?' + section1 + '.contentType=(.*?);.*?' + section1 + '.id=(.*?);.*?' + section1 + '.lessonId=(.*?);.*?' + section1 + '.name="(.*?)";.*?');
                            var section2 = response.match(reg6);
                            var section = {'chapter_id':section2[1],'lesson_id':section2[5],'content_id':section2[2],'section_id':section2[4],'section_name':unescape(section2[6].replace(/\\u/gi, '%u').replace(/\/|:|\?|\*|"|<|>|\|/g," ")),'content_type':section2[3]};
                            lesson.section_info.push(section);
                        });
                        chapter.lesson_info.push(lesson);
                    });
                    course_info.chapter_info.push(chapter);
                });
                mylog(course_info);
            }
        });
    }

    //批量下载
    function batchDownload(){
        course_info.chapter_info.forEach(function(chapter,index_chapter){
            chapter.lesson_info.forEach(function(lesson,index_lesson){
                lesson.section_info.forEach(function(section,index_section){
                    var file_name = '第' + (index_section + 1) + '部分_' + section.section_name;
                    var save_path = course_save_path.replace(/\\/g,'\/') + '/' + course_info.course_name + '/第' + (index_chapter + 1) + '章_' + chapter.chapter_name + '/第' + (index_lesson + 1) + '节_' + lesson.lesson_name;
                    if(section.content_type == '1'){
                        getVideoToken(section.content_id,file_name,save_path);
                    } else if(section.content_type == '3'){
                        getCourseContentUrl(section.content_id,section.section_id,file_name,save_path);
                    }
                });
            });
        });
    }

    //获取文档下载地址
    function getCourseContentUrl(content_id,section_id,file_name,save_path){
        var timestamp = new Date().getTime();
        var params = {
            "callCount":"1",
            "scriptSessionId":"${scriptSessionId}190",
            "httpSessionId":sessionId,
            "c0-scriptName":"CourseBean",
            "c0-methodName":"getLessonUnitLearnVo",
            "c0-id":"0",
            "c0-param0":"number:" + content_id,
            "c0-param1":"number:3",
            "c0-param2":"number:0",
            "c0-param3":"number:" + section_id,
            "batchId":timestamp
        };
        $.ajax({
            url:'https://www.icourse163.org/dwr/call/plaincall/CourseBean.getLessonUnitLearnVo.dwr',
            method:'POST',
            async: true,
            data: params,
            success: function (response){
                var pdfUrl = response.match(/textOrigUrl:"(.*?)",/)[1];
                //mylog(pdfUrl);
                sendDownloadTaskToAria2(pdfUrl,file_name + ".pdf",save_path);
            }
        });
    }

    //获取视频信息
    function getVideoToken(content_id,file_name,save_path){
        var params = {
            'videoId':content_id,
            'targetId':course_info.course_id,
            'targetType':'0'
        };
        $.ajax({
            url:'https://www.icourse163.org/web/j/resourceRpcBean.getVideoToken.rpc?csrfKey=' + sessionId,
            method:'POST',
            async: true,
            data: params,
            success: function (response){
                var signature = response.result.signature;
                getVideoUrl(content_id,signature,file_name,save_path);
            }
        });
    }

    //获取视频下载地址
    function getVideoUrl(content_id,signature,file_name,save_path){
        var params = {
            'videoId':content_id,
            'signature':signature,
            'clientType':'1'
        };
        $.ajax({
            url:'https://vod.study.163.com/eds/api/v1/vod/video',
            method:'POST',
            async: true,
            data: params,
            success: function (response){
                var videoUrls = response.result.videos;
                var video_url_list = [];
                videoUrls.forEach(function(video){
                    if(video.format == video_format) {
                        video_url_list.push({'video_format': video.format,'video_quality': video.quality,'video_url': video.videoUrl});
                    }
                });
                if(video_url_list.length != 0){
                    if(video_quality=="2"){
                        video_download_url = video_url_list[video_url_list.length-1].video_url;
                    }else{
                        video_download_url = video_url_list[0].video_url;
                    }
                }
                if(video_download_url != ""){
                    //mylog(video_download_url);
                    sendDownloadTaskToAria2(video_download_url,file_name + '.' + video_format,save_path);
                }
            }
        });
    }

    // 将下载链接发送到 Aria2 下载
    function sendDownloadTaskToAria2(download_url,file_name,save_path){
        var json_rpc = {
            id:'',
            jsonrpc:'2.0',
            method:'aria2.addUri',
            params:[
                [download_url],
                {
                    dir:save_path,
                    out:file_name
                }
            ]
        };
        GM_xmlhttpRequest({
            url:aria2_url,
            method:'POST',
            data:JSON.stringify(json_rpc),
            onerror:function(response){
                mylog(response);
            },
            onload:function(response){
                mylog(response);
                if (!hasOpenAriac2Tab){
                    GM_openInTab('http://aria2c.com/',{active:true});
                    hasOpenAriac2Tab = true;
                }
            }
        });
    }

})();