网课字幕

暂支持B站和网易公开课

// ==UserScript==
// @name         网课字幕
// @namespace    http://tampermonkey.net/
// @version      2.0
// @homepage     https://www.baidu.com/
// @description  暂支持B站和网易公开课
// @author       hello world
// @match        fanyi.baidu.com
// @match       *://*.bilibili*
// @include      http*://www.bilibili.com/video/*
// @include      http*://www.bilibili.com/bangumi/play/ss*
// @include      http*://www.bilibili.com/bangumi/play/ep*
// @include      http*://www.bilibili.com/watchlater/
// @include      http*://www.bilibili.com/medialist/play/ml*
// @include      http*://www.bilibili.com/blackboard/html5player.html*
// @include      http*://www.bilibili.com/cheese/*
// @include      http*://open.163.com/*
// @icon         https://www.google.com/s2/favicons?domain=csdn.net
// @grant        none
// @antifeature  暂支持B站和网易公开课
// ==/UserScript==



var musicUl;
var i;
var time1=new Date();
var flag1 = 1;
var k2;
var data2;

window.onload = function () {

  

    //dofinish();
    setTimeout(dofinish, 5000);
   
   
    // let h=document.getElementById("music");
    //     musicPlay(h);
    //     return;
    //  setTimeout(dofinish,5000);
    //  musicPlay(h);

}



function decodeFromSRT(input) {
    let g = {
        srtReg: /(?:(\d+):)?(\d{1,2}):(\d{1,2})[,\.](\d{1,3})\s*(?:-->|,)\s*(?:(\d+):)?(\d{1,2}):(\d{1,2})[,\.](\d{1,3})\r?\n([.\s\S]+)/

    };


    if (!input) return;
    const data = [];
    let split = input.split('\n\n');
    if (split.length == 1) split = input.split('\r\n\r\n');
    split.forEach(item => {
        const match = item.match(g.srtReg);
        if (!match) {
            //console.log('跳过非正文行',item);
            return;
        }
        data.push({
            time: (match[1] * 60 * 60 || 0) + match[2] * 60 + (+match[3]) + (match[4] / 1000),
            lrc: match[9].trim().replace(/{\\.+?}/g, '').replace(/\\N/gi, '\n').replace(/\\h/g, ' ')
        });
    });
    return { body: data };
};


function decodeFromLRC(input) {
    if (!input) return;
    const data = [];
    input.split('\n').forEach(line => {
        let match = line.match(/((\[\d+:\d+\.?\d*\])+)(.*)/);
        if (!match) {
            if (match = line.match(/\[offset:(\d+)\]/i)) {
                this.offset.value = +match[1] / 1000;
            }
            //console.log('跳过非正文行',line);
            return;
        }
        const times = match[1].match(/\d+:\d+\.?\d*/g);
        times.forEach(time => {
            const t = time.split(':');
            data.push({
                time: t[0] * 60 + (+t[1]),
                content: match[3].trim().replace('\r', '')
            });
        });
    });
    return {
        body: data.sort((a, b) => a.time - b.time).map((item, index) => (
            item.content != '' && {
                time: item.time,
                // to:index==data.length-1?item.time+20:data[index+1].time,
                lrc: item.content
            }
        )).filter(item => item)
    };
}


function decodeFromASS(input) {
    if (!input) return;
    const data = [];
    let split = input.split('\n');
    split.forEach(line => {
        const match = line.match(this.assReg);
        if (!match) {
            //console.log('跳过非正文行',line);
            return;
        }
        data.push({
            time: match[1] * 60 * 60 + match[2] * 60 + (+match[3]),
            // to:match[4]*60*60 + match[5]*60 + (+match[6]),
            lrc: match[7].trim().replace(/{\\.+?}/g, '').replace(/\\N/gi, '\n').replace(/\\h/g, ' ')
        });
    });
    return { body: data };
}



