Greasy Fork

Greasy Fork is available in English.

Udemy下载助手(需配合Aria2使用)

在 Udemy 上课程的课程内容页面添加下载按钮(可批量下载和单个视频下载),方便将视频下载到本地学习

当前为 2018-08-25 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name              Udemy下载助手(需配合Aria2使用)
// @name:en           Udemy Downloader
// @namespace         http://mofiter.com/
// @version           0.1
// @description       在 Udemy 上课程的课程内容页面添加下载按钮(可批量下载和单个视频下载),方便将视频下载到本地学习
// @description:en    add button on udemy's course content to download videos
// @author            mofiter
// @create            2018-07-31
// @lastmodified      2018-08-25
// @require           https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js
// @match             http*://www.udemy.com/*/learn/v4/content
// @grant             GM_getValue
// @grant             GM_setValue
// ==/UserScript==

(function() {
    'use strict';
    var $ = $ || window.$;
    var log_count = 1;
    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;
                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;
                            chapter.lecture_info = [];
                        }
                    }else if(item._class == 'lecture'){
                        var lecture = {'lecture_sn':(++lecture_sn),'lecture_id':item.id,'lecture_name':item.title,'lecture_asset':{'asset_id':item.asset.id,'asset_name':item.asset.title,'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);
                    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
                }
            ]
        };
        $.ajax({
            url:aria2_url,
            type:'POST',
            crossDomain:true,
            processData:false,
            data:JSON.stringify(json_rpc),
            contentType: 'application/json',
            success:function(response){
                mylog(response);
            }
        });
    }

})();