在##大学 MOOC 的课程学习页面添加批量下载按钮,方便将视频下载到本地学习
// ==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.r###lt.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.r###lt.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; } } }); } })();