function decodeFile(text, type) {

    // let data2;
    // const type = k2.file.name.split('.').pop().toLowerCase();
    //  console.log(this.reader.result);
    switch (type) {
        case 'lrc': data2 = decodeFromLRC(text); break;
        case 'ass': case 'ssa': data2 = decodeFromASS(text); break;
        case 'srt': case 'sbv': case 'vtt': data2 = decodeFromSRT(text); break;
        case 'bcc': data2 = JSON.parse(text); break;
        default: break;
    }

    lrc = data2;

}



function setCookie(name,value)
{
var Days = 1000;
var exp = new Date();
exp.setTime(exp.getTime() + Days*24*60*60*1000);
document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString();
}
function getCookie(name)
{
var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
if(arr=document.cookie.match(reg))
return unescape(arr[2]);
else
return null;
}


var a,b,h1_1,h1_2,h1_3,h2_1,h2_2,h2_3,d_top;

var font_color1;

var firstkkk = 1;
var els2;
var kinds;
var videoid;
function dofinish() {


    let encodings = ['UTF-8', 'GB18030', 'BIG5', 'UNICODE', 'JIS', 'EUC-KR'];
    
    
    els2 = document.getElementsByClassName("r-con")[0];//b 站
    kinds=0;
    if(els2==undefined){
        els2=document.getElementsByClassName("video-list")[0];//网易空开课
        kinds=1;
        videoid=document.getElementById("vjs_video_3_html5_api");
    }
    //let els3 = document.getElementsByClassName("up-info report-wrap-module report-scroll-module")[0];
    
    var y1=document.createElement("div");

    //document.body.insertBefore(y1,document.body.firstElementChild);

    els2.insertBefore(y1,els2.firstElementChild);

    templeft = "10px";
    temptop = "10px";
    y1.style.marginLeft=templeft;
    y1.style.marginTop=temptop;
    let y2=document.createElement("a");
    y1.appendChild(y2);
    y1.id="12345";
    els2=y1;

    var dialog=y1;
    var dialogleft = parseInt(dialog.style.marginLeft);
    var dialogtop = parseInt(dialog.style.marginTop);
    var ismousedown = false;
          var dialogleft, dialogtop;
          var downX, downY;
          dialogleft = parseInt(dialog.style.marginLeft);
          dialogtop = parseInt(dialog.style.marginTop);
          dialog.onmousedown = function (e) {
            ismousedown = true;
            downX = e.clientX;
            downY = e.clientY;
          }
          document.onmousemove = function (e) {
            if (ismousedown) {
              dialog.style.marginTop = e.clientY - downY + dialogtop + "px";
              dialog.style.marginLeft = e.clientX - downX + dialogleft + "px";
            }
          }
          /*松开鼠标时要重新计算当前窗口的位置*/
          document.onmouseup = function () {
            dialogleft = parseInt(dialog.style.marginLeft);
            dialogtop = parseInt(dialog.style.marginTop);
            ismousedown = false;
          }






    let els3=els2.firstElementChild;

    var d1 = document.createElement("div");
    d1.id = "music";
    d1.style = "margin: 0 auto;width: 400px;height: 750px";
    els2.insertBefore(d1, els3);


    



    // var k = document.getElementById("viewbox_report")
    k2 = document.createElement("input");
    els2.insertBefore(k2, d1);







 


    var m1 = document.createElement("select");
    els2.insertBefore(m1, k2);
    // m1.id="be_slected"
    //m1.append("<option value="+"aaa"+">"+abb+"</option>");
    var y1 = document.createElement("option");
    m1.appendChild(y1);
    y1.text = y1.value = encodings[0];

    y1 = document.createElement("option");
    m1.appendChild(y1);
    y1.text = y1.value = encodings[1];

    y1 = document.createElement("option");
    m1.appendChild(y1);
    y1.text = y1.value = encodings[2];

    y1 = document.createElement("option");
    m1.appendChild(y1);
    y1.text = y1.value = encodings[3];

    y1 = document.createElement("option");
    m1.appendChild(y1);
    y1.text = y1.value = encodings[4];



    var m2 = document.createElement("select");
    els2.insertBefore(m2, m1);

    var y0 = document.createElement("option");
    m2.appendChild(y0);
    y0.text ="大";
    y0.value = 0;

    var y1 = document.createElement("option");
    m2.appendChild(y1);
    y1.text ="大";
    y1.value = 0;

    y1 = document.createElement("option");
    m2.appendChild(y1);
    y1.text ="中";
    y1.value = 1;

    y1 = document.createElement("option");
    m2.appendChild(y1);
    y1.text ="小";
    y1.value = 2;








    var d6=document.createElement("input");
    els2.insertBefore(d6, m1);
    d6.placeholder="背景颜色的十六进制";

    var d7=document.createElement("input");
    els2.insertBefore(d7, d6);
    d7.placeholder="选中颜色的十六进制";
    
    var d8=document.createElement("input");
    els2.insertBefore(d8, d7);
    d8.placeholder="字体颜色的十六进制";
    
    


    d6.value=getCookie("d6");
    d7.value=getCookie("d7");
    d8.value=getCookie("d8");
    let g1=getCookie("m2");
    if(g1==1){
        y0.text ="中";
        y0.value = 1;
    }
    else if(g1==2){
        y0.text ="小";
        y0.value = 2;
    }



    k2.type = "file";
    k2.accept = ".lrc,.ass,.ssa,.srt,.bcc,.sbv,.vtt";


    k2.style.width = "370px";
    k2.style.marginBottom = "5px";
    // k2.style.cursor("move");
    // k2.style.userSelect ("none");
    // k2.style.lineHeight("1");
    //k2.innerHTML = "选择字幕";






    var type3;

    k2.onchange = function (e) {



        var reader = new FileReader();

        reader.onload = function (e) {
            let text = reader.result;

            decodeFile(text, type3);


            musicPlay(d1);
            mouse1();


        }

        //  console.log(k2.files[0]);
        type3 = k2.files[0].name.split('.').pop().toLowerCase();
        k2.style.display = "none";
        var encoding = encodings[m1.selectedIndex];
        console.log(encoding);
        m1.style.display = "none";

        var fangan=[
            {
            background_width:"400px",
            background_height:"750px",
            no_slected_font_size:"16px",
            slected_font_size:"19px",
            music_border:"7px"
            },
            {
            background_width:"330px",
            background_height:"750px",
            no_slected_font_size:"15px",
            slected_font_size:"17px",
            music_border:"4px"
            },
            {
            background_width:"280px",
            background_height:"750px",
            no_slected_font_size:"13px",
            slected_font_size:"16px",
            music_border:"0px"
            }
        ]
    
    
    
        
         let fangan_idx=m2.selectedIndex-1;
        if(fangan_idx==undefined||fangan_idx==-1)fangan_idx=0;

        d1.style.width=fangan[fangan_idx].background_width;
        d1.style.height=fangan[fangan_idx].background_height;



        font_color1=d8.value;

        let s2=`.play{
            background-color:`+d7.value+`;
            border-radius:5%;
            font-size:  `+fangan[fangan_idx].slected_font_size+`;
        }
        #music{
            border:`+fangan[fangan_idx].music_border+` solid;
            border-radius: 7%;
            background-color:`+d6.value+`;
            font-size:`+fangan[fangan_idx].no_slected_font_size+`;
        }`;


        var style = document.createElement('style');
        style.innerHTML = s2;
        var head = document.head || document.getElementsByTagName('head')[0];
        head.appendChild(style);
    
        if(fangan_idx==0){
            // let a = 750;//歌词容器到高,随便改,但最好和你自己写到那个div一样高;
            // let b = 55;//li的高度,无特殊要求;
            a=750;
            b=55;
            d_top=233;

            // let h1 = h2_3;
            // if (lrc_li.lrc.length <= h1_1) h1 = h2_1;
            // else if (lrc_li.lrc.length <= h1_2) h1 = h2_2;

            h1_1=18;//字数
            h2_1=30;//高度
            h1_2=38;
            h2_2=58;
            h2_3=80;
        }
        else if(fangan_idx==1){
            // let a = 750;//歌词容器到高,随便改,但最好和你自己写到那个div一样高;
            // let b = 55;//li的高度,无特殊要求;
            a=750;
            b=55;
            d_top=233;

            // let h1 = h2_3;
            // if (lrc_li.lrc.length <= h1_1) h1 = h2_1;
            // else if (lrc_li.lrc.length <= h1_2) h1 = h2_2;

            h1_1=18;//字数
            h2_1=25;//高度
            h1_2=37;
            h2_2=45;
            h2_3=70;
        }
        else{//小 

            // let a = 750;//歌词容器到高,随便改,但最好和你自己写到那个div一样高;
            // let b = 55;//li的高度,无特殊要求;
            
            a=750;
            b=55;


            d_top=233;


            h1_1=17;//字数
            h2_1=24;//高度
            h1_2=32;
            h2_2=45;
            h2_3=67;
        }

        setCookie("d6",d6.value);
        setCookie("d7",d7.value);
        setCookie("d8",d8.value);
        setCookie("m2",fangan_idx);
        d6.style.visibility="collapse";
        d7.style.visibility="collapse";
        d8.style.visibility="collapse";
        m2.style.visibility="collapse";


        reader.readAsText(k2.files[0], encoding);



    }









}

