Chzzk_Live: Partner_Not_Manager Green+BlackNicknameDelete

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

目前為 2025-04-07 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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();
    }
})();