js弹幕脚本(基于油猴)

js弹幕脚本(基于油猴)

该脚本包含往视频上插入弹幕,发射弹幕,弹幕查询,弹幕暂停,脏话过滤等基础功能。话不多说 ,直接上代码。
仅供参考 ,该代码是我给别人写的定制化的,复制后不可用。

// ==UserScript==
// @name         bullet chat
// @namespace    http://
// @version      0.0.1a
// @description  Display user comments in 'danmaku' style, or in a side comment area
// @require      http://cdn.bootcss.com/jquery/3.2.1/jquery.min.js
// @author       Hezc
// @match        https://
// @grant        GM_xmlhttpRequest
// @connect      *
// ==/UserScript==
(function ($) {
    'use strict';
    let _$ = document;
    const essentialElements = {
        player: _$.getElementById("primaryScreen"),
        sideBar: _$.getElementById("eventTabPanes"),
        video: _$.getElementById("primaryVideo"),
    };
    window.datas = [];
    let listener;
    let danmakuCtl;
    let videoFlag;
    let textList = ['需要屏蔽的关键字1', '需要屏蔽的关键字2', '需要屏蔽的关键字3', '需要屏蔽的关键字4'];
    let timeElapsed = () => essentialElements.video.currentTime;
    let domId = 0;
    var server = () => (getPageID() === null ? (() => { throw 'Page ID not specified!'; })() : `http://127.0.0.1:8888/${getPageID()}`);
    function getPageID() {
        var regex = /\?id\=([0-9a-z\-]+)(&start)?/gi;
        var result = regex.exec(location.href);
        if (result === null) {
            console.error("");
        } else {
            result = result[1];
        }
        return result;
    }

    function loadDanmaku() {
        GM_xmlhttpRequest({
            method: "GET",
            url: server(),
            headers: { "Content-Type": "application/x-www-form-urlencoded" },
            onload: (resp) => {
                datas = JSON.parse(resp.responseText);
                window.danmakuList = datas.filter(v => v.time > timeElapsed() - 1);
                if (danmakuList) {
                    danmakuList.forEach((item) => {
                        listener.register(item.time, () => { danmakuCtl.shoot(item.value, item.id); });
                    });
                } else {
                    console.log("No comment avaliable on this lecture");
                }
                // 弹幕列表
                if (danmakuList.length) {
                    let html = ''
                    for (let i in danmakuList) {
                        html += `<p class="bbp-item" style="line-height: 35px;">${danmakuList[i].value}</p>`
                    }
                    let timer01;
                    timer01 && clearInterval(timer01)
                    timer01 = setInterval(() => {
                        if ($('.bulletChatCont-allp')) {
                            $('.bulletChatCont-allp').html(html)
                            clearInterval(timer01)
                        }
                    }, 33)
                }
            },
            onerror: (e) => {
                console.error("Cannot load comment for this page...");
                console.error(e);
            }
        });


    }
	// 发射弹幕
    function sendDanmaku(content) {
        GM_xmlhttpRequest({
            method: "POST",
            url: server() + "/add",
            data: "value=" + content + "&time=" + (timeElapsed() + ""),
            headers: {
              "Content-Type": "application/x-www-form-urlencoded"
            },
            onload: (resp) => {
                if (resp.responseText.indexOf("Success") != -1){
                    let item = JSON.parse(JSON.stringify(datas[datas.length - 1]));
                    datas.push({ id: ++item.id, vid: ++item.vid, time: timeElapsed(), value: content });
                    listener.register(timeElapsed(), () => { danmakuCtl.shoot(content, item.id); });
                }else{
                    console.warn(resp.responseText);
                }
            },
            onerror: (e) => {
                console.log(e);
            }
        });
    }
	// 单条弹幕相关
    class Barrage {
        constructor(videoBox) {
            this.videoBox = videoBox;
            let rect = this.videoBox.getBoundingClientRect();
            this.w = rect.right - rect.left;
            this.h = rect.bottom - rect.top;
            this.barrageList = [];
        }

        shoot(value, id) {
            let top = this.getTop();
            let color = this.getColor();
            let offset = this.getOffset();
            let reg = new RegExp(textList.join('|'), 'g');
            let barrage = {
                id: id,
                value: value.replace(reg, '***'),
                top: top,
                left: this.w,
                color: color,
                offset: offset,
            }
            this.barrageList.push(barrage);
            this.draw()
        }

        draw() {
            // 创建&&移除
            if (this.barrageList.length) {
                domId++;
                let s = this.barrageList[this.barrageList.length - 1];
                let html = `<div class="apend-dom-zx apend-dom-${domId}"
                            style="color:${s.color};
                            cursor: pointer;
                            position:absolute;
                            top:${s.top}px;
                            animation:mymove 10s;
                            animation-fill-mode: forwards;
                            z-index: 999999;
                            font-size:25px;
                            font-weight:600;"
                            data-id="${s.id}">
                                <span class="bullet-chat-text">${s.value}</span>
                                <div class="bullet-chat-tips">
                                    <div class="bullet-chat-selss">
                                        <div class="bullet-chat-items bullet-chat-items-fabulous">点赞</div>
                                        <div class="bullet-chat-items bullet-chat-items-reply">回复</div>
                                        <div class="bullet-chat-items bullet-chat-items-forward">转发</div>
                                        <div class="bullet-chat-items bullet-chat-items-copy">复制</div>
                                    </div>
                                </div>
                            </div>`;
                $('#BulletChatBox').append(html);
                $('#primaryScreen').on('webkitAnimationEnd', `.apend-dom-${domId}`, function () {
                    $(this).remove()
                });
            }
        }
        getColor() {
            return '#' + Math.floor(Math.random() * 0xffffff).toString(16);
        }
        getTop() {
            return Math.floor(Math.random() * (this.h - 30)) + 30;
        }
        getOffset() {
            return +(Math.random() * 4).toFixed(1) + 1;
        }
    }
	// 弹幕按视频时间进行发射
    class PlayerTimeListener {
        constructor() {
            this.callbackList = new Map();
            this.lastCallOn = 0.0;
        }
        register(time, func) {
            this.callbackList.set(time, [func, true]);
        }
        start() {
            window.interval = setInterval(() => {
                if (timeElapsed() < this.lastCallOn) {
                    this.callbackList.forEach((v, k) => {
                        if (k > timeElapsed()) {
                            this.callbackList.set(k, [v[0], true]);
                        }
                    });
                }
                this.callbackList.forEach((v, k) => {
                    if (k < timeElapsed() && v[1]) {
                        this.callbackList.set(k, [v[0], false]);
                        v[0]();
                    }
                });
                this.lastCallOn = timeElapsed();
            }, 500);
        }
        stop() {
            clearInterval(window.interval);
        }
    }

    function main() {
        listener = new PlayerTimeListener();
        listener.stop();
        listener.start();
        var videoBox = `<div id="BulletChatBox" style="width:100%;height:100%;position:absolute;top:0;left:0;z-index:999;overflow:hidden"></div>`;
        $('#primaryScreen').append(videoBox);
        danmakuCtl = new Barrage($('#BulletChatBox').get(0));
        danmakuCtl.draw();
        loadDanmaku();
    }


    // init
    window.onload = () => {
        setTimeout(main, 2000);

        !function () {
            var timer = setTimeout(() => {
                var commentArea = essentialElements.sideBar.appendChild(_$.createElement("DIV"));
                commentArea.style.width = commentArea.parentElement.clientWidth + "px";
                commentArea.style.height = "10em";
                commentArea.style.position = "absolute";
                commentArea.style.bottom = 0;
                commentArea.style.left = 0;
                commentArea.innerHTML = `<textarea id="danmaku-content" style:"width:100%;height:7em;" placeholder="Write your comment here"></textarea>
                                        <div id="danmaku-submit">Send</div>
                                        <div id="danmaku-switch">Close</div>
                                        `;
                $('#eventTabPanes').on('click', '#danmaku-submit', function () {
                    $("#danmaku-content").val().trim() && sendDanmaku($("#danmaku-content").val());
                    $("#danmaku-content").val('')
                    $("#danmaku-content").css({ 'border-color': 'rgb(133, 133, 133)' })
                    $(this).off()
                })
                // open&close
                $('#eventTabPanes').on('click', '#danmaku-switch', function () {
                    if ($(this).hasClass('switch-flag')) {
                        $(this).removeClass('switch-flag').text('Close')
                        $('#BulletChatBox').css({ 'z-index': '999' })
                    } else {
                        $(this).addClass('switch-flag').text('Open')
                        $('#BulletChatBox').css({ 'z-index': '-1' })
                    }
                })
                //search
                $('#bookmarksTabHeader').after(`<div id="bulletChatCont" class="event-tab-header accented-tab" >
                                                    <span class="text">弹幕</span>
                                                </div>`)
                $('body').append(`<div class="bulletChatCont-box bulletChatCont-box-none" style="width: 300px;min-height: 400px;max-height: 600px;overflow: auto;background: #fff;border-radius: 8px;position: fixed;top: 20px;left: 150px;padding: 0 20px 20px 20px;box-shadow: 0 0 18px rgba(0, 0, 0, .3);z-index: 9999;">
                                    <div class="bulletChatCont-box-header" style="display: flex;background: #fff;align-items: center;justify-content: center;position: sticky;top: 0px;border-bottom: 1px solid #ccc;padding: 20px 0;">
                                        <input type="text" placeholder="search content" class="bulletChatCont-box-ipt" style="height: 28px;border:1px solid #ccc;padding-left: 5px;outline: none;margin-right: 10px;">
                                        <div class="bulletChatCont-box-btn">search</div>
                                    </div>
                                    <div class="bulletChatCont-allp">
                                        <p class="bbp-item" style="line-height: 35px;">空你几哇</p>
                                    </div>
                                </div>`)
                // 播放状态 - 弹幕
                essentialElements.video.addEventListener("playing", function () {
                    $('.apend-dom-zx').css({ 'animation-play-state': 'running' })
                    videoFlag = true;
                });
                essentialElements.video.addEventListener("pause", function () {
                    $('.apend-dom-zx').css({ 'animation-play-state': 'paused' })
                    videoFlag = false;
                });
                // 创建css
                var style = document.styleSheets[0];
                style.insertRule(`.bulletChatCont-box-none {display:none;}`);
                style.insertRule(`.bullet-chat-items {flex-shrink: 0;cursor: pointer;}`);
                style.insertRule(`#danmaku-submit,#danmaku-switch,.bulletChatCont-box-btn {cursor: pointer;display: inline-block;padding: 3px 5px;border:1px solid #888;background: #eee;border-radius: 5px;}`);
                style.insertRule(`.bullet-chat-tips::before {content: '';width: 0;height: 0px;border: 5px solid transparent;border-bottom: 5px solid rgba(0, 0, 0, .5);position: absolute;top: -10px;left: 50%;transform: translateX(-50%);}`);
                style.insertRule(`.bullet-chat-tips::after {content: '';width: 100%;height: 20px;position: absolute;top: -18px;left: 0;}`);
                style.insertRule(`.bullet-chat-selss {display: flex;justify-content: space-between;}`);
                style.insertRule(`.bullet-chat-tips {width: 180px;padding: 5px 10px;font-size: 16px;background: rgba(0, 0, 0, .5);color: #fff;position: absolute;top: 48px;left: 50%;transform: translateX(-50%);border-radius: 8px;opacity: 0;transition: all .3s;}`);
                style.insertRule(`@keyframes mymove{from{transform:translateX(${$('#primaryScreen').width() + 100}px) }to{transform:translateX(-400px)}}`);//写入样式
                clearTimeout(timer);
            }, 2000);
        }()


        !function () {
            // 移入&&移出
            $('#primaryScreen').on('mouseover', '.apend-dom-zx', function () {
                let id = $(this).data('id');
                $(this).css({ 'animation-play-state': 'paused' });
                $(this).find('.bullet-chat-tips').css({ 'opacity': '1', 'top': '35px' })
            })
            $('#primaryScreen').on('mouseout', '.apend-dom-zx', function () {
                if (videoFlag) {
                    $(this).css({ 'animation-play-state': 'running' })
                } else {
                    $(this).css({ 'animation-play-state': 'paused' })
                }
                $(this).find('.bullet-chat-tips').css({ 'opacity': '0', 'top': '55px' })
            })

            //复制
            $('#primaryScreen').on('click', '.bullet-chat-items-copy', function () {
                copyText($(this).parents('.bullet-chat-tips').siblings('.bullet-chat-text').text())
            })
            // 转发 
            $('#primaryScreen').on('click', '.bullet-chat-items-forward', function () {
                copyText(window.location.href, function () {
                    alert('链接已复制到粘贴板!')
                });
            })
            // 点赞  
            $('#primaryScreen').on('click', '.bullet-chat-items-fabulous', function () {
                if ($(this).hasClass('color-red')) {
                    $(this).removeClass('color-red').css({ 'color': '#fff' });
                } else {
                    $(this).addClass('color-red').css({ 'color': 'red' });
                }
            })
            // 回复 
            $('#primaryScreen').on('click', '.bullet-chat-items-reply', function () {
                $('#danmaku-content').val(`${$(this).parents('.bullet-chat-tips').siblings('.bullet-chat-text').text()} 回复:`)
                $('#danmaku-content').css({ 'border': '1px solid red' })
            })
            //查询
            $('#eventTabControl').on('click', '#bulletChatCont', function () {
                if ($(this).hasClass('actvxeee')) {
                    $('.bulletChatCont-box').addClass('bulletChatCont-box-none')
                    $(this).removeClass('actvxeee')
                } else {
                    $('.bulletChatCont-box').removeClass('bulletChatCont-box-none')
                    $(this).addClass('actvxeee')
                }
            })
            $(document).on('click', '.bulletChatCont-box-btn', function () {
                let t = $('.bulletChatCont-box-ipt').val().trim();
                !t && (() => {
                    if (danmakuList.length) {
                        let html = '';
                        for (let i in danmakuList) {
                            html += `<p class="bbp-item" style="line-height: 35px;">${danmakuList[i].value}</p>`
                        }
                        $('.bulletChatCont-allp').html(html)
                    }
                })();
                t && (() => {
                    let arr = window.danmakuList.filter((v, i) => {
                        let x;
                        if (v.value.indexOf(t) > -1) {
                            x = v;
                        }
                        return x
                    })
                    arr.length && (() => {
                        let html = '';
                        for (let i in arr) {
                            html += `<p class="bbp-item" style="line-height: 35px;">${arr[i].value}</p>`
                        }
                        $('.bulletChatCont-allp').html(html)
                    })();
                })();
            })
        }()

        //兼容ios复制
        function copyText(text, callback) {
            const textString = text.toString();
            let input = document.querySelector('#copy-input');
            if (!input) {
                input = document.createElement('input');
                input.id = "copy-input";
                input.readOnly = "readOnly";
                input.style.position = "absolute";
                input.style.left = "-1000px";
                input.style.zIndex = "-1000";
                document.body.appendChild(input)
            }
            input.value = textString;
            selectText(input, 0, textString.length);
            if (document.execCommand('copy')) {
                document.execCommand('copy');
            } else {
                console.log('不兼容');
            }
            input.blur();
            function selectText(textbox, startIndex, stopIndex) {
                if (textbox.createTextRange) {//ie
                    const range = textbox.createTextRange();
                    range.collapse(true);
                    range.moveStart('character', startIndex);
                    range.moveEnd('character', stopIndex - startIndex);
                    range.select();//不兼容苹果
                } else {
                    textbox.setSelectionRange(startIndex, stopIndex);
                    textbox.focus();
                }
            }
            callback && callback()
        }
    };
})($)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值