Greasy Fork

获取弹幕_DOM版

在线获取抖音,快手直播间弹幕DOM版本为线上发布版本,因抖音快手直播间可能经常跟新,所以选择在线版本使用DOM获取弹幕,webscket版本抓取弹幕在版本会因为wepack打包跟新变量名而失效,因此只能在本地部署。

目前为 2024-01-18 提交的版本。查看 最新版本

// ==UserScript==
// @name         获取弹幕_DOM版
// @namespace    http://tampermonkey.net/
// @version      2024-01-18
// @description  在线获取抖音,快手直播间弹幕DOM版本为线上发布版本,因抖音快手直播间可能经常跟新,所以选择在线版本使用DOM获取弹幕,webscket版本抓取弹幕在版本会因为wepack打包跟新变量名而失效,因此只能在本地部署。
// @author       37
// @match        https://live.douyin.com/*
// @match        https://live.kuaishou.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant        none
// @license MIT
// ==/UserScript==

(function () {
    'use strict';
    let ws;
    let observer;
    let waitMsgList = [];
    let timeId;
    let stopWs = false;
    function connectWebSocket(wxUrl) {
        ws = new WebSocket(wxUrl);
        ws.addEventListener('open', () => { 
            console.log('连接成功');
            const submitButton = document.querySelector('#submitButton');
            submitButton.textContent = '断开';

            if (waitMsgList.length) {
                waitMsgList.forEach((item) => {
                    ws.send(item);
                    console.log('成功发送缓存---', item);
                });
                waitMsgList = [];
            }
            timeId = setInterval(() => {
                ws.readyState === 1 && ws.send(JSON.stringify({ "type": 2, "answerText": "监测连接" }));
            }, 30000);
            
        });
        ws.addEventListener('message', event => {
            console.log('从服务器接收到消息:', event.data);
        });
        ws.addEventListener('close', (event) => {
            const submitButton = document.querySelector('#submitButton');
            submitButton.textContent = '连接';
            if (stopWs) {
                stopWs = false
            } else {
                setTimeout(() => {
                    console.log('WebSocket 已关闭--正在重新连接');
                    connectWebSocket(wxUrl);
                }, 3000);
            }
            clearInterval(timeId);
        });
    }

    function startObserver() {
        observer = new MutationObserver(mutationsList => {
            mutationsList.forEach(mutation => {
                mutation.addedNodes.forEach(addedNode => {
                    if (window.location.host == 'live.kuaishou.com') {
                        if (addedNode.nodeType === Node.ELEMENT_NODE && addedNode.classList.contains('chat-info')) {
                            const userElement = addedNode.querySelector('.username');
                            const contentElement = addedNode.querySelectorAll('.comment')[1];
                            if (contentElement && contentElement != undefined) {
                                const dataToSend = {
                                    answerText: contentElement.textContent,
                                    type: 1
                                };
                                if (ws && ws.readyState === 1) {
                                    ws.send(JSON.stringify(dataToSend));

                                    console.log('成功发送弹幕---', userElement.textContent, contentElement.textContent);
                                } else {

                                    console.log('储存弹幕一条---', userElement.textContent, contentElement.textContent);
                                    waitMsgList.push(JSON.stringify(dataToSend));
                                }
                            }
                        }
                    } else {
                        if (addedNode.nodeType === Node.ELEMENT_NODE && addedNode.classList.contains('webcast-chatroom___enter')) {
                            const userElement = addedNode.querySelector('.u2QdU6ht');
                            const contentElement = addedNode.querySelector('.webcast-chatroom___content-with-emoji-text');
                            if (contentElement) {
                                const dataToSend = {
                                    answerText: contentElement.textContent,
                                    type: 1
                                };
                                if (ws && ws.readyState === 1) {
                                    ws.send(JSON.stringify(dataToSend));

                                    console.log('成功发送弹幕---', userElement.textContent, contentElement.textContent);
                                } else {

                                    console.log('储存弹幕一条---', userElement.textContent, contentElement.textContent);
                                    waitMsgList.push(JSON.stringify(dataToSend));
                                }
                            }
                        }
                    }

                });
            });
        });
        observer.observe(document.documentElement, { childList: true, subtree: true });
    }

    function stopObserver() {
        if (observer) {
            observer.disconnect();
            observer = null;
        }
    }
    function disconnectWebSocket() {
        if (ws) {
            ws.close();
            stopObserver()
            stopWs = true
            console.log('WebSocket 已手动断开连接');
        }
    }
 
    function createFloatingInput() { 
 
        const inputContainer = document.createElement('div');
        inputContainer.style.position = 'fixed';
        inputContainer.style.top = '20px';
        inputContainer.style.left = '20px';
        inputContainer.style.zIndex = '999999';

        const inputElement = document.createElement('input');
        inputElement.setAttribute('type', 'text');
        inputElement.setAttribute('placeholder', '输入 WebSocket 地址');
        inputElement.classList.add('input-box');
        inputElement.style.padding = '8px';
        inputElement.style.border = '1px solid #ccc';
        inputElement.style.borderRadius = '4px';
        inputElement.style.outline = 'none';

        const submitButton = document.createElement('button');
        submitButton.id = 'submitButton'
        submitButton.textContent = '连接';
        submitButton.style.marginLeft = '8px';
        submitButton.style.padding = '8px';
        submitButton.style.border = '1px solid #ccc';
        submitButton.style.borderRadius = '4px';
        submitButton.style.backgroundColor = '#f0f0f0';
        submitButton.style.cursor = 'pointer';

        submitButton.addEventListener('click', () => {
            const inputVal = inputElement.value.trim();
            if (inputVal) {
                if(ws && ws.readyState == 1){
                    disconnectWebSocket();
                }else{
                    startObserver()
                    connectWebSocket(inputVal);
                }
            }
        });

  

        inputContainer.appendChild(inputElement);
        inputContainer.appendChild(submitButton); 
        document.body.appendChild(inputContainer);

    }

    createFloatingInput();
})();