bilibili-live-random-send

定时从设置的字幕中随机取出一条在B站直播间发送,需先登录(不可用)B站账号

目前为 2022-07-16 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/447937/1070634/bilibili-live-random-send.js

// ==UserScript==
// @name            bilibili-live-random-send
// @version         1.2.3
// @description     定时从设置的字幕中随机取出一条在B站直播间发送,需先登录(不可用)B站账号
// @author          Gamyou
// @include         /https?:\/\/live\.bilibili\.com\/[blanc\/]?[^?]*?\d+\??.*/
// @icon            https://www.bilibili.com/favicon.ico
// @grant           none
// @run-at          document-end
// @license         Apache License, Version 2.0
// @note            22-07-16 1.2.3 修复设置弹幕时旧(初始)数据没有清空的BUG
// @note            22-06-24 1.2.2 优化部分代码
// @note            22-06-20 1.2.1 修复定时停止不能再开始的BUG
// @note            22-06-19 1.2.0 添加弹幕设置功能
// ==/UserScript==


(function () {
    'use strict';
 
    let data1 = ['绿豆','红豆','黄豆','蓝猫'];
    let data2 = ['红','接天莲叶无穷碧,映日荷花别样红。'];
    let data3 = ['黄','儿童急走追黄蝶,飞入菜花无处寻。'];
    let data4 = ['蓝','沧海月明珠有泪,蓝田日暖玉生烟。'];
    let data5 = ['绿','知否,知否?应是绿肥红瘦。'];
 
    let timer = null; // 定时器
    let data, waiters = [];
    let default_timeout = 600; // 超时时间,默认10分钟
    let count = 0, lastSent = 0, arrayIndex = 0, isRandom = true, waitCount = 10, signInContent = '签到';
    let dmButtonSend, dmInput, divSetting, dataText1, dataText2, dataText3, dataText4, dataText5, spanApplyTip, rdCheckbox;
    
    initCss();
    window.addEventListener("load", () => {
        waiters[waiters.length] = setInterval(pageFullyLoaded, 1500);
        initData();
        window.arrayInfo = arrayInfo;
        signIn();
    });
 
    function openSetting() {
        divSetting.style.display = 'block';
    }
 
    function closeSetting() {
        rdCheckbox.checked = isRandom;
        divSetting.style.display = 'none';
    }
 
    function applySetting() {
        data1 = isNull(dataText1.value) ? [] : dataText1.value.split('|');
        data2 = isNull(dataText2.value) ? [] : dataText2.value.split('|');
        data3 = isNull(dataText3.value) ? [] : dataText3.value.split('|');
        data4 = isNull(dataText4.value) ? [] : dataText4.value.split('|');
        data5 = isNull(dataText5.value) ? [] : dataText5.value.split('|');
        initData();
        isRandom = rdCheckbox.checked;
        spanApplyTip.style.display = 'block';
        setTimeout(() => {
            spanApplyTip.style.display = 'none';
        }, 1500);
    }
 
    function initData() {
        data = [];   
        data = data.concat(data1).concat(data2).concat(data3).concat(data4).concat(data5);
        !rdCheckbox || rdCheckbox.checked ? data = randomSort(data) : arrayIndex = 0;
    }
 
    function offOrOn() {
        let timeout = 0;
        if (timer) {
            console.log('=================> ' + new Date().toLocaleString() + ' 停止发送弹幕');
            clearInterval(timer);
            timer = null;
            console.log('=================> ' + new Date().toLocaleString() + ' 停止成功!!');
            dmButtonSend.style.background = 'rgba(217,157,27,1)';
            dmButtonSend.textContent = '开始';
            dmInput.removeAttribute("disabled");
        } else {
            timeout = isNull(dmInput.value) ? default_timeout * 1000 : dmInput.value * 1000;
            danmu();
            console.log('=================> ' + new Date().toLocaleString() + ' 开启定时器');
            timer = setInterval(danmu, timeout);
            console.log('=================> ' + new Date().toLocaleString() + ' 开启成功!!');
            dmButtonSend.style.background = '#ff0000';
            dmButtonSend.textContent = '停止';
            dmInput.setAttribute('disabled', 'disabled');
        }
    }
 
    function danmu() {
        if (!data || data.length < 1) {
            alert('请任意在一个分组里输入一条弹幕');
            return;
        }
        if (isRandom) {
            arrayIndex = Math.floor((Math.random() * data.length));
        }
        
        send(data[arrayIndex], arrayIndex);
        ++arrayIndex;
        if (arrayIndex >= data.length)
            arrayIndex = 0;
    }
 
    function signIn() {
        let timestamp = new Date(new Date(new Date().setDate(new Date().getDate() + 1)).toDateString()).getTime() - getCurrentTimestamp();
        console.log('=================> 设置第二天凌晨签到定时器【' + timestamp + '】');
        setTimeout(() => {
            send(signInContent, 0);
            console.log('++++++++++++++++++++++> 完成签到发送,进入下一轮递归签到发送 <++++++++++++++++++++++');
            signIn();
        }, timestamp);
    }
 
    function send(msg, index) {
        let dmTextArea = document.getElementById('aside-area-vm').getElementsByClassName('chat-input border-box')[0];
        if (!dmTextArea) {
            alert('找不到输入弹幕文本框,请尝试刷新页面');
            return;
        }
 
        let btnSend = document.getElementsByClassName('bl-button live-skin-highlight-button-bg live-skin-button-text bl-button--primary bl-button--small')[0];
        if (!btnSend) {
            alert('找不到发送按钮,请尝试刷新页面');
            return;
        }
        
        dmTextArea.value = msg;
        // 定义事件, 定义才可发送
        dmTextArea.dispatchEvent(new Event('input', { "bubbles": true, "cancelable": true }));
        btnSend.click();
        lastSent = getCurrentTimestamp();
        ++count;
        console.log('=================> ' + new Date().toLocaleString() + ' 弹幕发送成功 ' + count + ' 次,第【' + index + '】条数据 === ' + msg);
    }
 
    function isNull(str) {
        if (!str || str == "") {
            return true;
        }
 
        let regu = "^[ ]+$";
        let re = new RegExp(regu);
        return re.test(str);
    }
 
    function randomSort(arr) {
        for (let i = 0; i < arr.length; i++) {
            const rdIndex = Math.floor(Math.random() * arr.length)
            const temp = arr[i]
            arr[i] = arr[rdIndex]
            arr[rdIndex] = temp
        }
 
        return arr
    }
 
    function getCurrentTimestamp() {
        return new Date().getTime();
    }
 
    function clearWaiters() {
        for (let i = 0; i < waiters.length; i++) {
            clearInterval(waiters[i]);
            waiters[i] = null;
        }
 
        waiters = [];
    }
 
    function arrayInfo() {
        console.info(data);
    }
 
    function selectRandom() {}
 
    function initCss() {
        let linkElement = document.createElement('link');
        linkElement.rel = 'stylesheet';
        linkElement.href = 'https://unpkg.com/[email protected]/lib/theme-chalk/index.css';
        document.head.appendChild(linkElement);
 
        // 图标库 https://ionic.io/ionicons
        // let scriptElement = document.createElement('script');
        // scriptElement.src = 'https://unpkg.com/[email protected]/dist/ionicons.js';
        // document.head.appendChild(scriptElement);
 
        let customerStyle = document.createElement('style');
        customerStyle.setAttribute('type', 'text/css');
        customerStyle.innerHTML = '.el-button{display:inline-block;line-height:1;white-space:nowrap;cursor:pointer;background:#FFF;border:1px solid #DCDFE6;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:.1s;transition:.1s;font-weight:500;padding:12px 20px;font-size:14px;border-radius:4px}.el-button.is-circle{border-radius:50%;padding:12px}.el-button--mini.is-circle{padding:3px;}.el-button:focus,.el-button:hover{color:#409EFF;border-color:#c6e2ff;background-color:#ecf5ff}.el-icon-close.is-circle{padding:5px;color:#ff0000;border:1px solid #ff0000;margin-left:20px;}.el-icon-check.is-circle{padding:5px;color:#0000ff;border:1px solid #0000ff;margin-left:20px;}.random-check{display:inline-block;}.random-check label{display:inline-block;vertical-align:middle;border:1px solid #bdc3c7;border-radius:60px;width:40px;height:18px;position:relative;transition:all .3s;}.random-check input{display:none;}.random-check label:before{width:14px;height:14px;content:"";display:inline-block;background-color:#bdc3c7;border-radius:100%;position:absolute;top:2px;left:4px;transition:all .3s;}.random-check :checked ~ label{background-color:#26b22b;border-color:#26b22b;}.random-check :checked ~ label:before{left:22px;background-color:#fff;}';
        document.head.appendChild(customerStyle);
    }
 
    function pageFullyLoaded() {
        let divButton = document.getElementsByClassName('bottom-actions p-relative')[0];
        if (!divButton) {
            console.error('没能找到发送按钮上层的div');
            --waitCount;
            if (0 >= waitCount) {
                clearWaiters();
            }
            return;
        }
        clearWaiters();
 
        let divSettingTitle = document.createElement('div');
        divSettingTitle.textContent = '弹幕设置';
        divSettingTitle.style.textAlign = 'center';
        divSettingTitle.style.fontSize = '16px';
        divSettingTitle.style.fontWeight = '700';
        divSettingTitle.style.color = '#1c5adc';
        divSettingTitle.style.margin = '4px 0px 8px 0';
 
        let divText1 = document.createElement('div');
        divText1.textContent = '分组 1 :'
        divText1.style.fontSize = '14px';
        divText1.style.paddingLeft = '2px';
        divText1.style.color = '#12388d';
        divText1.style.display = 'inline';
 
        let divTip = document.createElement('div');
        divTip.style.color = '#0b81cc';
        divTip.style.marginLeft = '5px';
        divTip.style.fontStyle = 'italic';
        divTip.style.display = 'inline';
        divTip.innerHTML = '任一分组内输入弹幕即可,多条用<span style="color:#dc6b07;margin:0 2px 0 4px;font-weight:700;font-style:normal;">竖线</span>分隔';
 
        dataText1 = document.createElement('textarea');
        dataText1.style.width = '98%';
        dataText1.style.height = '100px';
        dataText1.style.margin = '1px 0 4px 0';
        dataText1.style.border = '0';
        dataText1.style.resize = 'none';
        dataText1.setAttribute('placeholder', '请输入弹幕,多条弹幕请用“|”分隔');
 
        let divText2 = document.createElement('div');
        divText2.textContent = '分组 2 :'
        divText2.style.fontSize = '14px';
        divText2.style.paddingLeft = '2px';
        divText2.style.color = '#12388d';
 
        dataText2 = document.createElement('textarea');
        dataText2.style.width = '98%';
        dataText2.style.height = '100px';
        dataText2.style.margin = '1px 0 4px 0';
        dataText2.style.border = '0';
        dataText2.style.resize = 'none';
        dataText2.setAttribute('placeholder', '请输入弹幕,多条弹幕请用“|”分隔');
 
        let divText3 = document.createElement('div');
        divText3.textContent = '分组 3 :'
        divText3.style.fontSize = '14px';
        divText3.style.paddingLeft = '2px';
        divText3.style.color = '#12388d';
 
        dataText3 = document.createElement('textarea');
        dataText3.style.width = '98%';
        dataText3.style.height = '100px';
        dataText3.style.margin = '1px 0 4px 0';
        dataText3.style.border = '0';
        dataText3.style.resize = 'none';
        dataText3.setAttribute('placeholder', '请输入弹幕,多条弹幕请用“|”分隔');
 
        let divText4 = document.createElement('div');
        divText4.textContent = '分组 4 :'
        divText4.style.fontSize = '14px';
        divText4.style.paddingLeft = '2px';
        divText4.style.color = '#12388d';
 
        dataText4 = document.createElement('textarea');
        dataText4.style.width = '98%';
        dataText4.style.height = '100px';
        dataText4.style.margin = '1px 0 4px 0';
        dataText4.style.border = '0';
        dataText4.style.resize = 'none';
        dataText4.setAttribute('placeholder', '请输入弹幕,多条弹幕请用“|”分隔');
 
        let divText5 = document.createElement('div');
        divText5.textContent = '分组 5 :'
        divText5.style.fontSize = '14px';
        divText5.style.paddingLeft = '2px';
        divText5.style.color = '#12388d';
 
        dataText5 = document.createElement('textarea');
        dataText5.style.width = '98%';
        dataText5.style.height = '100px';
        dataText5.style.margin = '1px 0 4px 0';
        dataText5.style.border = '0';
        dataText5.style.resize = 'none';
        dataText5.setAttribute('placeholder', '请输入弹幕,多条弹幕请用“|”分隔');
 
        let descCheckbox = document.createElement('span');
        descCheckbox.textContent = '随机';
        descCheckbox.title = '将合并所有分组数据,从中随机选出一条发送';
        descCheckbox.style.fontSize = '16px';
        descCheckbox.style.verticalAlign = 'middle';
        descCheckbox.style.marginRight = '4px';
        descCheckbox.style.color = '#095ca2';
 
        rdCheckbox = document.createElement('input');
        rdCheckbox.type = 'checkbox';
        rdCheckbox.id = 'rdmCheckbox';
        rdCheckbox.checked = isRandom;
        rdCheckbox.addEventListener('click', selectRandom);
 
        let lblCheckbox = document.createElement('label');
        lblCheckbox.setAttribute('for', 'rdmCheckbox');
 
        let divCheckbox = document.createElement('div');
        divCheckbox.classList.add('random-check');
        divCheckbox.style.marginLeft = '10px';
        divCheckbox.appendChild(descCheckbox);
        divCheckbox.appendChild(rdCheckbox);
        divCheckbox.appendChild(lblCheckbox);
 
        spanApplyTip = document.createElement('span');
        spanApplyTip.textContent = '设置成功'
        spanApplyTip.style.fontSize = '16px';
        spanApplyTip.style.color = '#128712';
        spanApplyTip.style.display = 'none';
 
        let divApplyTip = document.createElement('div');
        divApplyTip.style.textAlign = 'center';
        divApplyTip.style.display = 'inline-block';
        divApplyTip.style.verticalAlign = 'middle';
        divApplyTip.style.width = '34%';
        divApplyTip.appendChild(spanApplyTip);
 
        let btnApplySetting = document.createElement('i');
        btnApplySetting.setAttribute('title', '应用');
        btnApplySetting.classList.add('el-button');
        btnApplySetting.classList.add('el-icon-check');
        btnApplySetting.classList.add('is-circle');
        btnApplySetting.addEventListener('click', applySetting);
 
        let btnCloseSetting = document.createElement('i');
        btnCloseSetting.setAttribute('title', '关闭');
        btnCloseSetting.classList.add('el-button');
        btnCloseSetting.classList.add('el-icon-close');
        btnCloseSetting.classList.add('is-circle');
        btnCloseSetting.addEventListener('click', closeSetting);
 
        let divSettingButton = document.createElement('div');
        divSettingButton.style.display = 'inline-block';
        divSettingButton.style.verticalAlign = 'middle';
        divSettingButton.appendChild(btnApplySetting);
        divSettingButton.appendChild(btnCloseSetting);
 
        let divBottomContainer = document.createElement('div');
        divBottomContainer.style.width = '100%';
        divBottomContainer.style.height = '25px';
        divBottomContainer.style.margin = '4px 0 8px 0';
        // divBottomContainer.style.position = 'absolute';
        // divBottomContainer.style.bottom = '0';
        divBottomContainer.appendChild(divCheckbox);
        divBottomContainer.appendChild(divApplyTip);
        divBottomContainer.appendChild(divSettingButton);
 
        divSetting = document.createElement('div');
        divSetting.style.backgroundColor = '#d4f2e0';
        divSetting.style.borderRadius = '2px';
        divSetting.style.width = '100%';
        divSetting.style.height = '100%';
        divSetting.style.overflowY = 'auto';
        divSetting.style.position = 'absolute';
        divSetting.style.left = '0';
        divSetting.style.top = '0';
        divSetting.style.zIndex = '999';
        divSetting.style.display = 'none';
        divSetting.appendChild(divSettingTitle)
        divSetting.appendChild(divText1);
        divSetting.appendChild(divTip);
        divSetting.appendChild(dataText1);
        divSetting.appendChild(divText2);
        divSetting.appendChild(dataText2);
        divSetting.appendChild(divText3);
        divSetting.appendChild(dataText3);
        divSetting.appendChild(divText4);
        divSetting.appendChild(dataText4);
        divSetting.appendChild(divText5);
        divSetting.appendChild(dataText5);
        divSetting.appendChild(divBottomContainer);
 
        let asideAreaVm = document.getElementById('aside-area-vm');
        asideAreaVm.appendChild(divSetting);
 
        dmButtonSend = document.createElement('button');
        dmButtonSend.textContent = '开始';
        dmButtonSend.style.minWidth = '65px';
        dmButtonSend.style.height = '24px';
        dmButtonSend.style.fontSize = '12px';
        dmButtonSend.style.borderRadius = '4px';
        dmButtonSend.style.color = '#ffffff';
        dmButtonSend.style.background = 'rgba(217,157,27,1)';
        dmButtonSend.style.border = '0';
        dmButtonSend.style.cursor = 'pointer';
        //dmButtonSend.onclick = function() { alert('Hello world');}
        dmButtonSend.addEventListener('click', offOrOn);
 
        let beforeSpan = document.createElement('span');
        beforeSpan.textContent = '每';
        beforeSpan.style.color = '#ffffff';
        beforeSpan.style.fontSize = '12px';
        beforeSpan.style.marginLeft = '4px';
        beforeSpan.style.backgroundColor = '#ec6c1b';
 
        dmInput = document.createElement('input');
        dmInput.value = default_timeout;
        dmInput.style.width = '25px';
        dmInput.style.height = '15px';
        dmInput.style.margin = '0 3px';
        dmInput.style.border = '0';
        dmInput.style.borderRadius = '3px';
        dmInput.setAttribute('oninput', "this.value = this.value.replace(/[^0-9]/g, '')");
 
        let afterSpan = document.createElement('span');
        afterSpan.textContent = '秒发送';
        afterSpan.style.color = '#ffffff';
        afterSpan.style.fontSize = '12px';
        afterSpan.style.backgroundColor = '#ec6c1b';
        afterSpan.style.marginRight = '4px';
 
        let iElement = document.createElement('i');
        iElement.classList.add('el-icon-setting');
 
        let btnSetting = document.createElement('button');
        btnSetting.title = '设置';
        btnSetting.classList.add('el-button');
        btnSetting.classList.add('el-button--mini');
        btnSetting.classList.add('is-circle');
        btnSetting.addEventListener('click', openSetting);
        btnSetting.appendChild(iElement);
 
        // let btnSetting = document.createElement('ion-icon');
        // btnSetting.setAttribute('name', 'settings-sharp');
        // btnSetting.classList.add('el-button');
        // btnSetting.classList.add('el-button--mini');
        // btnSetting.classList.add('is-circle');
        // btnSetting.addEventListener('click', openSetting);
 
        let div = document.createElement('div');
        div.style.position = 'absolute';
        div.appendChild(dmButtonSend);
        div.appendChild(beforeSpan);
        div.appendChild(dmInput);
        div.appendChild(afterSpan);
        div.appendChild(btnSetting);
        divButton.appendChild(div);
    }
})();

QingJ © 2025

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