var lrc;


function musicPlay(ele3) {
    console.log("函数。。。");




    //  let music=window.player;
    let musicArea = document.createElement('div');
    // let music = document.createElement('audio');
    musicUl = document.createElement('ul');
    // let a = 750;//歌词容器到高,随便改,但最好和你自己写到那个div一样高;
    // let b = 55;//li的高度,无特殊要求;
    //    let c = 'road.mp3'//歌曲目录,只能放一个哈!



    ele3.appendChild(musicArea);
    //.appendChild(music);
    musicArea.appendChild(musicUl);
    musicStyle();
    //我让ajax打败了,所以歌词直接放变量了。(╯﹏╰)恶补中;
    //烦人的报错,让我把ajax先扔去喂鱼,等下再吃。

    function musicStyle() {//控件css样式;

        els2.style.height = a + 'px';
        //document.getElementsByClassName("r-con")[0].style.height = a + 'px';

        // music.autoplay = true;
        // music.src = c;
        // music.controls = true;
        // music.loop = true;
        // music.style.outline = 'none';
        // music.style.width = '100%';
        musicArea.style.width = '100%';
        musicArea.style.height = '100%';
        musicArea.style.overflow = 'hidden';
        // musicArea.style.outline ='3px solid'
        musicUl.style.listStyle = 'none';
        musicUl.style.width = '100%';
        musicUl.style.padding = '0';
    }
    // //把歌词变成[{time,lrc},{time,lrc}...]的样子,不然没法用的
    // function split() {//把lrc歌词分割成数组,
    //     let split_1 = lrc.split('\n');
    //     let length = split_1.length;
    //     for (let i = 0; i < length; i++) {
    //         let lrcArr = split_1[i];
    //         split_1[i] = change(lrcArr);
    //         function change(str) {
    //             let lrc = str.split(']');
    //             let timer = lrc[0].replace('[', '');
    //             let str_music = lrc[1];
    //             let time_split = timer.split(':');
    //             let s = +time_split[1];
    //             let min = +time_split[0];
    //             return {
    //                 time: min * 60 + s,
    //                 lrc: str_music//分割好到歌词和时间
    //             }

    //         }
    //     }
    //     return split_1
    // }





    let lrcArr = lrc.body;//至此歌词处理完了。
    console.log(lrcArr);
    var topheight = createLi();




    function createLi() {//根据歌词数组创建li
        let len = lrcArr.length;
        var ch = 0;
        var topheight2 = [0];
        for (let i = 0; i < len; i++) {
            let lrc_li = lrcArr[i];
            let li = document.createElement('li');
            li.innerText = lrc_li.lrc;

             let h1 = h2_3;
            if (lrc_li.lrc.length <= h1_1) h1 = h2_1;
            else if (lrc_li.lrc.length <= h1_2) h1 = h2_2;

            if (i) topheight2[topheight2.length] = ch;
            ch += h1;

            li.style.height = h1 + 'px'
            li.style.textAlign = 'center'
            li.style.width = '100%'
            li.style.padding = '0';
            li.style.color = font_color1;
            li.style.transition = '0.3s'
            //  li.style.fontSize='17px';
            li.className = "diy";
           if(kinds==0) li.onclick = () => { window.player.seek(lrc_li.time); time1=new Date();flag1 = 1; current(); };
           else if(kinds==1)li.onclick = () => { videoid.currentTime=lrc_li.time; time1=new Date();flag1 = 1; current(); };
           musicUl.appendChild(li);
        }
        return topheight2;
    }
    function setCurrentLi() {
        let time;
        try {
          if(kinds==0)  time = window.player.getCurrentTime();
            else if(kinds==1)time=videoid.currentTime;
        }
        catch (err) {
            return -1;
        }
        // console.log(time)
        for (i = 0; i < lrcArr.length; i++) {
            let play = lrcArr[i];
           // Math.abs(time - play.time)<=0.00001
           if(Math.abs(time - play.time)<=0.00001)return i;
            if (time<play.time) {
                return i-1;
            }
        } return i - 1;
    }
    function current() {//设置top,让其滚动
        let li = setCurrentLi();
        let divHeight = a;
        let liHeight = b;
        //let top = liHeight * li - divHeight / 2 + liHeight / 2 + 3 * liHeight;
        let top = topheight[li] - d_top;
        if (top < 0) {
            top = 0;
        }
        musicUl.style.marginTop = -top + 'px';
        // console.log('top'+top);
        let playLi = musicUl.querySelector('.play')
        if (playLi) {
            playLi.className = '';
        }
        if (li >= 0) {
            musicUl.children[li].className = 'play';
        }
    }
    // window.player.ontimeupdate = current;


    var lastid = window.location.href;

    fockit();
    function fockit() {

        if (window.location.href != lastid) location.reload();


            setTimeout(() => {

                time1=new Date();
                if(flag1==1) current();
                fockit();
            }, 100);
     
    }



    document.onkeydown = function(){
        flag1=1;
        var keyCode = event.keyCode;
        //console.log(keyCode);
        if(keyCode==16||keyCode==83){//down
           let kk= setCurrentLi();
           videoid.currentTime=lrcArr[kk+1].time;
        }else if(keyCode==13||keyCode==87){//up
            let kk= setCurrentLi();
            if(kk)videoid.currentTime=lrcArr[kk-1].time;
        }
      }

      

}
//Razbit出品,转载请注明出处;





function mouse1() {


    var oDiv = musicUl;

    console.log(oDiv.style.marginTop);


    function onMouseWheel(ev) {/*当鼠标滚轮事件发生时,执行一些操作*/

        time1=new Date();
        flag1=0;

        ev = ev || window.event;
        var down = true; // 定义一个标志,当滚轮向下滚时,执行一些操作
        down = ev.wheelDelta ? ev.wheelDelta < 0 : ev.detail > 0;
        if (down) {
            oDiv.style.marginTop = parseInt(oDiv.style.marginTop) - 30 + 'px';
        } else {
            oDiv.style.marginTop = parseInt(oDiv.style.marginTop) + 30 + 'px';
        }
        if (ev.preventDefault) {/*FF 和 Chrome*/
            ev.preventDefault();// 阻止默认事件
        }
        //flag1=!0;
        return false;
    }
    addEvent(oDiv, 'mousewheel', onMouseWheel);
    addEvent(oDiv, 'DOMMouseScroll', onMouseWheel);
}
function addEvent(obj, xEvent, fn) {
    if (obj.attachEvent) {
        obj.attachEvent('on' + xEvent, fn);
    } else {
        obj.addEventListener(xEvent, fn, false);
    }
}


QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址