Greasy Fork

Chzzk_Live: Partner_Not_Manager Green+BlackNicknameDelete

파트너 스트리머이며 매니저가 아닌 채팅의 닉네임과 메시지를 연두색으로 표시. 닉네임이 너무 어두운 경우 색상 제거 (시인성 개선)

当前为 2025-04-07 提交的版本,查看 最新版本

// ==UserScript==
// @name         Chzzk_Live: Partner_Not_Manager Green+BlackNicknameDelete
// @namespace    Chzzk_Live: Partner_Not_Manager Green
// @version      1.1
// @description  파트너 스트리머이며 매니저가 아닌 채팅의 닉네임과 메시지를 연두색으로 표시. 닉네임이 너무 어두운 경우 색상 제거 (시인성 개선)
// @author       DOGJIP
// @match        https://chzzk.naver.com/*
// @grant        none
// @run-at       document-end
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const LIGHT_GREEN = "rgb(102,255,102)";
    let chatObserver = null;

    function cleanNicknameStyle(elem) {
        const computedColor = getComputedStyle(elem).color;
        const rgb = computedColor.match(/\d+/g);
        if (!rgb) return;
        const [r, g, b] = rgb.map(Number);

        const isTooDark = (r < 40 && g < 40 && b < 40);
        const isTransparent = computedColor.includes('rgba') && computedColor.includes(', 0)');
        if (isTooDark || isTransparent) {
            elem.style.removeProperty('color');
        }
    }

    function processChatMessage(messageElem) {
        if (messageElem.getAttribute('data-partner-processed') === 'true') return;

        const isPartner = messageElem.querySelector('[class*="name_icon__zdbVH"]') !== null;

        const badgeImgs = messageElem.querySelectorAll('.badge_container__a64XB img');
        let isManager = false;
        badgeImgs.forEach(img => {
            if (img.src.includes("manager.png")) {
                isManager = true;
            }
        });

        const nicknameElem = messageElem.querySelector('.live_chatting_username_nickname__dDbbj');
        const textElem = messageElem.querySelector('.live_chatting_message_text__DyleH');

        // 모든 닉네임에 대해 스타일 정리
        if (nicknameElem) {
            cleanNicknameStyle(nicknameElem);
        }

        if (isPartner && !isManager) {
            if (nicknameElem) nicknameElem.style.color = LIGHT_GREEN;
            if (textElem) textElem.style.color = LIGHT_GREEN;
        }

        messageElem.setAttribute('data-partner-processed', 'true');
    }

    function setupChatObserver() {
        if (chatObserver) {
            chatObserver.disconnect();
        }
        const chatContainer = document.querySelector('[class*="live_chatting_list_wrapper__"]');
        if (!chatContainer) {
            setTimeout(setupChatObserver, 500);
            return;
        }
        const existingMessages = chatContainer.querySelectorAll('[class^="live_chatting_message_chatting_message__"]');
        existingMessages.forEach(msg => processChatMessage(msg));

        chatObserver = new MutationObserver(mutations => {
            mutations.forEach(mutation => {
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType === 1) {
                        if (node.className && node.className.indexOf('live_chatting_message_chatting_message__') !== -1) {
                            processChatMessage(node);
                        } else {
                            const msgs = node.querySelectorAll('[class^="live_chatting_message_chatting_message__"]');
                            msgs.forEach(msg => processChatMessage(msg));
                        }
                    }
                });
            });
        });
        chatObserver.observe(chatContainer, { childList: true, subtree: true });
    }

    function setupSPADetection() {
        let lastUrl = location.href;
        function onUrlChange() {
            if (location.href !== lastUrl) {
                lastUrl = location.href;
                setTimeout(setupChatObserver, 1000);
            }
        }
        const origPushState = history.pushState;
        history.pushState = function() {
            origPushState.apply(history, arguments);
            onUrlChange();
        };
        const origReplaceState = history.replaceState;
        history.replaceState = function() {
            origReplaceState.apply(history, arguments);
            onUrlChange();
        };
        window.addEventListener('popstate', onUrlChange);
    }

    function init() {
        setupChatObserver();
        setupSPADetection();
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();