Greasy Fork

Greasy Fork is available in English.

B站油管showroom简易打尻装置

啊B、油管或showroom打尻,需要用户已登录。若有滥用等问题概不负责,诶嘿。顺便关注一下小东人鱼和noworld吧~

当前为 2022-02-12 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         B站油管showroom简易打尻装置
// @namespace    http://tampermonkey.net/
// @version      0.5.1
// @description  啊B、油管或showroom打尻,需要用户已登录。若有滥用等问题概不负责,诶嘿。顺便关注一下小东人鱼和noworld吧~
// @author       太陽闇の力
// @include      /https?:\/\/live\.bilibili\.com\/(blanc\/)?\d+\??.*/
// @match        https://www.youtube.com/live_chat*
// @exclude      https://www.youtube.com/live_chat_replay*
// @match        https://www.showroom-live.com/*
// @exclude      https://www.showroom-live.com/room/*
// @grant        none
// @license MIT
// ==/UserScript==
 
//1.界面参考自小东人鱼午安社五更耗纸 https://github.com/gokoururi-git/gachihelper/
 
//2.搜索找到代码中let countdown = "220"; let intervaltime = "6";这两句可以改开局的倒计时时间和发送间隔时间(油管和showroom的发送间隔在let intervaltime = "6";下面的代码中进行修改)。
//3.interval.min、interval.max、interval.step分别是滑动条的最小值、最大值和滑动间隔,已根据平台区别设定了这三个值和interval的关系,尽量避免发送太猛吓到主播。
//4.B站直播五秒内同一句打call的话,会显示发送频率太快而无法发送成功。建议写多几句不一样的。
 
//6.showroom的50 count中,搜索找到下面这两行代码可以更改设置
//const kankaku = 2; //50 count的时间间隔 。网络不好的时候不宜进行50 count,会自动停止
//countDownButton.innerText = kankaku*(50-1)+1;//50 count所用总时间。这个值是我乱猜的,不过也有实验过姑且能用的样子
 
