Rain Classroom PDF Direct Download

Automatic generation of direct download PDF on Rain Classroom

目前為 2021-03-27 提交的版本,檢視 最新版本

/* globals jspdf UPNG */

// ==UserScript==
// @name         Rain Classroom PDF Direct Download
// @name:zh-CN   雨课堂课件PDF下载工具
// @namespace    https://www.pizyds.com/
// @version      1.0.2
// @description  Automatic generation of direct download PDF on Rain Classroom
// @description:zh-CN 在雨课堂页面自动生成PDF版本课件提供下载
// @author       PillarsZhang
// @homepage     https://www.pizyds.com/rain-classroom-pdf-direct-download
// @license      MIT
// @match        https://www.yuketang.cn/v2/web/student*
// @icon         https://www.yuketang.cn/static/images/favicon.ico
// @require      https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.3.1/jspdf.umd.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/pako/2.0.3/pako.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/upng-js/2.1.0/UPNG.min.js
// @resource     pizyds_iconfont_css https://at.alicdn.com/t/font_2448118_l5d66dc50k9.css
// @grant        GM_getResourceText
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';
    //jsPDF用于PDF生成,UPNG、pako用于PNG的反交错和压缩
    const {jsPDF} = jspdf;

    //下载的图标,感谢iconfont
    const pizyds_iconfont_css = GM_getResourceText("pizyds_iconfont_css");
    GM_addStyle(pizyds_iconfont_css);

    //实时查找PPT窗口
    setInterval(()=>{
        var el_dialog = find_basePPTDialog();
        el_dialog && add_button_download(el_dialog);
    },500);

    //按钮触发PDF生成逻辑
    function download_process(el_dialog){
        var url_slides = get_url_slides(el_dialog);
        if (url_slides.length > 0){
            refreshProcessStatus("处理图片...");
            image_process(url_slides)
                .then(img_list => {
                refreshProcessStatus("生成PDF...");
                var ppt_name = document.getElementsByClassName("ppt_name")[0].innerText;
                var filename = ppt_name + ".pdf";
                pdf_process(img_list, filename);
                refreshProcessStatus("下载课件");
            })
        } else{
            alert("雨课堂课件PDF下载工具:没有提取到图片");
        }
    }

    //第一步-借助UPNG,进行图片下载与反交错、压缩处理
    function image_process(url_slides){
        var promiseList = new Array(url_slides.length);
        var finished_num = 0;
        var count_finished_num = (index) => {
            var processStatus = `${++finished_num}/${url_slides.length}`;
            refreshProcessStatus(`处理图片(${processStatus})`);
            console.log(`${processStatus} - 第${index+1}页 - ${url_slides[index]} - finished`);
        }
        for (let i = 0; i < url_slides.length; i++){
            promiseList[i] = fetch(url_slides[i]).then(response => {
                return response.arrayBuffer();
            }).then(arrayBuffer_origin => {
                var img = UPNG.decode(arrayBuffer_origin);
                var rgba = UPNG.toRGBA8(img);
                var arrayBuffer_compress = UPNG.encode(rgba, img.width, img.height, 0);
                count_finished_num(i);
                return {unit8: new Uint8Array(arrayBuffer_compress), width: img.width, height: img.height};
            }).catch(err => {
                console.error(err);
                alert("雨课堂课件PDF下载工具:图像处理出错");
            });
        }
        return Promise.all(promiseList);
    }

    //第二步-借助jsPDF,进行PDF的生成
    function pdf_process(img_list, filename){
        var doc = new jsPDF({
            orientation: "landscape",
            unit: "px",
            format: [img_list[0].width, img_list[0].height],
            hotfixes: ["px_scaling"]
        });
        doc.addImage(img_list[0].unit8, 'PNG', 0, 0, img_list[0].width, img_list[0].height);
        for (let i = 1; i < img_list.length; i++){
            doc.addPage([img_list[i].width, img_list[i].height], "landscape");
            doc.addImage(img_list[i].unit8, 'PNG', 0, 0, img_list[i].width, img_list[i].height);
        }
        doc.save(filename);
    }

    //按钮文本刷新
    function refreshProcessStatus(processStatus){
        var el_download = document.getElementsByClassName("pizyds_download")[0];
        el_download.innerHTML = `<i class="iconfont icon-pizyds-rain-down-xiazai"></i> ${processStatus}`;
    }

    //查找PPT窗口
    function find_basePPTDialog(){
        var el_dialogs = document.getElementsByClassName("basePPTDialog");
        if (el_dialogs.length == 1){
            return el_dialogs[0];
        } else{
            return false;
        }
    }

    //PPT图片链接提取
    function get_url_slides(el_dialog){
        try{
            var el_swiper = el_dialog.getElementsByClassName("pptSwiper")[0];
            var el_slides = el_swiper.getElementsByClassName("swiper-slide");
            var url_slides = new Array(el_slides.length);
            for(let i = 0; i < el_slides.length; i++){
                url_slides[i] = el_slides[i].getElementsByTagName("img")[0].src;
            }
            return url_slides;
        } catch(err){
            return new Array();
        }
    }

    //按钮注入
    function add_button_download(el_dialog){
        var el_header = el_dialog.getElementsByClassName("layout_header")[0];
        if (el_header.getElementsByClassName("pizyds_download").length == 0){
            var el_download = create_node_from_html(`<span class="print pizyds_download" style="right:120px">
              <i class="iconfont icon-pizyds-rain-down-xiazai"></i> 下载课件</span>`);
            el_download.onclick = () => download_process(el_dialog);
            el_header.appendChild(el_download);
            return true;
        } else{
            return false;
        }
    }

    //HTML字符串转节点
    function create_node_from_html(html){
        let template = `<div class='child'>${html}</div>`;
        let tempNode = document.createElement('div');
        tempNode.innerHTML = template;
        return tempNode.firstChild;
    }
})();