add button on udemy's course content to download videos
// ==UserScript== // @name Udemy下载助手(需配合Aria2使用) // @name:en Udemy Downloader // @namespace http://mofiter.com/ // @version 0.3 // @description 在 Udemy 上课程的课程内容页面添加下载按钮(可批量下载和单个视频下载),方便将视频下载到本地学习 // @description:en add button on udemy's course content to download videos // @author mofiter // @require https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js // @match *://www.udemy.com/*/learn/v4/content // @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 = "720"; //视频清晰度 var aria2_url = "http://127.0.0.1:6800/jsonrpc"; //Aria2 地址 var course_save_path = '/Users/mofiter/Downloads/study163'; //课程保存路径 var mycourses_url = "https://www.udemy.com/api-2.0/users/me/subscribed-courses"; //已购所有课程的地址 var curricuclum_url = "https://www.udemy.com/api-2.0/courses/{0}/cached-subscriber-curriculum-items/?page_size=9999"; //当前课程的地址 var lesson_url = "https://www.udemy.com/api-2.0/assets/{0}?fields[asset]=@min,status,delayed_asset_message,time_estimation,stream_urls,captions,body&fields[caption]=@default,is_translation"; //一节课的地址 var cookies = document.cookie; var match_cookie = cookies.match(/access_token=(\w+?);/); var authorization = "Bearer " + match_cookie[1]; var mycourses_info; var current_course_url = location.pathname; var current_course_info = {'course_id':{},'course_name':{},'chapter_info':[]}; var isExpand = false; //下载助手是否展开 //自定义 log 函数 function mylog(param1,param2){ param1 = param1 ? param1 : ""; param2 = param2 ? param2 : ""; console.log("#" + log_count++ + "-UdemyDownloader-log:",param1,param2); } //javascript 字符串使用占位符轻松拼接 String.prototype.format = function() { if(arguments.length == 0) return this; var param = arguments[0]; var s = this; if(typeof(param) == 'object') { for(var key in param) {s = s.replace(new RegExp("\\{" + key + "\\}", "g"), param[key]);} return s; } else { for(var i = 0; i < arguments.length; i++) {s = s.replace(new RegExp("\\{" + i + "\\}", "g"), arguments[i]);} return s; } } setTimeout(function(){ getCourseInfo(); loadSetting(); addDownloadAssistant(); addDownloadButton(); mylog("Udemy 下载助手加载完成 ~"); },5000); //页面加载完成后延时5秒执行 //获取视频信息 function getCourseInfo(){ $.ajax({ url:mycourses_url, async:false, method:'GET', beforeSend:function(xhr){ xhr.setRequestHeader('authorization',authorization); }, success:function(response){ mycourses_info = response.results; } }); $.each(mycourses_info,function(index,element){ if (current_course_url.indexOf(element.url) > -1) { current_course_info.course_id = element.id; current_course_info.course_name = element.title.replace(/:|\?|\*|"|<|>|\|/g," "); return false; } }); curricuclum_url = curricuclum_url.format(current_course_info.course_id); $.ajax({ url:curricuclum_url, async:false, method:'GET', beforeSend:function(xhr){ xhr.setRequestHeader('authorization',authorization); }, success:function(response){ var list = response.results; list.push({'_class':'chapter','id':'useless','title':''}); var chapter = {'chapter_id':'','chapter_name':{},'lecture_info':[]}; var lecture_sn = 0; list.forEach(function(item,index){ if(item._class == 'chapter'){ if(chapter.chapter_id != ''){ var data = JSON.parse(JSON.stringify(chapter)); current_course_info.chapter_info.push(data); } if(item.id != 'useless'){ chapter.chapter_id = item.id; chapter.chapter_name = item.title.replace(/:|\?|\*|"|<|>|\|/g," "); chapter.lecture_info = []; } }else if(item._class == 'lecture'){ var lecture = {'lecture_sn':(++lecture_sn),'lecture_id':item.id,'lecture_name':item.title.replace(/:|\?|\*|"|<|>|\|/g," "),'lecture_asset':{'asset_id':item.asset.id,'asset_name':item.asset.title.replace(/:|\?|\*|"|<|>|\|/g," "),'asset_type':item.asset.asset_type}}; chapter.lecture_info.push(lecture); } }); mylog(current_course_info); } }); } //添加下载助手按钮 function addDownloadAssistant(){ var download_assistant = $('<li ui-sref-active="active"></li>'); var download_assistant_a = $('<a class="dropdown-toggle"><span class="mr5"><span>下载助手</span></span><i class="udi udi-caret-down"></i></a>'); var assistant_content = $('<div id="assistant_content" style="display:none;z-index:999999;position:absolute;width:90px;background-color:#fff;border:1px solid #ddd;top:55px;padding:5px 10px;text-align:center;line-height:30px;"></div>'); var batch_download = $('<a>批量下载</a>'); var assistant_setting = $('<a>设置</a>'); assistant_content.append(batch_download).append(assistant_setting); download_assistant.append(download_assistant_a).append(assistant_content); $('.nav-tabs').append(download_assistant); download_assistant.click(function(event){ if(isExpand){ isExpand = false; }else{ isExpand = true; } assistant_content.toggle(); event.stopPropagation(); }); $(document).click(function(){ if(isExpand){ assistant_content.hide(); isExpand = false; } }); batch_download.click(function(){ loadSetting(); if(course_save_path==""){ alert("请到下载助手的设置里面填写文件保存位置"); }else if(aria2_url==""){ alert("请到下载助手的设置里面填写 Aria2 地址"); }else{ batchDownload(); } }); assistant_setting.click(function(){ showSetting(); }); } //加载个人设置 function loadSetting(){ video_quality = GM_getValue('video_quality', '720'); 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;top:10%;right:2%;width:270px;background-color:#eee;padding:5px 10px;font-size:14px;border:1px solid;"; container.innerHTML = "<div style='line-height:25px;'>" + "<div style='text-align:center;font-size:16px;'>下载助手设置</div>" + "<ul>" + "<li>Aria2 地址:</li>" + "<li><input type='text' id='aria2_url' name='aria2_url' value='" + aria2_url + "' style='width:100%'></input></li>" + "<li>文件保存位置:</li>" + "<li><input type='text' id='save_path' name='save_path' value='" + course_save_path + "' style='width:100%'></input></li>" + "<li>清晰度:</li>" + "<li><label title='720P'><input id='video-quality-1' name='video-quality' value='720' type='radio' style='margin:0 5px;'" + (video_quality=="720" ? "checked":"") + "></input>720P</label>" + "<label title='480P' style='padding:0 5px;'><input id='video-quality-2' name='video-quality' value='480' type='radio' style='margin:0 5px;'" + (video_quality=="480" ? "checked":"") + "></input>480P</label>" + "<label title='360P' style='padding:0 5px;'><input id='video-quality-3' name='video-quality' value='360' type='radio' style='margin:0 5px;'" + (video_quality=="360" ? "checked":"") + "></input>360P</label>" + "<label title='144P' style='padding:0 5px;'><input id='video-quality-4' name='video-quality' value='144' type='radio' style='margin:0 5px;'" + (video_quality=="144" ? "checked":"") + "></input>144P</label></li>" + "</ul>\n" + "<input type='button' value='取消' id='cancel_button' style='position:relative;float:left;border:1px solid;padding:0 4px;'></input>\n" + "<input type='button' value='保存' id='save_button' style='position:relative;float:right;border:1px solid;padding:0 4px;'></input>\n" + "</div>"; document.body.appendChild(container); }else{ loadSetting(); if(video_quality=="720"){ $('#video-quality-1').prop('checked',true); }else if(video_quality=="480"){ $('#video-quality-2').prop('checked',true); }else if(video_quality=="360"){ $('#video-quality-3').prop('checked',true); }else if(video_quality=="144"){ $('#video-quality-4').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('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 batchDownload(){ current_course_info.chapter_info.forEach(function(chapter,index){ chapter.lecture_info.forEach(function(lecture){ if(lecture.lecture_asset.asset_type == 'Video'){ var file_name = lecture.lecture_sn + '.' + lecture.lecture_name; var save_path = course_save_path.replace(/\\/g,'\/') + '/' + current_course_info.course_name + '/' + (index + 1) + '.' + current_course_info.chapter_info[index].chapter_name; var real_lesson_url = lesson_url.format(lecture.lecture_asset.asset_id); getVideoUrl(real_lesson_url,file_name + '.mp4',save_path); } }); }); } //添加下载按钮 function addDownloadButton(){ var li_items = $('div.section--section--CIk7q li.curriculum-item--curriculum-item--iJwX5'); $.each(li_items,function(index,element){ if (element.firstChild.childNodes[2].innerHTML == '') { element.firstChild.style.paddingRight = "70px"; return true; } var download_button = document.createElement('span'); download_button.className = 'download-button'; download_button.innerHTML = '下载'; download_button.style.order = 5; download_button.style.marginLeft = '20px'; (element.firstChild).append(download_button); }); $('.download-button').each(function(){ $(this).click(function(event){ loadSetting(); if(course_save_path==""){ alert("请到下载助手的设置里面填写文件保存位置"); }else if(aria2_url==""){ alert("请到下载助手的设置里面填写 Aria2 地址"); }else{ var chapter_index = $(this).parents('.section--section--CIk7q').index(); var lecture_index = $(this).parents('.curriculum-item--curriculum-item--iJwX5').index(); var lecture = current_course_info.chapter_info[chapter_index].lecture_info[lecture_index]; mylog("选择的课为【lecture_name:" + lecture.lecture_name + ",lecture_id:" + lecture.lecture_id + '】'); var file_name = lecture.lecture_sn + '.' + lecture.lecture_name; var save_path = course_save_path.replace(/\\/g,'\/') + '/' + current_course_info.course_name + '/' + (chapter_index + 1) + '.' + current_course_info.chapter_info[chapter_index].chapter_name; var real_lesson_url = lesson_url.format(lecture.lecture_asset.asset_id); var url = 'https://www.udemy.com/vuejs-app/learn/v4/t/lecture/{0}?start=0'.format(lecture.lecture_id); getVideoUrl(real_lesson_url,file_name + '.mp4',save_path); } event.stopPropagation(); }); }); } //获取视频下载地址 function getVideoUrl(url,file_name,save_path){ $.ajax({ url:url, async:true, method:'GET', beforeSend:function(xhr){ xhr.setRequestHeader('authorization',authorization); }, success:function(response){ var video_urls = response.stream_urls.Video; video_urls.forEach(function(value){ if (value.label == video_quality){ //mylog(value.file); sendDownloadTaskToAria2(value.file,file_name,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; } } }); } })();