网课的不正经总结

警告: 此文章含有大量javascript/html代码, 请谨慎食用, 不想看代码可以考虑ctrl+w

网课就要结束了~ 开学时间也确定了~ 网课期间我们干了不少事呢~ 在此总结梳理

主线: 上课, 课程软件, 脚本

Sunshine Netclass 时期


The Netclass

一开始我们在阳光网络课堂上课. 阳光网络课堂, 我可以毫不客气地说, 就是一个壳子. 直播平台是CCLive, 阳光网络课堂只是新建了一个账号, 然后做了一个"中介"的角色, 向机构售卖课时, 然后向CCLive缴费, 核心的内容在于与CCLive的协调. 可是, 做这个网站的人和做CCLive的人都没怎么用心, 加上我们一直在探索, 阳光网络课堂的各种草行径就暴露无疑.

首先, 我怀着好奇宝宝的心尝试了用F12分析阳光网络课堂的接口, 加上postman做了简单的请求测试. 观察到阳光网络课堂在登陆之前会检查手机号是否存在, 调用接口

POST http://fudao.xuetang365.com/Home/Common/checkPhoneExist.html

body: phone=phonenumber

POST后反回了如下格式数据

已注册:

{
    "status": 200,
    "msg": "该手机号已注册过",
    "data": {
        "id": "2207936",
        "username": null,
        "realname": "123",
        "avatar": "",
        "role": "100",
        "school_id": "1113",
        "cellphone": "phonenumber",
        "password": "e1fc628c1402ba6c7b3b0926d1ff1b33",
        "salt": "kbFEIy",
        "status": "200",
        "balance": "0.00",
        "skip_id_check": "1584273049",
        "updated": "1586585652",
        "created": "1584273019"
    }
}

未注册:

{
    "status": 400,
    "msg": "该手机号未注册过"
}

并且不需要sign, 即任何人可以请求, 获取信息.

不久后, 老师上课泄露了教师账号和密码, 教师账号为类似 15000000000 的 "手机号". 顺藤摸瓜请求此类 "手机号" 发现 19900000000 后为 "测试账号", 密码一遍试出来为123456, 我们由此得到了同时使用教师端与学生端的机会.

然后, 我注意到阳光登录CCLive的密码不随登录阳光的密码改变, 自此我们拥有了对阳光的永久访问权(bushi)类似于:

https://view.csslcloud.net/api/view/lecturer?roomid=B574DD00E9C5E9AC9C33DC5901307461&userid=18B2799E5FF3520E&publishname=aaa&publishpassword=1eb97fc0c90e99470fbe255f30e95fa4

进一步:

cclive://18B2799E5FF3520E/B574DD00E9C5E9AC9C33DC5901307461/123456/1eb97fc0c90e99470fbe255f30e95fa4

直接登入程序.


后来, 高二的yur他们发现了网课发图片的方法, 网课自此进入新的阶段.


The Picclass

