Chzzk_Live: Partner_Not_Manager Green+BlackNicknameDelete

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

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==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();
    }
})();