(function() {
    let waitTime = 1;//等待1秒,如果加载比较慢的话,不等待可能获取不到元素。
    let times = 10;//尝试查询的次数
 
    let timescopy = times;
    let maint;
    let isOnLive;//showroom是否在直播
    const roomID = /\d+/.exec(location.pathname)[0];
    const main = () => {
        try {
            //-----------配置区-------------
            //0默认收起,1默认展开
            let isunfold = 0;
            let unfold = ["展开","收起"];
            //输入框选择符
            let inputSelector = 'textarea';
            //发送按钮选择符
            let sendSelector = '.bl-button';
            const urlCheck = (s)=>window.location.host == s;
            const isShowroom = urlCheck("www.showroom-live.com");
            const isBilibili = urlCheck("live.bilibili.com");
            const isYoutube = urlCheck("www.youtube.com");
            let countdown = "220"; //倒计时
            let intervaltime = "6";//发送间隔
            let biliTextArea;
            let biliTextSender;
            if(isYoutube){//如果在油管的话设置初始发送间隔时间为20秒
                intervaltime="20";
            }
            if(isShowroom){//判断是不是showroom的直播间
                intervaltime="50";//如果在showroom的话设置初始发送间隔时间为20秒
 
                const showroomURL = "https://www.showroom-live.com";
                let ogURL = window.document.querySelector("meta[property='og:url']");
                ogURL = ogURL?.content;
                if(ogURL==showroomURL) {
                    clearInterval(maint);
                    return;
                }
                const liveURL = "https://www.showroom-live.com/api/live/live_info?room_id="+roomID;
                const req = new XMLHttpRequest();
                let live_status;
                req.onload = function(){
                    if(req.status == 200){
                        live_status = JSON.parse(req.responseText).live_status;
                        isOnLive = live_status == 2;
                    }
                }
                req.open("GET",liveURL,false);
                req.send(null);
                if(!isOnLive) {
                    clearInterval(maint);
                    return;
                }
                //免费礼物点一下就能十连发
                const comboInterval=25;
                const list = window.document.querySelector("#room-gift-item-list");
                const gift = list.childNodes;
                for(let i = 0;i<5;i++){
                    gift[i].addEventListener('mousedown',(e)=>{
                        if(e.which ==1){//左键点下
                            const num = e.target.parentNode.parentNode.querySelector("div").innerText.split(" ")[1]-1;
                            const comboNum = num > 9 ? 9 : num;
                            for(let i = 1;i<=comboNum;i++){
                                setTimeout(()=>{e.target.click();},i*comboInterval)
                            }
                        }
                    })
                }
 
                //评论栏和发送按钮
                inputSelector ='.comment-input-text';
                sendSelector = '.js-room-comment-btn';
            }
            //iframe,生日直播间之类的会成嵌套框架的结构,那个时候只看框架代码
            if(isBilibili&&!(window.document.firstChild instanceof window.Comment)){//「あなたに逢えなくなって、錆びた時計と泣いたけど…」
                clearInterval(maint);
                return;
            }
            clearInterval(maint);
 
            const callDealler = (call) => {
                let tempcallResult = [];
                call = call.trim();
                call = call.replace(/ /g, '');
                call = call.replace(/ /g, '');
                call = call.replace(/\n{2,}/g, '\n');
                tempcallResult = call.split('\n');
                return tempcallResult;
            }
            let callResult = [];
            let currIndex = 0;
            let t = null;
            let ct = null;
            const inputEvent = document.createEvent("Event");
            inputEvent.initEvent("input",true, true);
            const send = function(){
                if(isYoutube){
                    biliTextArea.innerText = callResult[currIndex++];
                }else{
                    biliTextArea.value = callResult[currIndex++];
                }
                biliTextArea.dispatchEvent(inputEvent);
                biliTextSender.click();
            }
            const next = function() {
                if(isShowroom&&!biliTextSender.classList.contains('is-disabled')){
                    biliTextArea.value = "";
                    pause();
                    return;
                }
                currIndex %= callResult.length;
                send();
            }
            const init = function() {
                biliTextArea = window.document.querySelector(inputSelector);
                biliTextSender = window.document.querySelector(sendSelector);
                if(isYoutube){
                    biliTextArea = window.document.querySelector("#input").querySelector("#input");
                    biliTextSender = window.document.querySelector("#send-button").querySelector("#button");
                }
                currIndex = 0;
                send();
                const intervalChoose = intervalValBox&&parseFloat(intervalValBox.value) > 0 ? intervalValBox.value : interval.value;
                timeLabel.innerText = intervalChoose;
                t = setInterval(next, intervalChoose * 1000);
            }
            // ------------------GUI设计开始---------------
            // 总容器
            const container = window.document.createElement('div');
            container.style.cssText = 'width:260px;position:fixed;bottom:5px;left:5px;z-index:999;box-sizing:border-box;';
 
            // 工具名称
            const topTool = window.document.createElement('div');
            topTool.innerText = 'call';
            topTool.style.cssText = 'text-align:center;line-height:20px;height:20px;width:100%;color:rgb(210,143,166);font-size:14px;';
 
            // 最小化按钮
            const collapseButton = window.document.createElement('button');
            collapseButton.innerText = unfold[isunfold];
            collapseButton.style.cssText = 'float:right;width:40px;height:20px;border:none;cursor:pointer;background-color:#1890ff;border-radius:1px;color:#ffffff;';
 
            // 主窗口
            const mainWindow = window.document.createElement('div');
            mainWindow.style.cssText = 'width:100%;background-color:rgba(220, 192, 221, .5);padding:10px;box-sizing:border-box;';
            if(isunfold==0){
                mainWindow.style.display = "none";
            }
            // call框
            const textArea = window.document.createElement('textarea');
            textArea.style.cssText = 'width:100%;height:50px;resize:none;outline:none;background-color:rgba(255,255,255,.5);border-radius:2px';
 
            // 按钮区容器
            const buttonArea = window.document.createElement('div');
            buttonArea.style.cssText = 'width:100%;height:30px;box-sizing:border-box;display:flex; justify-content: center;';
 
            // 按钮区容器2
            const buttonArea2 = window.document.createElement('div');
            buttonArea2.style.cssText = 'width:100%;height:30px;box-sizing:border-box;display:flex;justify-content: space-around;';
 
            // 开始按钮
            const goButton = window.document.createElement('button');
            goButton.innerText = '开始';
            goButton.style.cssText = 'width:max-content;height:28px;padding:0 5px;margin-left:5px;';
 
            // 发送间隔提示文本
            const intervalLabel = window.document.createElement('div');
            intervalLabel.innerText = '发送间隔:'
            intervalLabel.style.cssText = 'width:70px;height:28px;line-height:28px;';
 
            // 选择延迟
            const interval = window.document.createElement('input');
            interval.type = "range";
            interval.step = "0.1";
            interval.min = (intervaltime-2)/2;
            interval.value = intervaltime;
            interval.max = (+intervaltime+14)*1.5;
            interval.style.cssText = 'width:max-content;padding:0 5px;height:28px;margin-left:5px;';
 
            const timeLabel = window.document.createElement('div');
            timeLabel.innerText = intervaltime;
            timeLabel.style.cssText = 'width:24px;height:28px;line-height:28px;';
 
            const secondLabel = window.document.createElement('div');
            secondLabel.innerText = '秒';
            secondLabel.style.cssText = 'width:max-content;height:28px;line-height:28px;';
 
            // 倒计时
            const countDownButton = window.document.createElement('button');
            countDownButton.setAttribute("contenteditable", "true");
            countDownButton.innerText = countdown;
            countDownButton.style.cssText = 'width:50px;height:28px;margin-left:5px;padding:0 5px;';
 
            // 组装
            topTool.appendChild(collapseButton);
            container.appendChild(topTool);
 
            mainWindow.appendChild(textArea);
 
            buttonArea.appendChild(intervalLabel);
            buttonArea.appendChild(interval);
            buttonArea.appendChild(timeLabel);
            buttonArea.appendChild(secondLabel);
            buttonArea2.appendChild(goButton);
            buttonArea2.appendChild(countDownButton);
            mainWindow.appendChild(buttonArea);
            mainWindow.appendChild(buttonArea2);
            container.appendChild(mainWindow);
            window.document.body.appendChild(container);
            // 显示逻辑控制
            collapseButton.addEventListener('click', () => {
                if (collapseButton.innerText === '收起') {
                    mainWindow.style.display = 'none';
                    collapseButton.innerText = '展开';
                    return;
                }
                if (collapseButton.innerText === '展开') {
                    mainWindow.style.display = 'block';
                    collapseButton.innerText = '收起';
                    return;
                }
            }, false);
            //显示滑动条数字
            interval.oninput = function() {
                timeLabel.innerText = interval.value;
            }
 
            if(isShowroom){
                container.style.width = "282px";
                timeLabel.style.width = "32px";
            }
            if(isBilibili){
                //填充上次所写的打call语句
                const tsc = localStorage.getItem('tampermonkey_script_call');
                if(tsc){
                    const tscJson = JSON.parse(tsc);
                    textArea.value = tscJson[roomID]||``;
                }else{
                    localStorage.setItem('tampermonkey_script_call',JSON.stringify({}));
                }
 
            }
            //-------------------gui设计结束------------------
            let intervalValBox ;
            function createInput(){
                intervalLabel.innerText = "";
                intervalValBox = document.createElement('input');
                intervalValBox.style.width = "100%";
                intervalValBox.placeholder = "输入数值";
                intervalLabel.appendChild(intervalValBox);
                intervalLabel.onclick = null;
            }
            intervalLabel.onclick =createInput;
            function pause(){
                clearInterval(t);
                clearInterval(ct);
                goButton.innerText = '开始';
                countDownButton.innerText = countDownButton.innerText==0?countdown:220;
                countDownButton.setAttribute("contenteditable", "true");
                if(isShowroom&&textArea.value.trim() === ''){
                    //showroom中如果输入为空,则进行50 count。
                    interval.min = (intervaltime-2)/2;
                    interval.value = intervaltime;
                    timeLabel.innerText = intervaltime;
                }
            }
            const countdownfunc = function() {
                if (countDownButton.innerText > 0) {
                    countDownButton.innerText -= 1;
                } else {
                    pause();
                }
 
            }
            goButton.addEventListener('click', () => {
                if (goButton.innerText == '暂停') {
                    pause()
                    return;
                }
                if(intervalValBox){
                    intervalValBox.remove();
                    intervalLabel.innerText = "发送间隔:";
                    intervalLabel.onclick = createInput;
                }
                const value = textArea.value;
                callResult = callDealler(value);
                if (value.trim() === '') {
                    if(!isShowroom){
                        window.alert('打尻:您还没有输入call语句');
                        return;
                    }else{
                        //设定50 count
                        const kankaku = 2; //50 count的时间间隔
                        countDownButton.innerText = kankaku*(50-1)+1;//这个值是我乱猜的
                        interval.min = kankaku;
                        interval.value = kankaku;
                        timeLabel.innerText = kankaku;
                        callResult = Array.from({length:50}, (v,k) => k+1);
                    }
                }
                if(isBilibili){
                    const tsc_temp = localStorage.getItem('tampermonkey_script_call');
                    const tscJson_temp = JSON.parse(tsc_temp);
                    tscJson_temp[roomID] = textArea.value;
                    localStorage.setItem('tampermonkey_script_call',JSON.stringify(tscJson_temp));
                }
                ct = setInterval(countdownfunc, 1000);
                goButton.innerText = '暂停';
                countDownButton.setAttribute("contenteditable", "false");
                if (!isNaN(parseFloat(countDownButton.innerText))&&!(isShowroom&&textArea.value.trim() === '')) {
                    countdown = countDownButton.innerText;
                }
                init();
            }, false);
        } catch (e) {
            times-=1;
            if(times==0){
                times = timescopy;
                clearInterval(maint);
                if(window.confirm('打尻:发生未知错误\n可能是在加载中无法获取元素\n' + e+"\n是否重新尝试打尻?")){
                    maint= setInterval(main, 1000 * waitTime);
                }
            };
        }
    }
    maint= setInterval(main, 1000 * waitTime);
})();