bilibili港澳台番剧替换弹幕

点击按钮后,输入想要替换的番剧的网址、Epid、SeasonId其中一种即可替换弹幕

// ==UserScript==
// @name         bilibili港澳台番剧替换弹幕
// @namespace    https://github.com/LuffyLSX/bilibili_danmaku_replace
// @version      1.3
// @description  点击按钮后,输入想要替换的番剧的网址、Epid、SeasonId其中一种即可替换弹幕
// @author       LuffyLSX
// @license      GNU
// @match        https://www.bilibili.com/bangumi/*
// @match        https://www.bilibili.com/video/*
// @require      https://unpkg.com/[email protected]/dist/ajaxhook.min.js
// @require      http://code.jquery.com/jquery-3.x-git.min.js
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function () {
    let css = `
        .danmu-replace {
            margin: 0px 0px 0px 28px;
            position: relative;
            display: block;
            float: left;
            height: 36px;
            cursor: pointer;
        }

        .danmu-svg {
            width: 28px;
            height: 28px;
            display: inline-block;
            fill: #757575;
        } 

        .danmu-span {
            display: inline-block;
            vertical-align: top;
            height: 28px;
            line-height: 28px;
            font-size: 14px;
            color: #505050;margin-left: 5px;
            
        } `
    
        
    function getBangumiData(Epid_or_Ssid = window.location.href, ep = 0){
        $.ajaxSettings.async = false
        var bangumi_data = {}
        var BangumiInfo_url = 'https://bangumi.bilibili.com/view/web_api/season'
        var get_data = {
            ep_id:/ep([0-9]+)/.exec(Epid_or_Ssid) == null ? 0 : /ep([0-9]+)/.exec(Epid_or_Ssid)[1],
            season_id:/ss([0-9]+)/.exec(Epid_or_Ssid) == null ? 0 : /ss([0-9]+)/.exec(Epid_or_Ssid)[1],
        }
        ep_item = document.getElementsByClassName('ep-item cursor visited')
        $.get(BangumiInfo_url, get_data, function(data){
            //bangumi_data.ep_watch = 1
            bangumi_data.ep_watch = (ep_item.length == 0) ? ep : /[0-9]+/.exec(ep_item[0].innerText)[0]
            console.log(bangumi_data.ep_watch)
            bangumi_data.ep_id = data['result']['episodes'][bangumi_data.ep_watch - 1]['ep_id']
            bangumi_data.season_id = data['result']['season_id']
            bangumi_data.title = data['result']['title'].replace(/(.+)/, '')
            bangumi_data.aid = data['result']['episodes'][bangumi_data.ep_watch - 1]['aid']
            bangumi_data.cid = data['result']['episodes'][bangumi_data.ep_watch - 1]['cid']
            bangumi_data.mid = data['result']['episodes'][bangumi_data.ep_watch - 1]['mid'] 
        },"json")
        $.ajaxSettings.async = true
        return bangumi_data
    }

    function getVideoData(bvid = window.location.href, ep_on){
        $.ajaxSettings.async = false
        var video_data = {}
        var get_data = {
            bvid: /BV[0-9A-Za-z]+/.exec(bvid) == null ? bvid : /BV[0-9A-Za-z]+/.exec(bvid)[0],
            jsonp: 'jsonp'
        }
        var VideoInfo_url = 'https://api.bilibili.com/x/player/pagelist'
        $.get(VideoInfo_url, get_data, function(data){
            video_data.cid = data['data'][ep_on - 1]['cid']
            video_data.ep_watch = ep_on
        },"json")
        $.ajaxSettings.async = true
        return video_data
    }

    //合并arraybuff
    function concatenate(arrays){
        let totalLen = 0;
        for (let arr of arrays)
            totalLen += arr.byteLength;
        let res = new Uint8Array(totalLen)
        let offset = 0
        for (let arr of arrays) {
            let uint8Arr = new Uint8Array(arr)
            res.set(uint8Arr, offset)
            offset += arr.byteLength
        }
        return res.buffer
    }

    function inputDanmaku(protobuf){
        ah.proxy({
            onRequest: (config, handler) => {
                handler.next(config);
            },
            //请求发生错误时进入,比如超时;注意,不包括http状态码错误,如404仍然会认为请求成功
            onError: (err, handler) => {
                handler.next(err)
            },
            //请求成功后进入
            onResponse: (response, handler) => {
                var DanmuProtobufUrl = /api\.bilibili\.com\/x\/v2\/dm\/web\/seg\.so.+/
                if (DanmuProtobufUrl.test(response.config.url)) {
                    if (protobuf) {
                        response.response = protobuf;
                        protobuf = undefined;
                        console.log(response.response)
                        ah.unProxy()
                    }
                }
                handler.next(response)
            }
        })
        try {
            window.player.reload()
        } catch(error) {
            window.player.reload({'cid':video_reloadData.cid,'p':video_reloadData.ep_watch})
        }
    }

    
    function getDanmukuProtobuf(cid = 714449041, n = 1){
        var url = "https://api.bilibili.com/x/v2/dm/web/seg.so?type=1&oid=" + cid +"&segment_index=" + n
        var xhr = new XMLHttpRequest()
        xhr.responseType = "arraybuffer"
        xhr.onreadystatechange = function(){
        // 通信成功时,状态值为4
        if (xhr.readyState === 4){
            if (xhr.status === 200){
            console.log(xhr.response)
            //var message = dmList.decode(xhr.response)
            danmuProtobuf.push(xhr.response)
            console.log(xhr.response)
            getDanmukuProtobuf(cid,n + 1)
            } else {
            console.log('弹幕获取完成')
            inputDanmaku(concatenate(danmuProtobuf))
            }
        }
        }
        xhr.onerror = function (e) {
        console.error(xhr.statusText)
        }
        xhr.open('GET', url, true) //只能异步,同步不能为'arraybuffer'
        xhr.send(null)
        return 1
    }

    var video_reloadData = {}
    var danmuProtobuf = new Array()
    function replace(){
        var episodes = document.querySelector('.list-box')
        var ep_on = (document.querySelector('.list-box') == null) ? 1 : /[0-9]+/.exec(episodes.querySelector('.on').innerText)[0]
        if(/video/.test(window.location.href)){
            video_reloadData = getVideoData(window.location.href, ep_on)
        }
        var text = prompt("请输入要替换番剧网址:")
        var EpSsid = /[eps]+([0-9]+)/.exec(text) == null? 0 : /[eps]+([0-9]+)/.exec(text)[0]

        if(EpSsid == 0){
            alert('非法输入')
            console.log(cid)
            return
        }
        var Target = getBangumiData(EpSsid, ep_on)
        getDanmukuProtobuf(Target.cid)
        danmuProtobuf = new Array()
    }
    
    function insert_danmu(){
        let danmu = document.createElement('div')
        danmu.className = "danmu-replace"
        danmu.innerHTML = `
       <div class="danmu-svg">
            <svg viewBox="0 0 28 28">
                        <use xlink:href="#bpx-svg-sprite-dantype-scroll"></use>
                    </svg>
            </div>
        <span class="danmu-span">替换弹幕</span>
        `
        /*
        <div class="danmu-svg">
            <svg viewBox="0 0 28 28">
                        <use xlink:href="#bpx-svg-sprite-dantype-scroll"></use>
                    </svg>
            </div>
        <span class="danmu-span">替换弹幕</span>
        `
        */
        
        document.getElementsByClassName('toolbar_toolbar__NJCNy')[0].appendChild(danmu)
        let styleNode = document.createElement("style");
        styleNode.className = 'css'
        styleNode.appendChild(document.createTextNode(css));
        //(document.querySelector("head") || document.documentElement).appendChild(styleNode);
        document.documentElement.appendChild(styleNode);
    
        danmu.addEventListener('click',function(){replace()})
        danmu.addEventListener("mouseover", function(){document.getElementsByClassName('danmu-span')[0].style.color = '#23ADE5'})
        danmu.addEventListener("mouseout", function(){document.getElementsByClassName('danmu-span')[0].style.color = ''})
    
        danmu.addEventListener("mouseover", function(){document.getElementsByClassName('danmu-svg')[0].style.fill = '#00a1d6'})
        danmu.addEventListener("mouseout", function(){document.getElementsByClassName('danmu-svg')[0].style.fill = ''})
    }
    /*
    function clone_danmu(){
        let sourceNode = document.getElementsByClassName("toolbar-left")[0]
        let danmu = sourceNode.getElementsByClassName('coin')[0].cloneNode(true)
        let svg = danmu.children[1]
        let text = danmu.children[2]
        danmu.title = ''
        danmu.className = 'video_danmu'
        let path = 'M23 3H5a4 4 0 00-4 4v14a4 4 0 004 4h18a4 4 0 004-4V7a4 4 0 00-4-4zM11 9h6a1 1 0 010 2h-6a1 1 0 010-2zm-3 2H6V9h2v2zm4 4h-2v-2h2v2zm9 0h-6a1 1 0 010-2h6a1 1 0 010 2z'
        svg.childNodes[0].setAttribute('d', path)
        text.innerText = '替换弹幕'
        document.getElementsByClassName('toolbar-left')[0].appendChild(danmu)
    
        danmu.addEventListener('click',function(){replace()})
    }
    */
   
    function clone_danmu(){
        let sourceNode = document.getElementsByClassName("toolbar_coin_info__5hnd9 toolbar_item_info__xpKhw")[0]
        let danmu = sourceNode.cloneNode(true)
        let svg = danmu.children[0]
        svg.innerHTML = `
                        <svg viewBox="0 0 28 28">
                            <use xlink:href="#bpx-svg-sprite-dantype-scroll"></use>
                        </svg>
                        `
        svg.style.fill='#757575'
        danmu.addEventListener("mouseover", function(){svg.style.fill = '#00a1d6'})
        danmu.addEventListener("mouseout", function(){svg.style.fill = '#757575'})
        let text = danmu.children[1]
        // danmu.title = ''
        // danmu.className = 'video_danmu'
        // let path = 'M23 3H5a4 4 0 00-4 4v14a4 4 0 004 4h18a4 4 0 004-4V7a4 4 0 00-4-4zM11 9h6a1 1 0 010 2h-6a1 1 0 010-2zm-3 2H6V9h2v2zm4 4h-2v-2h2v2zm9 0h-6a1 1 0 010-2h6a1 1 0 010 2z'
        // svg.childNodes[0].setAttribute('d', path)
        text.innerText = '替换弹幕'
        document.getElementsByClassName('toolbar_toolbar__NJCNy')[0].appendChild(danmu)
    
        danmu.addEventListener('click',function(){replace()})
    }

    var id = setInterval(function(){
        var bangumi_toolbar = document.querySelector('.main-container')
        var video_toolbar = document.querySelector('.video-toolbar-v1')
        if(bangumi_toolbar){
            clone_danmu()
            clearInterval(id)
        }
        if(video_toolbar){
            clone_danmu()
            clearInterval(id)
        }}, 1000)

})();