通过yur他们的聊天截屏, 我们逐渐掌握了用 [img_https://*] 发图片的方法, 网课的聊天区从此五彩斑斓起来. (当然, 各种乱七八糟的图片也多了起来)


因为用网站上课, 不可避免的我们试图了解它究竟在干些什么, 于是我们也在不断学习Javascript, 尝试弄清阳光课堂的逻辑.

突然有一天, 我在空间里看到了这样一条动态:

带大家领略一下,华师一信息组是怎么一步步攻占阳光网络课堂平台的

聊天记录

然后我忽然意识到 [img_https://] 里面一定有什么问题, 然后晚上一通对着F12瞎试之后, 我发现了[img_https://" "]会被解释为<img src="https://" "">. 于是, 通过 [img_https://" onerror="javascript();" "] 我们成功注入了脚本并且让这个脚本在任何接受到的浏览器用户上运行.

至此, 网课进入了新时代.


The Bugclass, the Scriptclass

有了这个漏洞, 我帮Nico宣传了一把, 引起了不小的轰动, 那时知道漏洞的人不多, 问题不大. 但是在此之后, 又有几个同学发现了这个漏洞... 然后有一天, 一位神仙上课时发了一句 [img_https://" onerror="document.write('我只是试试')" "] , 把几乎所有人的网页给覆盖了... 引发了轩然大波, 在此之后, 我跟yur商量写一个脚本把这个漏洞给补了. 在这个脚本中, 我们添加了许多功能 (或者说开启了许多隐藏功能), 我们获取的信息更多了. 通过翻代码, 我找到了漏洞的根源 (其实是yur找到的), 并且在脚本中集成了补丁, XSS就被我们强行补上了.

脚本基本不会再用了, 我也扔在这里:

// ==UserScript==
// @name         课堂优化
// @namespace    null
// @version      0.3.1.3
// @description  as is said
// @author       4e1a607a
// @match        https://view.csslcloud.net/api/view/index*
// @match        http://fudao.xuetang365.com/Home/Course/detail/id/*
// @grant        none
// ==/UserScript==

function a(){
    var lname = {}  //这里我用了漏洞收集了很多人名+id用于发私聊

    //添加一个人名+id 0.2.2
    function insertListItem(name, uid) {
        if ($("#names").find("option[value='" + name + "']").length) return
        $("#names").append('<option class="names_option" value=' + name + '>' + uid + '</option>')
    }

    //右下角信息 0.1
    $(".lmb-r2").prepend("<span class='fl mr5'>Teachers:</span><span class='fl mr5' id='room_teachers'></span><span class='fl mr5'>|</span><span class='fl mr5'>Room user count:</span><span id='count' class='fl mr5'></span><span class='fl mr5'>|</span>")
    //回底部
    $(".lrb-t").prepend('<div id="scroll_bottom" style="position:absolute; top:0; left:25px; cursor:pointer;">底部</div>')
    $("#scroll_bottom").on("click", function(){$('#chat-list').parent().scrollTop($('#chat-list').height())})

    //私聊 0.2.0
    function insertListItems() { //添加一堆人名+id
        insertListItem("所有人", "all")
        for (var i in lname) insertListItem(i, lname[i])
    }
    $("#private-name").remove()
    $(".p-arrow").remove()
    $(".select-span").after('<input class="user-input" value="所有人" style="border: 0px; width: 100px;" list="names">').hide()
    $(".user-input").on("change", function(){
        if (!$(".names_option[value="+ this.value + "]").length) {
            $(".select-current").html('所有人').attr("id", 'all')
            return
        }
        $(".select-current").html(this.value).attr("id", $(".names_option[value="+ this.value + "]").html())
    }).after('<datalist id="names"></datalist>')
    insertListItems()

    //显示老师状况 0.1
    window.on_cc_online_teachers = function(data) {
        data = filterContext(data)
        var teachers = ''
        for (var i = 0; i < data.teachers.length; i++) {
            insertListItem(data.teachers[i].name, data.teachers[i].id)
            teachers += htmlEncode(data.teachers[i].name) + "(" + data.teachers[i].ip + "), "
        }
        $('#room_teachers').text(teachers.substr(0, teachers.length-2))
    }

    //当聊天栏不在最底时禁止聊天栏自动滚动 0.1.2
    $("#chat-list").parent().on('scroll', function(){
        var nScrollHight = $(this)[0].scrollHeight
        var nScrollTop = $(this)[0].scrollTop
        var nDivHight = $(this).height()
        localStorage.setItem('is_chat_list_scrolled_bottom', (nScrollTop + nDivHight + 20 >= nScrollHight) ? true : false)
    })
    //重载chatScroll 0.3
    window.chatScroll = function(){
        if (localStorage.is_chat_list_scrolled_bottom == 'true')
            $('#chat-list').parent().scrollTop($('#chat-list').height())
    }

    //初始聊天栏自动滚动信息 0.2.1
    localStorage.setItem('is_chat_list_scrolled_bottom', true)

    //显示消息时间
    window.on_cc_live_chat_msgs = function(datas) {
        var cmHtml = ''
        var barrageList = []
        var chats = datas
        $.each(datas, function (index, data) {
            insertListItem(data.username, data.userid)
            var barrageInfo = $.trim(data.msg)
            var reg = new RegExp(/\[img_http(s)?:\/\/(.*?)\]/g)
            if (reg.test(barrageInfo)) {
                //barrageInfo = '';
            } else {
                if (data.status === '0') {
                    barrageList.push(barrageInfo)
                }
            }

            cmHtml += Template.chatMsg({
                admin: data.userrole == 'publisher' || data.userrole == 'teacher' || data.userrole == 'host',
                name: data.username + (data.time ? ' [' + data.time + ']' : ''),
                content: showEm(data.msg),
                id: data.userid,
                chatId: data.chatId,
                status: data.status,
                isFromMe: Viewer.isMe(data.userid)
            })
        })
        if ($('#barrage').val() == 1) {
            $.DW.barrageList(JSON.stringify({barrageInfo: barrageList}))
        }
        $('#chat-list').append(cmHtml)

        var rc = $('#chat-list').children().length - 500 + datas.length
        if (rc > 0) {
            $('#chat-list> li:lt(' + rc + ')').remove()
        }

        var uid = $('.select-current').attr('id')
        if (uid != 'all' && $('.viewall').hasClass('viewall-active')) {
            $('#chat-list li').hide()
            $('#chat-list li[uid="' + uid + '"]').show()
            $('.c-chat').hide()
            $('.pchat span').hide()
            $('.pchat .name-from').show()
            $('.name-from').removeClass('name-tip')
        }
        chatScroll()
    }

    //自动隐藏问答区 0.1.3
    $("#left-bar").click()

    //自动签到 0.2.1
    var on_cc_live_start_rollcall_old = window.on_cc_live_start_rollcall
    window.on_cc_live_start_rollcall = function(data) {
        on_cc_live_start_rollcall_old(data)
        setTimeout(function(){$(".signbtn button").click();}, 1000)
    }

    //补漏洞 0.2.2
    window.showEm = function(str) {
        if (!$.trim(str)) {
            return ''
        }
        str = str.replace(/\</g, '&lt;')
        str = str.replace(/\>/g, '&gt;')
        str = str.replace(/\n/g, '<br/>')
        str = str.replace(/\"/g, '&quot;')  //原文少了这一句, 导致引号没有被正确处理
        str = str.replace(/\'/g, '&apos;')
        str = str.replace(/\[em_([0-9]*)\]/g, '<img src="//static.csslcloud.net/img/em/$1.gif" border="0" />')
        str = str.replace(/\[em2_([0-9]*)\]/g, '<img src="//static.csslcloud.net/img/em2/$1.png" border="0" />')
        var nmsg = ''
        var reg = new RegExp(/\[img_http(s)?:\/\/(.*?)\]/g)
        var isImage = reg.test(str)
        if (isImage) {
            var sIndex = str.indexOf('_') + 1
            nmsg = str.slice(sIndex, str.length - 1)
            var imgTag = '<div class="chatImage" style="width: 100%" ><img src="' + nmsg + '"  style="width: 100%;cursor:pointer;" onclick="showMsgImage(event)"/></div>'
            return imgTag
        }
        $.each(str.split(' '), function (i, n) {
            n = $.trim(n)
            if (n.indexOf('[uri_') == 0 && n.indexOf(']') == n.length - 1 && n.length > 6) {
                var u = n.substring(5, n.length - 1) + ' '
                nmsg += '<a target="_blank" style="color: #2f53ff" href="' + u + '">' + u + '</a>' + ' '
            } else {
                nmsg += n + ' '
            }
        })

        var baseUrl = '//static.csslcloud.net/'
        // 解析 扣1、扣2,匹配 [em2_q1][em2_q2]
        reg = new RegExp(/\[em2_(q[1]|q[2])\]/ig)
        nmsg = nmsg.replace(reg, '<img class="em2-q em2-$1 kou" src="' + baseUrl + 'img/emoticon/em2/em2_q/$1.png"/>')
        // 解析红包、打赏,图片格式jpg、gif、png,匹配 [cem_https://www.csslcloud.net/img.jpg]
        reg = new RegExp(/\[cem_(http(s)?:\/\/.+\.(jpg|gif|png))\]/ig)
        nmsg = nmsg.replace(reg, '<img class="img cem" src="$1" />')

        return nmsg
    }
}

//课程详情页微调使三位数课时显示在一行中
function b(){
    $(".detail_course .period li span:first-child").css("width", "53px");
    $(".detail_course .period li i").css("margin", "0 10px 0 3px");
}

(function() {
    'use strict';
    console.log("User script loading")
    if (document.URL.match('https://view.csslcloud.net/api/view/index')) a()
    else if (document.URL.match('http://fudao.xuetang365.com/Home/Course/detail/id')) b()
    console.log("User script loaded")
})();

基本思路是通过覆盖原接口实现植入代码的目的.

更多关于漏洞的内容我就不赘述了, 我在这里自学了Javascript的最基础内容, 至少基本能看懂JS了.


5月1日, 阳光网络课堂关服维护 (其实就是倒闭了, 现在还没回来), 我们选择转入Classin继续上网课, 阳光时期到此结束.


Classin 时期

4.28左右, 阳光维护的消息发布, 我们开始对Classin进行第一次试探. Classin是一个跨平台的应用而不是网页, 这给我们分析逻辑带来了很多麻烦--我们总不能把Classin的源代码从工程师那里偷过来吧...

5.6, 第一天上课, 由于Classin普通教室只允许1000人而年级有1200人, 我们开启了公开模式, 可以在网页播放, 这为我们理解它的逻辑开放了一个窗口. 但是, 半天后, 老师们跟Classin达成了协议, 我们有了1500人的大教室, 网页告一段落.

那么如何研究Classin的逻辑呢? 我想到了抓包. 一通wireshark之后, 我放弃了: Classin用的大多是UDP封包, 看不懂. 但是有没有不是UDP的包呢? 似乎是有的. 但是Classin(个鬼)偏偏不支持代理服务器设置, Fiddler没什么用(至少我当时是这么想的). 然后我找了一个HTTPAnalyzer, 抓到了一大堆乱七八糟的包:

GET https://b0s-cdn.eeo.cn/siteTest.html?echo=mbyqltkfvsuhgcwzxnjaeprdio

server echo 测试server是否可用.

POST https://b0d-cdn.eeo.cn/saasajax/server.ajax.php?action=getNServeTime

同步服务器时间, 返回类似:

{
    "error_info": { "errno": 1, "error": "程序正常执行"},
    "data": {"serveTime": 1593755122.746}
}

POST https://b0d-cdn.eeo.cn/api/cloud.api.php?action=getTransFiles

body: UID=22061418&signKey=7453c9c226b32018783b1f8b4956855a&timeStamp=1593756005&fileId=127495032&source=1&version=3.0.7.1

返回一个文件的相关信息:

{"error_info":{"errno":1,"error":"\u7a0b\u5e8f\u6b63\u5e38\u6267\u884c"},"data":{"path":"\/upload\/trans\/ppt01\/12\/2b\/214768908\/","file":"{ \"source\": \"http:\/\/www.eeo.cn:61170\/upload\/files\/2020\/202005\/07\/59655790427574e97641.ppt\", \"sourceId\": \"214768908\", \"eeoFileType\": \"eeo-ppt\", \"output\": { \"HTML5\":  { \"sourceType\": \"ppt\", \"transMethod\": \"removing general data\", \"version\": \"1\", \"width\": 720, \"height\": 540, \"pageNumber\": 35, \"rootPath\": \"html5\" } } }","fileNum":0}}

但是这时候, 我发现了一个非常啃屎的问题: 基本上每个请求都会带上一个signKey, 这个signKey与时间等有关, 具体算法未知, 因此我们不大可能自行发包获取信息. 另外有一个非常重要的请求:

POST https://b0d-cdn.eeo.cn/api/classin.api.php?action=getLessonRecordInfo

body: SID=21912762&safeKey=7cabdd66fa3b474715ca4d66e3a484de&timeStamp=1593760094&clientCourseId=76055390&clientClassId=197206311&memberUid=21975284&source=1&version=3.0.7.1

请求课程信息, 得到回放列表, 结果类似:

{"error_info":{"errno":1,"error":"程序正常执行"},"data":{"lessonId":"197206311","lessonName":"高一数学:程序语言","lessonData":{"lessonStatus":1,"vodList":{"1593742772":"https:\/\/1252412222.vod2.myqcloud.com\/794b4a11vodbj1252412222\/5b1d66665285890804832327322\/f0.mp4"},"fileList":[{"CreateTime":"2020-07-03 12:03:53","Duration":6253,"EndTime":"2020-07-03 12:03:42","FileId":"5285890804832327322","FileName":"","Message":"Operation succeeded","Playset":[{"Definition":"0","Url":"https:\/\/1252412222.vod2.myqcloud.com\/794b4a11vodbj1252412222\/5b1d66665285890804832327322\/f0.mp4"}],"Size":"283501417","SourceType":0,"StartTime":"2020-07-03 10:19:32","Status":"2"}]},"lessonStarttime":"1593743400","lessonEndtime":"1593748800","courseLogo":"\/upload\/images\/20200517\/bf625819f2d31aee3601_400.png","courseName":"高一年级网络课(新)","courseIntroduce":"","lessonIntroduce":"","schoolLogo":"\/upload\/images\/20190425\/24a56ee4b150b40f6414_260.png","schoolName":"华中师范大学第一附属中学","showClassVideo":"1","avoidRecordReplay":"0","teacherId":"1341943","teacherName":"沈宇为","teacherAvatar":"","teacherBio":"","chatroomStatus":"0","playNum":0,"likeNum":0,"onlineNum":0,"lessonCode":1,"lessonStatus":1}}

用于获取课程回放, 但是... 也要signKey, 所以做一个自动下载回放的程序估计是无望了. 也因此, 我到现在仍然是每节课下课后手动下载回放.

还有一些请求引起了我的注意:

GET https://b0s-cdn.eeo.cn/upload/trans/ppt01/d2/d1/217998454/html5/index.html

GET https://b0s-cdn.eeo.cn/upload/trans/ppt01/d2/d1/217998454/html5/js/doc.js

GET https://b0s-cdn.eeo.cn/upload/trans/ppt01/d2/d1/217998454/html5/data/slide1.css

GET https://b0s-cdn.eeo.cn/upload/trans/ppt01/d2/d1/217998454/html5/data/slide1.js

GET https://b0s-cdn.eeo.cn/upload/trans/ppt01/d2/d1/217998454/html5/data/fnt1.ttf

这是老师的PPT在Classin加载时的请求. 好消息是, 它不需要signKey. 所以, 我经过一番折腾, 研究出了按照css和js指示对PPT进行排版的方法, 通过输入index.html地址, 我可以简单地排出PPT来, 供使用. JS也摆在这里.

// ==UserScript==
// @name         PPT Viewer
// @namespace    http://tampermonkey.net/
// @version      0.0.5
// @description  To view the teacher's ppt when in class.
// @author       4e1a607a
// @match        https://*.eeo.cn/upload/trans/ppt*/html5/index.html
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    $('html').html(`<head><meta charset="utf-8"></head><body><button id="show-all" style="left: 1000px;">Show All</button><button id="normal" style="left: 1100px;">Normal</button><button id="cfont" style="left: 1000px; top: 50px;">Disable Font</button></body>`).css("overflow", "auto");
    $('button').css('position', 'absolute');
    //Fonts
    var style = `<style id='font'>`;
    for (var i=0; i<50; i++) {
        style += `@font-face{font-family:'fnt${i}';src:url('data/fnt${i}.ttf'),url('data/fnt${i}.woff')format('woff');}\n`;
    }
    style += `</style>`;
    $('head').append(style);
    function printpage(page) {
        $('body').append(`<div id='p${page}'></div>`)
        $.ajax({
            type: "GET",
            url: `data/slide${page}.css`,
            success: function(data){
                $('head').append(`<style>${data}</style>`);
            },
        });
        $.ajax({
            type: "GET",
            url: `data/slide${page}.js`,
            success: function(data){
                var s = data.substr(data.match('<div').index);
                s = s.substr(0, s.length-8);
                $(`#p${page}`).html(s).css('position', 'absolute').css('top', 600*page-600);
                $(`#p${page} div, span, img, svg, path`).css('position', 'absolute');
                printpage(page+1);
            },
        });
    };
    printpage(1);
    $('#show-all').on('click', function(){
        $('div').css('display', 'block');
    });
    $('#normal').on('click', function(){
        $('div').css('display', '');
    });
    $('#cfont').on('click', function(){
        $('#font').remove();
    });
})();

由于Classin有时候有字体不全的问题, 我设置了一个按钮用于扔掉原来的Font以防字体炸裂的情况. 当然老师的其他资源都会明文GET, 抓包即可 (虽然Classin抠门压制得质量极差).

后来, 由于HTTPAnalyzer实在是有点不好用(经常漏包), 我一通百度(Bing)找到了Proxifier, 于是我可以愉快的用Fiddler了.

最近, 在Classin更新3.0.7后, 我们收到了一个神秘dll, 这个dll破解了classin的问题区, 我们可以在老师禁言了的情况下发问题, 作者未知. Classin的问题区活跃了起来.

Classin除了偶尔服务器崩溃导致Classout之外, 其他体验还不错.

临近7.10, 我们要复学了~ Classin也快成为历史(bushi) 也快用不上了吧.


支线: 录屏, 学生群, 回放站

从上网课开始, 我就注意到一位名叫Nico的大神会建网站(加之比较小康), 我一直挺想拜见一下dalao. 但是找什么理由呢? 我想了想, 花了点时间刨了一个漏洞出来, 然后加好友补漏洞一气呵成~~~ (有点...) 然后网课与各种大佬的交流就开始了. 在有回放站之前, 我和Nico没有太多交流. 至于究竟是何时开始有交流的... 可能是我公网ip80打不开问Nico为什么, 他给我普及了一下运营商的政策, 然后... 大概如此.

后来, 阳光快关闭的时候, Nico正好打算建立回放站, 我就干了一些用Python搞代码修改数据的活. 通过代码的互相交流, (当然还有跟yur的交流), 我们增进了友谊(bushi), 比较顺利地完成了xuetang一期回放站的组建工作. 当时, xuetang的回放站分为3个区, 分别是选考(/xuankao), 学考(/xuekao)和历史(/history). 那时的三个网页是yur写的, 但是似乎慢的要命... 因为slideup的问题. 后来, 也就是51, xuetang挂了, 我觉得既然有xuetang的回放站, 那么Classin的回放站也该安排一下了. 于是我搜了一下MD(Material Design), 自己写了一个粗糙的Classin回放站. 后来, 我跟Nico说我想把Classin的回放站也整合进去成为一个单独的页面, 厚脸皮地向Nico要了一个新建的账号(就是这个4e1a607a), 并且要了创建页面的权限. 但是当我打开新建页面时我傻了: 跟我想象的完全不一样. 于是我重造了Classin的回放页(/classin), 把它改造成了现在看到的样子. 中途借鉴了yur的一些代码, 也帮他改了一遍代码. 我们本来以为, 这样的回放站足够我们用到结束了.

外加一句吐槽: 5.1 Nico发的点到名的鸣谢被扔到教师群去太草了! (班主任还没找我算账...)

一开始, 我们以为这是"子孙帝王万世之业也", 用了Google的团队盘, 可是6.1, 他的团队盘崩了. 所有的Classin和xuetang回放源都丢失了, 我们也没有任何备份... (这就是Nico在总结里轻描淡写的"第一次升级"或者"第一次换源", 实际上我们丢失了所有源)

于是在6.1-6.5, 我们成立了分流组, 从百度网盘(f**k)上重新下载了所有源并进行了压缩, 统一上传到了Nico的OD(OneDrive)教育盘. 第一次迁移过后, 由于数据完全改变, 原来的xuetang三个网页我又懒得啃屎山, 我就重新写了xuetang回放页/xuetang365, 也就是现在的回放页, 然后重构了目录树, 把所有回放集中到了一个网页上. 6.1我换了电脑, 新电脑是台式机硬盘大, 我下载的数据我就全部打包保留, 作为备份.

于是, 我们又以为这是"子孙帝王万世之业也", 结果前两天(7.1)... OD也挂了. 再次所有资源消失... 不过这次我们有部分备份, 问题不算太大. (这是Nico轻描淡写的第二次换源...)

一天后(7.2), 我们补上了所有源, 然后以Nico的NAS作为server和cloud, 重建了现在的回放站. 我这里也增加了备份, 资源的备份达到了90%.

但是, 形势依然不容乐观. 由于运营商一般不允许家用宽带开server, 所以他(也包括我)都担心会不会被电信Warn, 导致他家断网等问题, 因此Nico准备买一个10英镑一个月的云服务器(好贵!), 我来Call on各位赞赏一下Nico解决一下这笔开支...

别的不想多说, 附上已经被Redirect的/xuankao(我有重制)和/history(yur原版)的代码(除了变量名有点怪以外其他还好).

<script src="https://cdn.jsdelivr.net/npm/flv.js@1.5.0/dist/flv.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.loli.net/ajax/libs/mdui/0.4.3/css/mdui.min.css">
<script src="https://cdnjs.loli.net/ajax/libs/mdui/0.4.3/js/mdui.min.js"></script>
<script>
    $('#morphing-content, .read_mode').remove()</script>
<style>
    #dplayer {
        width: 100%;
        position: relative;
    }
</style>
<!--Search-->
<div class="mdui-typo">
    <div class="mdui-container">
        <div class="mdui-textfield mdui-textfield-floating-label">
            <i class="mdui-icon material-icons">search</i>
            <label class="mdui-textfield-label">输入关键字...</label>
            <input class="mdui-textfield-input" type="text" id="js-classId" />
        </div>
        <ul class="mdui-list mdui-list-dense" id="classid" style="display: none; height: 700px; overflow-y: auto;"></ul>
    </div>
</div>

<div id="dplayer"></div>
<br />
<div>
    <span class="mdui-center mdui-text-center" style="font-weight:300;font-size:24px;">正在播放</span>
    <span class="mdui-center mdui-text-center" style="font-weight:400;font-size:26px;" id="nwvd"></span>
</div>


<!--data import-->
<script type="text/javascript" src="https://upyun.loid.top/script/netclass/xuankao/rep.json"></script>
<script type="text/javascript" src="https://upyun.loid.top/script/netclass/xuankao/list.json"></script>


<script>
    var names = JSON.parse(mulu);
    var links = JSON.parse(rlk);
    for (var i = names.length - 1; -1 != i; --i) if (names[i] != '') {
        $('#classid').append(`<li data-id="${i}" class="mdui-list-item mdui-ripple"><a href="javascript:void(0)">${names[i]}</a></li>`);
    }
    jQuery.expr[':'].Contains = function (a, i, m) {
        return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
    };
    function filterList(list) {
        $('#js-classId').bind('input propertychange', function () {
            var filter = $(this).val();
            if (filter) {
                $matches = $(list).find('a:Contains(' + filter + ')').parent();
                $('li', list).not($matches).hide();
                $matches.show();
            } else $(list).find("li").show();
        });
    }
    var nowCs;
    $(function () {
        filterList($("#classid"));
        $('#js-classId').bind('focus', function () {
            $('#classid').slideDown();
        }).bind('blur', function () {
            $('#classid').slideUp();
        })
        $('#classid').on('click', 'li', function () {
            $('#classid').slideUp()
            var url = links[$(this).attr('data-id')].substr(-17, 13);
            var vurl = 'https://clsin.ajaxdong.workers.dev/src/netclass/xuankao/' + url + '.mp4?rootId=0AB-yT26LvKQgUk9PVA'
            var durl = 'https://clsin.ajaxdong.workers.dev/src/netclass/danmaku/' + url + '.json?rootId=0AB-yT26LvKQgUk9PVA';
            dp.switchVideo({
                url: vurl
            }, {
                maximum: 1000,
                addition: [durl]
            });
            dp.danmaku.show();
            $('#nwvd').html($(this).text());
            if (nowCs !== undefined)
                nowCs.classList.remove('mdui-list-item-active');
            this.classList.add('mdui-list-item-active');
            nowCs = this;
        });
    })
    const dp = new DPlayer({
        container: document.getElementById('dplayer'),
        video: {
            url: ''
        },
        danmaku: {
        }
    });
    var dm;
    $('.dplayer-notice, .dplayer-comment').hide();
    dp.danmaku.opacity(1);

    $(document).ready(() => {
        $('body').css('background-color', 'inherit');
        $('.breadcrumb bg-white-pure, #post-content').css('cursor', 'url(https://loid.top/usr/plugins/AliceStyle/static/img/cur/dew/normal.cur), default');
        setTimeout(() => { $('button').css('cursor', 'url("https://loid.top/usr/plugins/AliceStyle/static/img/cur/dew/link.cur"), pointer'); }, 500);
    })
</script>
<script>window.location = "/xuetang365";</script> <!--这里重定向了-->
<script src="https://cdn.jsdelivr.net/npm/flv.js@1.5.0/dist/flv.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
<link rel="stylesheet" href="//cdnjs.loli.net/ajax/libs/mdui/0.4.3/css/mdui.min.css">
<script src="//cdnjs.loli.net/ajax/libs/mdui/0.4.3/js/mdui.min.js"></script>
<style>
    #dplayer {
        width: 100%;
        margin: 0 auto;
    }
</style>
<div class="mdui-typo">
    <div class="mdui-container">
        <div class="mdui-textfield mdui-textfield-floating-label">
            <i class="mdui-icon material-icons">search</i>
            <label class="mdui-textfield-label">输入关键字...</label>
            <input class="mdui-textfield-input" type="text" id="js-classId" />
        </div>
        <ul class="mdui-list mdui-list-dense" id="classid" style="display: none; height: 700px; overflow-y: auto;"></ul>
    </div>
</div>
<div id="dplayer"></div>
<br />
<div>
    <span class="mdui-center mdui-text-center" style="font-weight:300;font-size:24px;">正在播放</span>
    <span class="mdui-center mdui-text-center" style="font-weight:400;font-size:26px;" id="nwvd"></span>
</div>
<script type="text/javascript" src="https://upyun.loid.top/script/netclass/history/rep.json"></script>
<script type="text/javascript" src="https://upyun.loid.top/script/netclass/history/list.json"></script>
<script>
    (function () {
        if (window.scrrun) { return; };
        window.scrrun = true;
        setTimeout(() => { $('#morphing-content, .read_mode, .read_mode_article').remove() }, 3000);
        var nm = JSON.parse(mulu)
        var lk = JSON.parse(rlk);
        var lst = $('#classid')[0];
        for (var i = nm.length - 1; i != -1; --i)
            if (nm[i] != '') {
                var kj = document.createElement('li');
                kj.setAttribute('data-id', i);
                kj.setAttribute('class', 'mdui-list-item mdui-ripple')
                kj.innerHTML = '<a href="javascript:void(0)">' + nm[i] + '</a>';
                lst.append(kj);
            }
        jQuery.expr[':'].Contains = function (a, i, m) {
            return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
        };
        function filterList(list) {
            $('#js-classId').bind('input propertychange', function () {
                var filter = $(this).val();
                if (filter) {
                    $matches = $(list).find('a:Contains(' + filter + ')').parent();
                    $('li', list).not($matches).hide();
                    $matches.show();
                } else $(list).find("li").show();
            });
        }
        var nowCs;
        $(function () {
            filterList($("#classid"));
            $('#js-classId').bind('focus', function () {
                $('#classid').slideDown();
            }).bind('blur', function () {
                $('#classid').slideUp();
            })
            $('#classid').on('click', 'li', function () {
                $('#classid').slideUp()
                dp.subtitle.hide();
                dp.switchVideo({
                    url: lk[$(this).data('id')]
                }, {
                    maximum: 1000,
                    addition: ['https://files.loid.top/src/netclass/dmk/xuankao/dmk' + ($(this).data('id') + 1) + '.json']
                });
                $('#nwvd')[0].innerHTML = $(this).text();
                if (nowCs !== undefined)
                    nowCs.classList.remove('mdui-list-item-active');
                this.classList.add('mdui-list-item-active');
                nowCs = this;
            });
        })
        const dp = new DPlayer({
            container: document.getElementById('dplayer'),
            video: {
                url: 'https://files.loid.top/Video/MMD/MMD_BoomClap_lieP9.flv'
            },
            danmaku: {
                maximum: 1000
            },
            subtitle: {
                url: 'https://files.loid.top/src/netclass/Boom%20Clap.vtt',
                fontSize: '30px',
                bottom: '10px',
                color: '#2196F3'
            }
        });
        var dm;
        $('.dplayer-comment').remove();
        $('.dplayer-notice').remove();
        dp.danmaku.opacity(1);
        dp.subtitle.show();
        $('#nwvd')[0].innerHTML = '[测试]Boom Clap by lieP9';
    })();
</script>
<script>window.location = "/xuetang365";</script>

不过我真的要吐槽他(实际上也是为了解决跨域的奇葩技巧)的数据引入:

https://upyun.loid.top/script/netclass/history/rep.json

var mulu = '["语文:《红楼梦》导读", "数学:平面向量基本概念及其表示", "化学:氯气 卤族元素", "政治:必修四第1课", "英语:book2 unit4 ", "物理:向心加速", "地理:人口1", "生物:细胞呼吸1", "语文:《红楼梦》阅读检测 视频资料", "数学:平面向量的线性运算", "政治:必修四第2课", "化学:二氧化硫", "英语:补充阅读或写作", "物理:向心力", "生物:细胞呼吸2", "地理:人口2", "语文:《林黛玉进贾府》", "数学:平面向量基本定理及其应用", "英语:book2 unit5", "物理:生活中的圆周运动", "语文:《祝福》上", "语文:《祝福》下", "数学:平面向量的坐标运算", "化学:硫酸 硫酸盐", "政治:哲学的基本问题", "英语:补充英文报刊阅读", "物理:圆周运动的临界问题(包括离心运动)", "地理:人口3", "生物:光合作用1", "语文:《祝福》电影", "数学:平面向量的数量积运算", "政治:唯物主义和唯心主义", "体育:室内健身", "英语:book3 unit1", "物理:曲线运动的复习课", "化学:氮气 氮氧化物", "心理:情绪万花筒", "语文:《老人与海》", "数学:平面向量应用举例及复习题", "生物:光合作用2", "地理:城市1", "英语:语法和写作", "物理:行星的运动(包括引力推导)", "语文:《琵琶行》", "数学:正弦定理", "化学:氨气", "政治:时代精神的精华", "英语:必修3 unit2", "美术:当代艺术", "地理:城市2", "生物:光合作用3", "语文:《琵琶行》2", "数学:余弦定理", "信息技术:人工智能时代", "政治:探究世界的本质(一)", "化学:硝酸", "英语:必修3 unit2", "物理:人造地球卫星 宇宙航行", "体育:室内搏击健身", "生物:细胞增殖1", "地理:城市3", "语文:《蜀道难》", "数学:正 余弦定理应用举例", "英语:单元检测", "语文:《蜀道难》", "数学:章节复习及习题课", "政治:探究世界的本质(一)", "英语:必修3 unit3", "物理:天体运动模型(卫星变轨)上", "物理:天体运动模型(卫星变轨)下", "音乐:《Victory》", "地理:农业1", "生物:细胞增殖2", "数学:不等式关系以及不等式的性质", "通用:瑞德西韦与技术的专利性", "政治:探究世界的本质(二)", "化学:原子结构(选修3)", "英语:必修3 unit3", "物理:《万有引力 天体运行》复习", "心理:疫情对生涯发展的影响以及生涯适应力的培养", "生物:细胞增殖3+细胞分化", "地理:农业2", "语文:讲评试卷", "数学:基本不等式及其应用", "英语:单元检测", "语文:《杜甫诗三首》", "数学:均值不等式复习以及数列的概念及其表示", "化学:原子结构2 上", "化学:原子结构2 下", "政治:探究世界的本质(三)", "英语:必修3 unit4", "美术:公共空间的雕塑", "地理:农业3", "生物:细胞的衰老、凋亡和癌变", "语文:《杜甫诗三首》", "数学:等差数列及其性质", "信息技术:图像识别技术", "政治:意识的本质", "化学:元素周期表(必修2)", "英语:必修3 unit4", "物理:功", "体育:室内体能训练", "生物:孟德尔的豌豆杂交实验(一)", "地理:农业4", "语文:表达交流《多思善想》", "数学:等差数列求和", "英语:单元检测", "语文:《李商隐诗两首》", "化学:元素周期表(必修2)", "政治:意识的作用", "英语:必修3 unit5", "物理:功率(机车启动)", "音乐:卡农", "地理:农业5", "生物:孟德尔的豌豆杂交实验(一)2", "语文:《李商隐诗两首》", "数学:等比数列的概念及其性质", "通用技术:一种穴位注射液与技术发现问题", "政治:独立作业(不直播)", "化学:原子结构与元素的性质(选修3)", "英语:必修3 unit5", "物理:动能 动能定理", "心理:感谢我、感谢你—资源取向的心理建设", "生物:孟德尔的豌豆杂交实验(二)1", "地理:农业6", "语文:诗歌阅读鉴赏技巧之形象篇", "数学:等比数列求和", "英语:单元检测", "语文:诗歌阅读鉴赏技巧", "数学:数列求和方法", "化学:元素推断专题", "政治:试卷讲评", "英语:B4U1 阅读+语言点", "物理:《动能 动能定理》习题课", "美术:隐秘的知识", "地理:农业7", "生物:孟德尔的豌豆杂交实验(二)2及习题讲解", "语文:诗歌阅读鉴赏技巧之语言篇", "数学:递推数列", "信息技术:智能图像处理技术II", "政治:求索真理的历程(一)", "化学:化学键(必修2)", "英语:B4U1 语法+语言运用", "物理:重力势能 弹性势能", "体育:室内体能训练", "生物:减数分裂和受精作用1", "地理:工业1", "语文:诗歌阅读鉴赏技巧练习", "数学:数列应用题", "英语:B4U1 单元检测 答疑", "语文:诗歌阅读鉴赏技巧之表达技巧篇", "数学:数列章节复习", "化学:共价键(选修3)", "政治:求索真理的历程(二)", "英语:B4U1 单元巩固+workbook等", "物理:机械守恒定律", "音乐:音乐要素", "地理:工业2", "生物:减数分裂和受精作用2", "语文:诗歌阅读鉴赏技巧练习", "通用技术:病毒来源之争与明确问题及技术的运用", "政治:求索真理的历程(三)", "英语:B4U1 补充阅读 teens", "物理:功能关系", "心理:如何提升学业自信心", "生物:基因在染色体上1", "地理:工业3", "语文:诗歌阅读鉴赏技巧之思想感情篇", "数学:试卷讲评", "英语:B4U1 综合检测(含听力) 上", "英语:B4U1 综合检测(含听力) 中", "英语:B4U1 综合检测(含听力) 下", "地理:农业测试试卷讲评", "英语:B4U2 阅读+语言点", "物理:功能关系习题课", "美术:中国传统建筑欣赏", "地理:工业4", "生物:基因在染色体上2+伴性遗传", "语文:诗歌阅读鉴赏技巧练习", "数学:立体几何之简单的多面体及其概念", "信息技术:Python编程简介", "化学:元素化合物推断专题", "英语:B4U2 语法+语言运用 上", "英语:B4U2 语法+语言运用 下", "物理:章节复习", "体育:室内体能训练", "生物:DNA是主要的遗传物质1", "地理:工业5", "语文:《动物游戏之谜》", "数学:三视图及直观图", "英语:B4U2 单元检测、答疑", "数学:简单几何体的表面积及体积", "化学:元素化合物推断专题", "政治:独立作业讲评", "语文:期中试卷讲评", "数学:期中考试试卷讲评+球的表面积和体积", "化学选考:期中试卷讲评", "政治选考:期中考试试卷讲评", "英语:期中考试试卷讲评", "物理选考:期中试卷讲评", "地理选考:工业6,期中试卷讲评", "生物选考:DNA是主要的遗传物质2+DNA分子的结构", "语文:《孟子》简介", "数学:立体几何第一章 章节复习及习题课", "政治选考:世界是普遍联系的", "化学选考:价层电子对互斥理论", "英语:必修4 unit3 阅读", "物理选考:动量 冲量 动量定理", "生物选考:DNA的复制+基因是具有遗传效应的DNA片段", "地理选考:交通1", "语文:《寡人之于国也》", "数学:立体几何第二章 空间中点、线、面的位置关系", "英语:必修4 unit3", "语文:《交际中的语言运用》", "数学:空间中平行关系的判定", "化学选考:杂化轨道理论", "政治选考:《用联系的观点看问题》", "英语:必修4 unit3", "物理选考:动量定理习题课", "地理选考:交通运输2", "生物选考:基因指导蛋白质的合成1", "语文:《过秦论》1", "政治选考:《唯物辩证法的发展观(一)》", "化学选考:配位化合物理论", "英语:必修4 unit3", "物理选考:动量守恒定律", "生物选考:基因指导蛋白质的合成2+基因对性状的控制", "地理选考:选考:交通运输3 上", "地理选考:选考:交通运输3 下", "语文:《过秦论》2", "数学:空间中平行关系的性质"]'

https://upyun.loid.top/script/netclass/history/list.json

var rlk= '["https://files.loid.top/src/netclass/xuankao/uOhUC0Rpe2-90.mp4", "https://files.loid.top/src/netclass/xuankao/umqQ7WtXFJ-90.mp4", "https://files.loid.top/src/netclass/xuankao/u3ejTaoUAV-90.mp4", "https://files.loid.top/src/netclass/xuankao/uegFKnT4bh-90.mp4", "https://files.loid.top/src/netclass/xuankao/uO19oR5QRL-90.mp4", "https://files.loid.top/src/netclass/xuankao/uLDUjjbmb3-90.mp4", "https://files.loid.top/src/netclass/xuankao/u3T6tzSSRs-90.mp4", "https://files.loid.top/src/netclass/xuankao/uo3uyAH9lj-90.mp4", "https://files.loid.top/src/netclass/xuankao/urwF0x45Kc-90.mp4", "https://files.loid.top/src/netclass/xuankao/uNmrhuxtm9-90.mp4", "https://files.loid.top/src/netclass/xuankao/uCSs3wAPL9-90.mp4", "https://files.loid.top/src/netclass/xuankao/uvX4Zyj3cy-90.mp4", "https://files.loid.top/src/netclass/xuankao/ukxL3KOk7v-90.mp4", "https://files.loid.top/src/netclass/xuankao/u3erf0lDLu-90.mp4", "https://files.loid.top/src/netclass/xuankao/uHDS8yMT91-90.mp4", "https://files.loid.top/src/netclass/xuankao/uv143WknD8-90.mp4", "https://files.loid.top/src/netclass/xuankao/uLm1y8ryrs-90.mp4", "https://files.loid.top/src/netclass/xuankao/uOHA117Rqb-90.mp4", "https://files.loid.top/src/netclass/xuankao/u1u1zUHvX7-90.mp4", "https://files.loid.top/src/netclass/xuankao/uN7GjCYiiN-90.mp4", "https://files.loid.top/src/netclass/xuankao/um7ml8d7lQ-90.mp4", "https://files.loid.top/src/netclass/xuankao/uCijo9Dxuj-90.mp4", "https://files.loid.top/src/netclass/xuankao/uJdLA1lIBp-90.mp4", "https://files.loid.top/src/netclass/xuankao/um7KbQzYCr-90.mp4", "https://files.loid.top/src/netclass/xuankao/ukl14wyANa-90.mp4", "https://files.loid.top/src/netclass/xuankao/uH99Iy3ke8-90.mp4", "https://files.loid.top/src/netclass/xuankao/ukaBUPHEFS-90.mp4", "https://files.loid.top/src/netclass/xuankao/uD0iZlfy1Y-90.mp4", "https://files.loid.top/src/netclass/xuankao/u1Tx2sQb1e-90.mp4", "https://files.loid.top/src/netclass/xuankao/uDS8O49huL-90.mp4", "https://files.loid.top/src/netclass/xuankao/uNOH0Mni1I-90.mp4", "https://files.loid.top/src/netclass/xuankao/uFchIrRMwz-90.mp4", "https://files.loid.top/src/netclass/xuankao/u1GdqKVKvp-90.mp4", "https://files.loid.top/src/netclass/xuankao/urQfxGmt91-90.mp4", "https://files.loid.top/src/netclass/xuankao/uLyorQ7Pjs-90.mp4", "https://files.loid.top/src/netclass/xuankao/u3XuI52ouS-90.mp4", "https://files.loid.top/src/netclass/xuankao/uoaRqd5wCQ-90.mp4", "https://files.loid.top/src/netclass/xuankao/uFf6kLFpNG-90.mp4", "https://files.loid.top/src/netclass/xuankao/uCihrhVlnD-90.mp4", "https://files.loid.top/src/netclass/xuankao/uFQ13ogJAM-90.mp4", "https://files.loid.top/src/netclass/xuankao/uOIlgWzaSC-90.mp4", "https://files.loid.top/src/netclass/xuankao/uFaZRnvH0c-90.mp4", "https://files.loid.top/src/netclass/xuankao/u1DsWsHISR-90.mp4", "https://files.loid.top/src/netclass/xuankao/uObHJ2DmH4-90.mp4", "https://files.loid.top/src/netclass/xuankao/um7JPmptGr-90.mp4", "https://files.loid.top/src/netclass/xuankao/u3pXQ9bhH8-90.mp4", "https://files.loid.top/src/netclass/xuankao/ubukqxnh7H-90.mp4", "https://files.loid.top/src/netclass/xuankao/ulX6l5fLJi-90.mp4", "https://files.loid.top/src/netclass/xuankao/uFTTLEFiSz-90.mp4", "https://files.loid.top/src/netclass/xuankao/uN9fBhNL2T-90.mp4", "https://files.loid.top/src/netclass/xuankao/uHlNYZjYl2-90.mp4", "https://files.loid.top/src/netclass/xuankao/ub8NWkRnGN-90.mp4", "https://files.loid.top/src/netclass/xuankao/urBRiWgWBP-90.mp4", "https://files.loid.top/src/netclass/xuankao/u1LdShE3dd-90.mp4", "https://files.loid.top/src/netclass/xuankao/uCUTghb4VA-90.mp4", "https://files.loid.top/src/netclass/xuankao/ubMTXZ3b6F-90.mp4", "https://files.loid.top/src/netclass/xuankao/uCM5gs8sCq-90.mp4", "https://files.loid.top/src/netclass/xuankao/uOsDW3kPmG-90.mp4", "https://files.loid.top/src/netclass/xuankao/ul4t8GEW90-90.mp4", "https://files.loid.top/src/netclass/xuankao/uJuAY1tBxR-90.mp4", "https://files.loid.top/src/netclass/xuankao/u11gE0mf39-90.mp4", "https://files.loid.top/src/netclass/xuankao/ub5IdytviC-90.mp4", "https://files.loid.top/src/netclass/xuankao/ukyrNzxyej-90.mp4", "https://files.loid.top/src/netclass/xuankao/uLZkbWTPCc-90.mp4", "https://files.loid.top/src/netclass/xuankao/uJFIAbYj8F-90.mp4", "https://files.loid.top/src/netclass/xuankao/uCQdcir3jK-90.mp4", "https://files.loid.top/src/netclass/xuankao/ul836GbiBp-90.mp4", "https://files.loid.top/src/netclass/xuankao/uJpwPimMXR-90.mp4", "https://files.loid.top/src/netclass/xuankao/umr0cKNmM1-90.mp4", "https://files.loid.top/src/netclass/xuankao/uD3bqN7i9N-90.mp4", "https://files.loid.top/src/netclass/xuankao/u1F4NvfCqH-90.mp4", "https://files.loid.top/src/netclass/xuankao/uoRb10NGrA-90.mp4", "https://files.loid.top/src/netclass/xuankao/uFWDG6mHTq-90.mp4", "https://files.loid.top/src/netclass/xuankao/ueyPLBPzEu-90.mp4", "https://files.loid.top/src/netclass/xuankao/uezCjEdmAU-90.mp4", "https://files.loid.top/src/netclass/xuankao/ukaXTj1c29-90.mp4", "https://files.loid.top/src/netclass/xuankao/umJKGEaaBV-90.mp4", "https://files.loid.top/src/netclass/xuankao/urJrvvVhdG-90.mp4", "https://files.loid.top/src/netclass/xuankao/u3AOnYOLoH-90.mp4", "https://files.loid.top/src/netclass/xuankao/uJMyOnnN9P-90.mp4", "https://files.loid.top/src/netclass/xuankao/um2d1mnRqO-90.mp4", "https://files.loid.top/src/netclass/xuankao/uvnIZQQwhp-90.mp4", "https://files.loid.top/src/netclass/xuankao/ur8QIeRpVD-90.mp4", "https://files.loid.top/src/netclass/xuankao/uFnuV3hFBf-90.mp4", "https://files.loid.top/src/netclass/xuankao/uoUchlJ1mv-90.mp4", "https://files.loid.top/src/netclass/xuankao/uvyyCchKBY-90.mp4", "https://files.loid.top/src/netclass/xuankao/ukapezeSMC-90.mp4", "https://files.loid.top/src/netclass/xuankao/uo7qiXdQ3X-90.mp4", "https://files.loid.top/src/netclass/xuankao/uNxiL7UJ3Q-90.mp4", "https://files.loid.top/src/netclass/xuankao/ubowP5TGoe-90.mp4", "https://files.loid.top/src/netclass/xuankao/uJJ6fJZXM7-90.mp4", "https://files.loid.top/src/netclass/xuankao/uFSAJnbYlU-90.mp4", "https://files.loid.top/src/netclass/xuankao/uouRSlfTEd-90.mp4", "https://files.loid.top/src/netclass/xuankao/u3fIeFk1Re-90.mp4", "https://files.loid.top/src/netclass/xuankao/urdAUuatNO-90.mp4", "https://files.loid.top/src/netclass/xuankao/uofWGD8gwI-90.mp4", "https://files.loid.top/src/netclass/xuankao/uo5LHJ2Uts-90.mp4", "https://files.loid.top/src/netclass/xuankao/uewhrWONu3-90.mp4", "https://files.loid.top/src/netclass/xuankao/uJQ5oz4S6o-90.mp4", "https://files.loid.top/src/netclass/xuankao/uCMmysJUxz-90.mp4", "https://files.loid.top/src/netclass/xuankao/", "https://files.loid.top/src/netclass/xuankao/u1pS1hCXML-90.mp4", "https://files.loid.top/src/netclass/xuankao/uJzpb1Y2Y9-90.mp4", "https://files.loid.top/src/netclass/xuankao/uOCPmWGd3P-90.mp4", "https://files.loid.top/src/netclass/xuankao/ubiaIsrIJs-90.mp4", "https://files.loid.top/src/netclass/xuankao/uluNITcPQQ-90.mp4", "https://files.loid.top/src/netclass/xuankao/u3YO0CCJVc-90.mp4", "https://files.loid.top/src/netclass/xuankao/uDwDqdr290-90.mp4", "https://files.loid.top/src/netclass/xuankao/u1zpFZNe20-90.mp4", "https://files.loid.top/src/netclass/xuankao/ulMpIhgGgA-90.mp4", "https://files.loid.top/src/netclass/xuankao/u3SYMNRYCp-90.mp4", "https://files.loid.top/src/netclass/xuankao/uN2RY7IGX4-90.mp4", "https://files.loid.top/src/netclass/xuankao/ukfvABWDjZ-90.mp4", "https://files.loid.top/src/netclass/xuankao/uJEN31H40y-90.mp4", "https://files.loid.top/src/netclass/xuankao/ubNMGg5LLm-90.mp4", "https://files.loid.top/src/netclass/xuankao/uDb0pU3eYp-90.mp4", "https://files.loid.top/src/netclass/xuankao/uF2cdXqCY7-90.mp4", "https://files.loid.top/src/netclass/xuankao/uDkc6IKYxi-90.mp4", "https://files.loid.top/src/netclass/xuankao/uCKzRxo8C3-90.mp4", "https://files.loid.top/src/netclass/xuankao/uFAMPMOFkB-90.mp4", "https://files.loid.top/src/netclass/xuankao/ubt7fMzPuG-90.mp4", "https://files.loid.top/src/netclass/xuankao/uDUvWOJoqd-90.mp4", "https://files.loid.top/src/netclass/xuankao/uHri3ncfUM-90.mp4", "https://files.loid.top/src/netclass/xuankao/uF9VEMOSGL-90.mp4", "https://files.loid.top/src/netclass/xuankao/uFnoc04F6h-90.mp4", "https://files.loid.top/src/netclass/xuankao/ur6mvRICm3-90.mp4", "https://files.loid.top/src/netclass/xuankao/ueU4sPsDfG-90.mp4", "https://files.loid.top/src/netclass/xuankao/uLBxIhdp2a-90.mp4", "https://files.loid.top/src/netclass/xuankao/uCMcSOmKqm-90.mp4", "https://files.loid.top/src/netclass/xuankao/uNqkypZWnR-90.mp4", "https://files.loid.top/src/netclass/xuankao/uvNjaRDR1q-90.mp4", "https://files.loid.top/src/netclass/xuankao/ukMwe8XSoW-90.mp4", "https://files.loid.top/src/netclass/xuankao/u3qsqBFfrm-90.mp4", "https://files.loid.top/src/netclass/xuankao/ur9MJ6LMdK-90.mp4", "https://files.loid.top/src/netclass/xuankao/uNUN8vOSSR-90.mp4", "https://files.loid.top/src/netclass/xuankao/uN67OYttsD-90.mp4", "https://files.loid.top/src/netclass/xuankao/urYjoCcjge-90.mp4", "https://files.loid.top/src/netclass/xuankao/u3f8c5WoHd-90.mp4", "https://files.loid.top/src/netclass/xuankao/uo4GrQhlFv-90.mp4", "https://files.loid.top/src/netclass/xuankao/uerWo3Andn-90.mp4", "https://files.loid.top/src/netclass/xuankao/uNZh8D59KE-90.mp4", "https://files.loid.top/src/netclass/xuankao/ubEoarFpub-90.mp4", "https://files.loid.top/src/netclass/xuankao/ukjgNa5VmW-90.mp4", "https://files.loid.top/src/netclass/xuankao/ueuXOJDkEj-90.mp4", "https://files.loid.top/src/netclass/xuankao/uNrghplM8f-90.mp4", "https://files.loid.top/src/netclass/xuankao/uDTzWk2Lj9-90.mp4", "https://files.loid.top/src/netclass/xuankao/uNZ061nDyj-90.mp4", "https://files.loid.top/src/netclass/xuankao/uLee24QFg1-90.mp4", "https://files.loid.top/src/netclass/xuankao/uFqGMa8tZ8-90.mp4", "https://files.loid.top/src/netclass/xuankao/uOB9KI6uTr-90.mp4", "https://files.loid.top/src/netclass/xuankao/ukYQTkmaMv-90.mp4", "https://files.loid.top/src/netclass/xuankao/uvYIFWVbUk-90.mp4", "https://files.loid.top/src/netclass/xuankao/uCeZ7ThA04-90.mp4", "https://files.loid.top/src/netclass/xuankao/uCuIbLZjpn-90.mp4", "https://files.loid.top/src/netclass/xuankao/ue9OKMpbUe-90.mp4", "https://files.loid.top/src/netclass/xuankao/umJFIldcpo-90.mp4", "https://files.loid.top/src/netclass/xuankao/ur51vPL84k-90.mp4", "https://files.loid.top/src/netclass/xuankao/uLJYuIrJhD-90.mp4", "https://files.loid.top/src/netclass/xuankao/uHVBxbMPuP-90.mp4", "https://files.loid.top/src/netclass/xuankao/uvutJishgJ-90.mp4", "https://files.loid.top/src/netclass/xuankao/ur0RkXa3Zw-90.mp4", "https://files.loid.top/src/netclass/xuankao/ukB9gPNJdr-90.mp4", "https://files.loid.top/src/netclass/xuankao/uF09L02WMg-90.mp4", "https://files.loid.top/src/netclass/xuankao/uFX5SxjQhe-90.mp4", "https://files.loid.top/src/netclass/xuankao/um7rDYweq2-90.mp4", "https://files.loid.top/src/netclass/xuankao/uOJ161Jujm-90.mp4", "https://files.loid.top/src/netclass/xuankao/uJG45DzhRh-90.mp4", "https://files.loid.top/src/netclass/xuankao/urCu5pqN53-90.mp4", "https://files.loid.top/src/netclass/xuankao/uLttejT57l-90.mp4", "https://files.loid.top/src/netclass/xuankao/uHAJ7KUeeM-90.mp4", "https://files.loid.top/src/netclass/xuankao/ueEFiNN48Q-90.mp4", "https://files.loid.top/src/netclass/xuankao/uNEysJtYoP-90.mp4", "https://files.loid.top/src/netclass/xuankao/uk5vO4wU4P-90.mp4", "https://files.loid.top/src/netclass/xuankao/uJn1vcacZ5-90.mp4", "https://files.loid.top/src/netclass/xuankao/uo2e6gylrK-90.mp4", "https://files.loid.top/src/netclass/xuankao/uvMMUIW70t-90.mp4", "https://files.loid.top/src/netclass/xuankao/uCKIj3eipI-90.mp4", "https://files.loid.top/src/netclass/xuankao/uNjjJQRb7b-90.mp4", "https://files.loid.top/src/netclass/xuankao/u1m4YcFGzf-90.mp4", "https://files.loid.top/src/netclass/xuankao/umrLxMZmfO-90.mp4", "https://files.loid.top/src/netclass/xuankao/ueT1NL8oit-90.mp4", "https://files.loid.top/src/netclass/xuankao/uL9TCX7Mg1-90.mp4", "https://files.loid.top/src/netclass/xuankao/uvMYWksH9y-90.mp4", "https://files.loid.top/src/netclass/xuankao/ueZTPMDrT8-90.mp4", "https://files.loid.top/src/netclass/xuankao/uoKKEi4oBN-90.mp4", "https://files.loid.top/src/netclass/xuankao/umt2cELBAH-90.mp4", "https://files.loid.top/src/netclass/xuankao/ubvDR9sspB-90.mp4", "https://files.loid.top/src/netclass/xuankao/u3wcQvEjyY-90.mp4", "https://files.loid.top/src/netclass/xuankao/ubY759DECV-90.mp4", "https://files.loid.top/src/netclass/xuankao/ue5MZMxqtF-90.mp4", "https://files.loid.top/src/netclass/xuankao/ubHIN6x2lt-90.mp4", "https://files.loid.top/src/netclass/xuankao/uDpGXT5AWF-90.mp4", "https://files.loid.top/src/netclass/xuankao/uHftTT4Nk7-90.mp4", "https://files.loid.top/src/netclass/xuankao/u1JeUGCzrK-90.mp4", "https://files.loid.top/src/netclass/xuankao/uJUR4LHDIf-90.mp4", "https://files.loid.top/src/netclass/xuankao/uvVv9l9kZ1-90.mp4", "https://files.loid.top/src/netclass/xuankao/uO0yGPawk5-90.mp4", "https://files.loid.top/src/netclass/xuankao/uNZVWhY1qO-90.mp4", "https://files.loid.top/src/netclass/xuankao/uk9cPlYM17-90.mp4", "https://files.loid.top/src/netclass/xuankao/uORlRY2eh1-90.mp4", "https://files.loid.top/src/netclass/xuankao/ueIV7kk0HX-90.mp4", "https://files.loid.top/src/netclass/xuankao/ubIYO10M20-90.mp4", "https://files.loid.top/src/netclass/xuankao/uDIH6zy2n4-90.mp4", "https://files.loid.top/src/netclass/xuankao/umKudJunzV-90.mp4", "https://files.loid.top/src/netclass/xuankao/uFUSSnsCRo-90.mp4", "https://files.loid.top/src/netclass/xuankao/ubwjiYlL9o-90.mp4", "https://files.loid.top/src/netclass/xuankao/urPJDukS1h-90.mp4", "https://files.loid.top/src/netclass/xuankao/urmNllSURd-90.mp4", "https://files.loid.top/src/netclass/xuankao/uHCmWJKgAr-90.mp4", "https://files.loid.top/src/netclass/xuankao/uv8xFVK9mB-90.mp4", "https://files.loid.top/src/netclass/xuankao/uDnj9EwCyP-90.mp4", "https://files.loid.top/src/netclass/xuankao/uN9NPpMeT6-90.mp4", "https://files.loid.top/src/netclass/xuankao/uDl3qb6QD0-90.mp4", "https://files.loid.top/src/netclass/xuankao/uFymykmtLL-90.mp4", "https://files.loid.top/src/netclass/xuankao/u1ARXUtSdf-90.mp4", "https://files.loid.top/src/netclass/xuankao/u16P8H0RST-90.mp4", "https://files.loid.top/src/netclass/xuankao/uLvJnnUJTv-90.mp4", "https://files.loid.top/src/netclass/xuankao/uboQcgJDD1-90.mp4", "https://files.loid.top/src/netclass/xuankao/uOz8ceNBKb-90.mp4", "https://files.loid.top/src/netclass/xuankao/uNxuFI5r4z-90.mp4", "https://files.loid.top/src/netclass/xuankao/uLRNbWdeEe-90.mp4", "https://files.loid.top/src/netclass/xuankao/umQVf9f9hP-90.mp4", "https://files.loid.top/src/netclass/xuankao/ulbJpQzhhN-90.mp4", "https://files.loid.top/src/netclass/xuankao/umtouWHCde-90.mp4", "https://files.loid.top/src/netclass/xuankao/uDZou0OcRG-90.mp4", "https://files.loid.top/src/netclass/xuankao/ubSNC41FTa-90.mp4", "https://files.loid.top/src/netclass/xuankao/uerWYCmT0C-90.mp4", "https://files.loid.top/src/netclass/xuankao/uCsjwmtPSB-90.mp4", "https://files.loid.top/src/netclass/xuankao/uoJejXgPqr-90.mp4", "https://files.loid.top/src/netclass/xuankao/uD2jIuUTcG-90.mp4", "https://files.loid.top/src/netclass/xuankao/ueSI0sJPi1-90.mp4"]'

(为什么要在json文件里面写javascript?!!!!!!!!!而且对齐啥的稀烂

现在的json就很好(自恋中(bushi))

{"语文":{"t":"f","n":"chinese","c":{"01、《红楼梦》导读":{"n":"01、《红楼梦》导读.mp4","d":"uOhUC0Rpe2-90"},"02、《红楼梦》阅读检测 视频资料":{"n":"02、《红楼梦》阅读检测-视频资料.mp4","d":"urwF0x45Kc-90"},"03、《林黛玉进贾府》":{"n":"03、《林黛玉进贾府》.mp4","d":"uLm1y8ryrs-90"},"04、《祝福》(上)":{"n":"04、《祝福》(上).mp4","d":"um7ml8d7lQ-90"},"05、《祝福》(下)":{"n":"05、《祝福》(下).mp4","d":"uCijo9Dxuj-90"},"06、《祝福》电影":{"n":"06、《祝福》电影.mp4","d":"uDS8O49huL-90"},"07、《老人与海》":{"n":"07、《老人与海》.mp4","d":"uFf6kLFpNG-90"},"08、《琵琶行》":{"n":"08、《琵琶行》.mp4","d":"uObHJ2DmH4-90"},"09、《琵琶行》2":{"n":"09、《琵琶行》2.mp4","d":"ub8NWkRnGN-90"},"10、《蜀道难》":{"n":"10、《蜀道难》.mp4","d":"ub5IdytviC-90"},"11、《蜀道难》2":{"n":"11、《蜀道难》2.mp4","d":"uJFIAbYj8F-90"},"12、讲评试卷":{"n":"12、讲评试卷.mp4","d":"ur8QIeRpVD-90"},"13、《杜甫诗三首》":{"n":"13、《杜甫诗三首》.mp4","d":"uvyyCchKBY-90"},"14、《杜甫诗三首》2":{"n":"14、《杜甫诗三首》2.mp4","d":"urdAUuatNO-90"},"15、表达交流《多思善想》":{"n":"15、表达交流《多思善想》.mp4","d":"ubiaIsrIJs-90"},"16、《李商隐诗两首》":{"n":"16、《李商隐诗两首》.mp4","d":"uDwDqdr290-90"},"17、《李商隐诗两首》2(上)":{"n":"17、《李商隐诗两首》2(上).mp4","d":"uDb0pU3eYp-90"},"18、《李商隐诗两首》2(下)":{"n":"18、《李商隐诗两首》2(下).mp4","d":null },"19、诗歌阅读鉴赏技巧之形象篇":{"n":"19、诗歌阅读鉴赏技巧之形象篇.mp4","d":"ur6mvRICm3-90"},"20、诗歌阅读鉴赏技巧之形象篇2":{"n":"20、诗歌阅读鉴赏技巧之形象篇2.mp4","d":"uCMcSOmKqm-90"},"21、诗歌阅读鉴赏技巧之语言篇":{"n":"21、诗歌阅读鉴赏技巧之语言篇.mp4","d":"u3f8c5WoHd-90"},"22、诗歌阅读鉴赏技巧之语言篇2":{"n":"22、诗歌阅读鉴赏技巧之语言篇2.mp4","d":"uLee24QFg1-90"},"23、诗歌阅读鉴赏技巧之表达技巧篇":{"n":"23、诗歌阅读鉴赏技巧之表达技巧篇.mp4","d":"ukYQTkmaMv-90"},"24、诗歌阅读鉴赏技巧之表达技巧篇2":{"n":"24、诗歌阅读鉴赏技巧之表达技巧篇2.mp4","d":"uvutJishgJ-90"},"25、诗歌阅读鉴赏技巧之思想感情篇":{"n":"25、诗歌阅读鉴赏技巧之思想感情篇.mp4","d":"urCu5pqN53-90"},"26、诗歌阅读鉴赏技巧练习":{"n":"26、诗歌阅读鉴赏技巧练习.mp4","d":"u1m4YcFGzf-90"},"27、《动物游戏之谜》":{"n":"27、《动物游戏之谜》.mp4","d":"ubY759DECV-90"},"28、期中试卷讲评":{"n":"28、期中试卷讲评.mp4","d":"uJUR4LHDIf-90"},"29、《孟子》简介":{"n":"29、《孟子》简介.mp4","d":"uDIH6zy2n4-90"},"30、《寡人之于国也》":{"n":"30、《寡人之于国也》.mp4","d":"uDnj9EwCyP-90"},"31、《交际中的语言运用》":{"n":"31、《交际中的语言运用》.mp4","d":"uFymykmtLL-90"},"32、《过秦论》1":{"n":"32、《过秦论》1.mp4","d":"umQVf9f9hP-90"},"33、《过秦论》2":{"n":"33、《过秦论》2.mp4","d":"uD2jIuUTcG-90"}}}}

当然这是minify之后的, 可能不太好看(

{
    "学考": {
    "type": "folder",
    "pname": "APT-Based",
    "contents": {
        "生物": {
            "type": "folder",
            "pname": "",
            "contents": {
                "细胞呼吸+光合作用1": {
                    "type": "video",
                    "fname": "细胞呼吸+光合作用1.mp4",
                    "danmaku": "ubQrQovyMo-90"
                },
                "酶、ATP、细胞呼吸": {
                    "type": "video",
                    "fname": "酶、ATP、细胞呼吸.mp4",
                    "danmaku": "ueWrYEl7Lp-90"
                }
            }
        }
    }
}

是不是好看多了(

不过我还是诉一下苦, 我在编写这个目录的时候, 所有的弹幕都是对照着前面的鬼一个个粘上去的... 由此得出几个要点:

  • 能省略就省略, 减少大小;

  • 能相对就相对, 以后万一要改还能统一修改; 举例: (代码上)第一次崩溃从见鬼的 var mulu= 搬到 tree.json 用了两整天, 第二次从files.loid.top搬到nas只用了两分钟(改一下base_url)...

  • 尽量备份一遍吧... 我的弹幕本来写好了, 结果我扔到GD上之后把本地的删了, GD挂掉之后只好拿着raw数据重写(不过幸好raw数据还在)

然后还想吐槽Nico的英语带师水平: 10科的科名他写错了3个 (继续鞭尸)

不过无论如何, 有惊无险, 我们到现在还没有彻底翻车...?


附加线: 加密, 信任

从5.1老师让Nico注意版权问题避免外泄开始, 加密与信任就成了一个非常无语的问题. 这其中的东西很乱, 我不太知道从哪里开始说, 我就从刚刚开始算了.

7.4, 我跟Nico讨论要不要干脆一个种子把我们的所有回放扔到群里, 我是正方(同意), 他是反方(不同意). 我们讨论的结果是他赢了(毕竟他是群主我是群成员), 我们把这个种子公布到了协作群用于备份. 我整理一下讨论(当然我可能对正反观点都有补充).

正: 我觉得你服务器目前状态是自家公网ip开放端口, 这样有被封禁的风险; 而种子的UDP是正常流量, 运营商一般不会管; 并且种子可以一对多(即一人下载多人上传), 速度更快. 所以说与其一人冒风险开https服务器不如多人维护种子健康度.

反: 我觉得种子是开放的, 而我们的东西理应是不能外传的, 做种子会增加外传的风险. 种子即使稳, 如果不能保证安全性, 是不应该被使用的. 如果放在大群里被传开了, 视频的版权就不好办了.

正: 私有种子不在DHT分发, 只要在大群里面说明版权问题, 就没有太大的传开的风险. 这么大量的文件放在服务器里, 服务器的费用太高, 至少对于我这样的穷鬼来说是完全不可行的; 一旦你被警告, 公网ip就难说了, 你的其它事情可能也会受影响.

反: 就算说明了版权问题, 我们也不可能信任大群里的所有人不外传; 会用BT的人没有会上网的人多, 这样一方面增大了传播的风险, 一方面限制了一些同学看回放的机会. 同学们看回放要么在线播放要么下载, BT也阻绝了在线播放的道路.

正: 我想hsy的学生这点学习能力还是有的, BT还是学得会的... 而且实际上目前的方式即注册, 它仍然是半透明状态, 只要有人向外泄露自己的账号密码, 外人仍然能够查看所有的回放; 退一万步, 我们的资源是从百度网盘上面下载下来的, 百度网盘本来就是一个半透明的应用, 加之我们的链接分享的提取码实际上已经泄露了...; 并且单从网课平台来看, 如果有人对外告知他的用户名密码, 所有的网课录像也是公开的. 你的注册制实际上也是建立在对大群里的同学的信任基础上; BT的下载速度对同学们的体验也是一大帮助.

反: 你觉得种子和服务器哪个更好传播? 种子谁都会下, 服务器还可以拦一部分人; 不是任何人都懂爬视频, 但任何人都可以下个迅雷.

正: 种子和服务器上的视频确实是种子更好传播; 但是种子和服务器的用户名+密码基本是差不多了. (其实你的nas的服务器... 也是半公开的啊, 目前没有任何加密策略, 知道地址就能访问)

后面的话... 我吃饭去了, 讨论结束.

但是我还是想继续说说. 首先我们看到, dns服务商提供的解析是有ip/无ip, 似乎并没有直接的主域名下有哪些二级域名, 所以通过增加二级域名的复杂程度可以简单降低试出来的可能性. 爆破法试loid.top的结果如下(Nico不要打我):

SubDomains

比如将nas换成nicosnas就能极大拉低爆破成功率... 然后套cf(CloudFlare)也是很好的解决方案(有点慢)... nas目录加密(似乎已被采用)或者目录403或者目录拒绝访问(ERR_CONNECTION_REFUSED)也是挺好的解决办法. 这些是资源;

资源目录加密后紧接着就是索引(前面提到过的tree.json), 如果索引到手, 跟目录不加密效果相同. 所以我的索引目前部署在cf上面, 通过对http请求的几个点的判断限制只有/xuetang365才能正常访问. 加密方式就不透露了, 有兴趣自己试试. (好吧其实加密挺失败的, 只要有loid.top的账号密码就能访问)

然后再说之前我第一次尝试做Classin回放站时候, 我的回放站没有嵌入到loid里面, 单独成页, 这时我想到了一个加密方式:

  1. 在loid新建一个类链接, 在其后插入时间加盐MD5, 盐可以很复杂; 如:

     location.href = "https://loid.top/a" + md5("sorghe(*#%EHFroi39gohwf" + Date())
  2. 在网页后台加入判断如果给定的MD5不是3秒内的MD5就回Forbidden

实际操作问题不大, 但是对于我这样喜欢整活的人似乎也不是那么难破解... 在跳转页打断或者抓包就可以得到规则 (似乎前提还是有loid账号密码, 感觉没毛病) 加盐MD5是个好东西. 比如N久以前的那段 手机号已经注册过 后面的password是加盐MD5, 我们现在都还没搞清楚究竟如何加密的.

对于信任问题: 我们管理组之间为何互相信任, 为何大群的所有人我们无法完全信任, 这留给Nico解释如何?

Re:还在在于了解和规模的问题。管理组起码是共事了几个月的同伴,而大群着实人太多,难以分辨真假。规模大了风险就大的道理都明白,因此这的确不是一个保险的做法。我愿意相信他们,可作为管理我必须保证其安全性。


附录补充

大佬(Ajax改的) yurzhang 写的两个油猴脚本:

  1. 在阳光网络课堂回放页显示课程名称
  2. 阳光网络课堂直播优化脚本
// ==UserScript==
// @name         阳光网络课堂回放助手
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  显示回放所对应的课程
// @author       yurzhang
// @include      http://fudao.xuetang365.com/Student/Course/replayList/courseId/*.html
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function() {
    'use strict';
    GM_xmlhttpRequest({
        method: 'get',
        url: 'https://gitee.com/yurzhang/file_hosting/raw/master/rep.json',
        onload: function(response) {
            var link=window.location.href;
            var reg; var pgs;
            if(link.match('page')) {
                reg=/\/(\d+)\/page\/(\d+).html/;
                pgs=link.match(reg)[2];
                link=link.match(reg)[1];
            } else {
                reg=/\/(\d+).html/; pgs=1;
                link=link.match(reg)[1];
            } var pageNum;
            if($('.laypage_last').attr('data-page')!==undefined)
                pageNum=$('.laypage_last').attr('data-page');
            else if($('.laypage_next').prev().attr('data-page')!==undefined)
                pageNum=$('.laypage_next').prev().attr('data-page');
            else pageNum=pgs;
            var allnum=0; var gets=[];
            for(var i=parseInt(pgs)+1;i<=parseInt(pageNum);++i)
                gets.push($.ajax({
                    type: 'get',
                    url: 'http://fudao.xuetang365.com/Student/Course/replayList/courseId/'+link+'/page/'+i+'.html',
                    success: function(content) {
                        var tb=$('<div></div>');
                        tb.html(content);
                        tb=$('.table.table-bordered.table-big',tb)[0];
                        allnum+=tb.children[1].children.length;
                    }
                }));
            $.when.apply($,gets).then(function(){
                var tb=$('.table.table-bordered.table-big')[0];
                var tmp=document.createElement('th');
                tmp.innerHTML='课程名称';
                tb.children[0].children[0].prepend(tmp);
                tb=tb.children[1].children;
                var lessons=$.parseJSON(response.responseText);
                for(var i=tb.length-1;i>=0;--i) {
                    var qwq=lessons[allnum];
                    ++allnum; var nr='';
                    if(qwq.replace(/[^\x00-\xff]/g,"xx").length>30) {
                        var l=0;
                        for(var j=0;j!=qwq.length;++j) {
                            nr+=qwq.charAt(j);
                            l+=(qwq.charAt(j).match(/[^\x00-\xff]/)!=null?2:1);
                            if(l>=30) {
                                nr+='<br/>\n';
                                l=0;
                            }
                        }
                    } else nr=qwq;
                    tmp=document.createElement('th');
                    tmp.innerHTML=nr;
                    tb[i].prepend(tmp);
                }
            })
        }
    });
})();
// ==UserScript==
// @name         阳光网络课堂助手
// @namespace    http://tampermonkey.net/
// @version      1.1.2
// @description  一些实用或不实用的小东西
// @author       yurzhang
// @include      https://view.csslcloud.net/api/view/index*
// @grant        none
// @require      https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.10.0-rc.1/katex.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.10.0-rc.1/contrib/auto-render.min.js
// ==/UserScript==

var userList = new Array();
var idx = new Array();

(function() {
    'use strict';
    $("#left-bar").click();
    var ncss = document.createElement("link");
    ncss.rel = "stylesheet";
    ncss.type = "text/css";
    ncss.href = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.10.0-rc.1/katex.min.css";
    $('head').append(ncss);
    window.setInterval(function(){renderMathInElement(document.body,{delimiters:[{left:"$$",right:"$$",display:true},{left:"$",right:"$",display:false}]});},1000);
    window.showEm = function(str) {
        if(!$.trim(str)) return '';
        str = str.replace(/\</g, '&lt;');
        str = str.replace(/\>/g, '&gt;');
        str = str.replace(/\n/g, '<br/>');
        str = str.replace(/\"/g, '&quot;');
        str = str.replace(/\[em_([0-9]*)\]/g, '<img src="//static.csslcloud.net/img/em/$1.gif" border="0" />');
        str = str.replace(/\[em2_([0-9]*)\]/g, '<img src="//static.csslcloud.net/img/em2/$1.png" border="0" />');
        var nmsg = '';
        var reg = new RegExp(/\[img_http(s)?:\/\/(.*?)\]/g);
        var isImage = reg.test(str);
        if (isImage) {
            var sIndex = str.indexOf('_') + 1;
            nmsg = str.slice(sIndex, str.length - 1);
            var imgTag = '<div class="chatImage" style="width: 100%" ><img src="' + nmsg + '"  style="width: 100%;cursor:pointer;" onclick="showMsgImage(event)"/></div>';
            return imgTag;
        } $.each(str.split(' '), function (i, n) {
            n = $.trim(n);
            if (n.indexOf('[uri_') == 0 && n.indexOf(']') == n.length - 1 && n.length > 6) {
                var u = n.substring(5, n.length - 1) + ' ';
                nmsg += '<a target="_blank" style="color: #2f53ff" href="' + u + '">' + u + '</a>' + ' ';
            } else nmsg += n + ' ';
        });
        var baseUrl = '//static.csslcloud.net/';
        var reg = new RegExp(/\[em2_(q[1]|q[2])\]/ig);
        nmsg = nmsg.replace(reg, '<img class="em2-q em2-$1 kou" src="' + baseUrl + 'img/emoticon/em2/em2_q/$1.png"/>');
        reg = new RegExp(/\[cem_(http(s)?:\/\/.+\.(jpg|gif|png))\]/ig);
        nmsg = nmsg.replace(reg, '<img class="img cem" src="$1" />');
        return nmsg;
    }
    window.on_cc_live_chat_msgs = function(datas) {
        var cmHtml = ''
        var barrageList = []
        var chats = datas
        $.each(datas, function (index, data) {
            if (!isWithGroup(data)) { return; }
            var barrageInfo = $.trim(data.msg);
            var reg = new RegExp(/\[img_http(s)?:\/\/(.*?)\]/g);
            if (reg.test(barrageInfo)) {
                //barrageInfo = '';
            } else {
                if (data.status === '0')
                    barrageList.push(barrageInfo);
            } cmHtml += Template.chatMsg({
                admin: data.userrole == 'publisher' || data.userrole == 'teacher' || data.userrole == 'host',
                name: '[' + data.time + '] ' + data.username,
                content: showEm(data.msg),
                id: data.userid,
                chatId: data.chatId,
                status: data.status,
                isFromMe: Viewer.isMe(data.userid)
            });
        });
        if ($('#barrage').val() == 1)
            $.DW.barrageList(JSON.stringify({barrageInfo: barrageList}));
        $('#chat-list').append(cmHtml);
        var rc = $('#chat-list').children().length - 500 + datas.length;
        if (rc > 0)
            $('#chat-list> li:lt(' + rc + ')').remove();
        var uid = $('.select-current').attr('id');
        if (uid != 'all' && $('.viewall').hasClass('viewall-active')) {
            $('#chat-list li').hide();
            $('#chat-list li[uid="' + uid + '"]').show();
            $('.c-chat').hide();
            $('.pchat span').hide();
            $('.pchat .name-from').show();
            $('.name-from').removeClass('name-tip');
        } chatScroll();
    }
    userList[$('#viewerId').val()] = $('#viewerName').val();
    idx[$('#viewerName').val()] = $('#viewerId').val();
    var tmp=document.createElement('span');
    tmp.id="count";
    $(".lmb-r-tools")[0].append("在线人数:");
    $(".lmb-r-tools")[0].append(tmp);
    $(".lmb-r-tools")[0].append("人 | 在线管理员:");
    tmp=document.createElement('span');
    tmp.id="adm";
    $(".lmb-r-tools")[0].append(tmp);
    var opts = {
        roomId: $('#roomId').val(),
        viewer: { sessionId: $.cookie('sessionid') },
        chat: {
            host: $('#chatHost').val(),
            spareHost: $('#backupChatHost').val()
        }
    };
    $(".lmb-r-tools")[0].append(" | 我的 userid:" + $('#viewerId').val());
    var params = {
        sessionid: opts.viewer.sessionId,
        platform: 1,
        terminal: 0
    };
    if (window.location.protocol === 'https:')
        params.secure = true;
    var host = opts.chat.host;
    var spareHost = opts.chat.spareHost;
    var socket = io.connect(SocketUtils.getConnectURI(host, opts.roomId), { query: params });
    new SocketSentinel(socket, SocketUtils.getConnectURI(spareHost, opts.roomId));
    socket.on('room_teachers', function (data) {
        data=JSON.parse(data);
        var qwq='';
        for(var i=0;i!=data.teachers.length;++i)
            qwq += data.teachers[i].name + '(' + data.teachers[i].ip + ') ';
        if(qwq=='') qwq='无'
        var nw=$('#adm')[0];
        nw.innerHTML=qwq;
    });
    socket.on('ban_chat', function (data) {
        $('#alct')[0].innerHTML = '(禁言中...)';
    });
    socket.on('unban_chat', function (data) {
        $('#alct')[0].innerHTML = '';
    });
    socket.on('room_setting', function (data) {
        data = JSON.parse(data);
        if(data.allow_chat == 'false')
            $('#alct')[0].innerHTML = '(禁言中...)';
        else $('#alct')[0].innerHTML = '';
    });
    socket.on('chat_message', function (data) {
        data = JSON.parse(data);
        userList[data.userid] = data.username;
        idx[data.username] = data.userid;
    });
    socket.on('private_chat', function (data) {
        data = JSON.parse(data);
        userList[data.fromuserid] = data.fromusername;
        idx[data.fromusername] = data.fromuserid;
    });
    var rlblk = document.createElement('div');
    rlblk.setAttribute('style','display:none;');
    rlblk.innerHTML='<form><table><tr><td><textarea wrap="virtual" style="width:400px;height:200px;resize:none;" required></textarea></td></tr><tr><td>发送对象(留空对所有人发送):<input type="text" id="tous" style="width:190px;"></td></tr><tr><td><div style="text-align:center"><button type="button" onclick="sd()">发送文本</button><span style="display:inline-block;width:60px;"></span><button type="button" onclick="sdpc()">发送图片</button></div></td></tr></table></form>';
    var hr = document.createElement('div');
    hr.setAttribute('id','here');
    $('body').append(hr);
    var chat_btn = document.createElement('a');
    chat_btn.setAttribute('id','clk');
    chat_btn.innerHTML='[高级输入框] ';
    chat_btn.onclick = function() {
        hr.append(createdialog(418,340,rlblk,"高级输入框",true));
    }
    $('.chat-title')[0].children[0].append(chat_btn);
    var ctmk = document.createElement('span');
    ctmk.id = 'alct';
    ctmk.style = 'color:red';
    $('.chat-title')[0].children[0].append(ctmk);
    window.sd = function() {
        if($('#tous').val() == '') $.DW.sendChat($('textarea').val());
        else {
            var re=/[\u4e00-\u9fa5]+/;
            var inp=$('#tous').val();
            if(re.test(inp)) {
                if(idx[inp]!==undefined)
                    $.DW.sendPrivateChat($('textarea').val(),0,idx[inp],inp);
                else {
                    alert('未找到名为' + inp + '的用户!可能 Ta 还没有发言过?');
                    return;
                }
            } else {
                var ton;
                if(userList[inp]!==undefined)
                    ton=userList[inp];
                else ton='未知用户';
                $.DW.sendPrivateChat($('textarea').val(),0,inp,ton);
            }
        } $('textarea').val('');
    }
    window.sdpc = function() {
        if($('#tous').val() == '') $.DW.sendChat('[img_' + $('textarea').val() + ']');
        else {
            var re=/[\u4e00-\u9fa5]+/;
            var inp=$('#tous').val();
            if(re.test(inp)) {
                if(idx[inp]!==undefined)
                    $.DW.sendPrivateChat('[img_' + $('textarea').val() + ']',0,idx[inp],inp);
                else {
                    alert('未找到名为' + inp + '的用户!可能 Ta 还没有发言过?');
                    return;
                }
            } else {
                var ton;
                if(userList[inp]!==undefined)
                    ton=userList[inp];
                else ton='未知用户';
                $.DW.sendPrivateChat('[img_' + $('textarea').val() + ']',0,inp,ton);
            }
        } $('textarea').val('');
    }
})();

var opblk = false;
function createdialog(width, height, bodycontent, title, removeable) {
    if(opblk) {
        alert('你已经打开了高级输入框!');
        return;
    } opblk = true;
    var dialog = document.createElement("div");
    var dialogtitlebar= document.createElement("div");
    var dialogbody = document.createElement("div");
    var dialogtitle = document.createElement("span");
    var dialogclose = document.createElement("span");
    var closeaction = document.createElement("button");
    dialog.id = "yurzhang";
    dialogtitle.innerHTML = title;
    dialogtitlebar.appendChild(dialogtitle);
    dialogtitlebar.appendChild(dialogclose);
    dialogclose.appendChild(closeaction);
    if(bodycontent!=null) {
        bodycontent.style.display = "block";
        dialogbody.appendChild(bodycontent);
    } dialog.appendChild(dialogtitlebar);
    dialog.appendChild(dialogbody);
    var templeft,temptop,tempheight;
    var dialogcssText,dialogbodycssText;
    templeft = (document.body.clientWidth-width)/2;
    temptop = (document.body.clientHeight-height)/2;
    tempheight= height-30;
    dialogcssText= "z-index:666;position:absolute;background:#65c294;padding:1px;border:4px;top:"+temptop+"px;left:"+templeft+"px;height:"+height+"px;width:"+width+"px;";
    dialogbodycssText = "width:100%;background:#ffffff;"+"height:" + tempheight + "px;";
    dialog.style.cssText = dialogcssText;
    dialogtitlebar.style.cssText = "height:30px;width:100%;cursor:move;";
    dialogbody.style.cssText  = dialogbodycssText;
    dialogtitle.style.cssText = "font-size:16px;float:left;display:block;margin:4px;line-height:20px;";
    dialogclose.style.cssText  = "float:right;display:block;margin:4px;line-height:20px;";
    closeaction.style.cssText = "background-color:red;height:20px;width:24px;border-width:1px;cursor:pointer;";
    var dialogleft = parseInt(dialog.style.left);
    var dialogtop = parseInt(dialog.style.top);
    var ismousedown = false;
    closeaction.onclick = function() {
        opblk = false;
        dialog.parentNode.removeChild(dialog);
    }
    if(removeable == true) {
        var ismousedown = false;
        var dialogleft,dialogtop;
        var downX,downY;
        dialogleft = parseInt(dialog.style.left);
        dialogtop = parseInt(dialog.style.top);
        dialogtitlebar.onmousedown = function(e) {
            ismousedown = true;
            downX = e.clientX;
            downY = e.clientY;
        }
        document.onmousemove = function(e) {
            if(ismousedown){
                dialog.style.top = e.clientY - downY + dialogtop + "px";
                dialog.style.left = e.clientX - downX + dialogleft + "px";
            }
        }
        document.onmouseup = function() {
            dialogleft = parseInt(dialog.style.left);
            dialogtop = parseInt(dialog.style.top);
            ismousedown = false;
        }
    } return dialog;
}

以及高二回放站代码(非屎山,早就重构过了)知道了, 但是为什么这么长... 我们高一站才100行出头... Classin三个完全不同的源才200行 (BY Ajax)

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8"/>
        <link rel="icon" type="image/png" sizes="520x520" href="icon.png"/>
        <link rel="stylesheet" href="https://cdnjs.loli.net/ajax/libs/mdui/0.4.3/css/mdui.min.css">
        <script src="https://cdnjs.loli.net/ajax/libs/mdui/0.4.3/js/mdui.min.js"></script>
        <script src="DPlayer.min.js"></script>
        <script src="jquery.min.js"></script>
        <title>华中师大一附中高二网课回放</title>
        <style>
            #dplayer {
                max-width: 1280px;
                height: 720px;
                margin: 0 auto;
            }
        </style>
        <script>
            var _hmt = _hmt || [];
            (function() {
              var hm = document.createElement("script");
              hm.src = "https://hm.baidu.com/hm.js?b1fdc74f2f397069bfa017f546459427";
              var s = document.getElementsByTagName("script")[0];
              s.parentNode.insertBefore(hm, s);
            })();
        </script>
    </head>
    <body class="mdui-theme-accent-blue">
        <div class="mdui-typo">
            <div class="mdui-text-center">
                <h1>华中师大一附中高二年级网课课程回放平台<small>不含阳光网络课堂历史课程</small></h1>
            </div>
            <div class="mdui-container">
                <div class="mdui-textfield mdui-textfield-floating-label">
                    <i class="mdui-icon material-icons">search</i>
                    <label class="mdui-textfield-label">输入关键字...</label>
                    <input class="mdui-textfield-input" type="text" id="js-classId"/>
                </div>
                <ul class="mdui-list mdui-list-dense" id="classid" style="display: none; height: 700px; overflow-y: auto;"></ul>
            </div>
        </div>
        <div class="mdui-center mdui-text-center">
            <span class="" style="font-weight:300;font-size:24px;" id="nwzt">正在播放</span>
            <span class="mdui-center mdui-text-center" style="font-weight:400;font-size:26px;" id="nwvd">【Animenz】名侦探柯南 主题曲 钢琴版</span>
        </div>
        <div id="dplayer"></div>
    </body>
    <script>
        var dp = new DPlayer({
            container: document.getElementById('dplayer'),
            video: {
                quality: [
                    {
                        name: '主线路',
                        url: '1.mp4'
                    }
                ],
                defaultQuality: 0
            },
            danmaku: {
                id: 'MAIN1',
                api: 'http://play2.loid.top:1207/',
                maximum: 1000,
                addition: ['http://play2.loid.top:1207/v3/bilibili?aid=540887495']
            }/*,
            subtitle: {
                url: '1.vtt',
                fontSize: '30px',
                bottom: '10px',
                color: '#2196F3'
            }*/
        });
        dp.on('pause', function() {
            $('#nwzt')[0].innerHTML = '暂停播放';
        });
        dp.on('play', function() {
            $('#nwzt')[0].innerHTML = '正在播放';
        });
        $('.dplayer-full-in-icon').remove();
        $('.dplayer-notice').remove();
        dp.danmaku.opacity(1);
        var lk;
        $.ajax({
            url: 'list.json',
            success: function(content) {
                lk = JSON.parse(content);
            }
        });
        var bk;
        $.ajax({
            url: 'matsuri.json',
            success: function(content) {
                bk = JSON.parse(content);
            }
        });
        $.ajax({
            url: 'rep.json',
            success: function(content) {
                var nm = JSON.parse(content);
                for(var i = nm.length - 1; i != -1; -- i)
                    if(nm[i] != '')
                        $('#classid').append(`<li data-id="${i}" class="mdui-list-item mdui-ripple"><a href="javascript:void(0)">${nm[i]}</a></li>`);
            }
        });
        jQuery.expr[':'].Contains = function(a, i, m) {
            return (a.textContent || a.innerHTML || "").toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
        };
        function filterList(list) {
            $('#js-classId').bind('input propertychange', function() {
                var filter = $(this).val();
                if(filter) {
                    $matches = $(list).find('a:Contains(' + filter + ')').parent();
                    $('li', list).not($matches).hide();
                    $matches.show();
                } else $(list).find('li').show();
            });
        }
        var nowCs;
        $(function() {
            filterList($('#classid'));
            $('#js-classId').bind('focus', function() {
                dp.pause();
                $('#dplayer').hide();
                $('#classid').slideDown();
            }).bind('blur', function() {
                $('#classid').slideUp('normal', function() {
                    $('#dplayer').show();
                });
            });
            $('#classid').on('click', 'li', function() {
                $('#classid').slideUp('fast', function() {
                    $('#dplayer').show();
                });
                dp.destroy();
                if($(this).data('id') <= 271 || bk[$(this).data('id') - 272] == '') {
                    dp = new DPlayer({
                        container: document.getElementById('dplayer'),
                        video: {
                            quality: [
                                {
                                    name: '线路 1',
                                    url: 'https://files.loid.top/netclass2/' + lk[$(this).data('id')] + '?rootId=0AIfTBLxk2DWmUk9PVA'
                                },
                                {
                                    name: '线路 2',
                                    url: 'https://1456877493.rsc.cdn77.org/' + lk[$(this).data('id')] + '?rootId=0AIfTBLxk2DWmUk9PVA'
                                },
                                {
                                    name: '线路 3',
                                    url: 'https://misty-firefly-bdfb.yurzhang.workers.dev/netclass2/' + lk[$(this).data('id')] + '?rootId=0AIfTBLxk2DWmUk9PVA'
                                }
                            ],
                            defaultQuality: 2
                        },
                        danmaku: {
                            id: lk[$(this).data('id')],
                            api: 'http://play2.loid.top:1207/',
                            maximum: 1000,
                            addition: ['danmaku\\dmk' + $(this).data('id') + '.json']
                        }
                    });
                } else {
                    dp = new DPlayer({
                        container: document.getElementById('dplayer'),
                        video: {
                            quality: [
                                {
                                    name: '源线路',
                                    url: 'https://1252412222.vod2.myqcloud.com/794b4a11vodbj1252412222/' + bk[$(this).data('id') - 272] + '/f0.mp4'
                                }
                            ],
                            defaultQuality: 0
                        },
                        danmaku: {
                            id: lk[$(this).data('id')],
                            api: 'http://play2.loid.top:1207/',
                            maximum: 1000,
                            addition: ['danmaku\\dmk' + $(this).data('id') + '.json']
                        }
                    });
                }
                dp.on('pause', function() {
                    $('#nwzt')[0].innerHTML = '暂停播放';
                });
                dp.on('play', function() {
                    $('#nwzt')[0].innerHTML = '正在播放';
                });
                $('.dplayer-full-in-icon').remove();
                $('.dplayer-notice').remove();
                dp.danmaku.opacity(1);
                _hmt.push(['_trackEvent', 'video', 'play', $(this).data('id')]);
                $('#nwvd')[0].innerHTML = $(this).text();
                if(nowCs !== undefined)
                    nowCs.classList.remove('mdui-list-item-active');
                nowCs = this;
                nowCs.classList.add('mdui-list-item-active');
            });
        });
    </script>
</html>

这里再附上高二阳光网络课堂的所有课时评论:

danmaku.zip

它们在回放站中会以弹幕形式再放送!


最后为 Nico 打call!

Last modification:July 5, 2020
如果觉得我的文章对你有用,请随意赞赏~