您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
파트너 스트리머이며 매니저가 아닌 채팅의 닉네임과 메시지를 연두색으로 표시
当前为
// ==UserScript== // @name Chzzk_Live: Partner_Not_Manager Green // @namespace Chzzk_Live: Partner_Not_Manager Green // @version 1.0 // @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; // 채팅 메시지 처리 함수: 파트너 여부(내부에 "name_icon__zdbVH")와 매니저 여부("manager.png")를 체크하여 스타일 적용 function processChatMessage(messageElem) { // 이미 처리된 메시지는 건너뛰기 if (messageElem.getAttribute('data-partner-processed') === 'true') return; // 파트너 여부: "name_icon__zdbVH" 클래스 존재 여부로 판단 const isPartner = messageElem.querySelector('[class*="name_icon__zdbVH"]') !== null; // 매니저 여부: badge_container 내부의 <img> 중 src에 "manager.png"가 포함되어 있는지 확인 const badgeImgs = messageElem.querySelectorAll('.badge_container__a64XB img'); let isManager = false; badgeImgs.forEach(img => { if (img.src.includes("manager.png")) { isManager = true; } }); // 조건: 파트너면서 매니저가 아닌 경우 if (isPartner && !isManager) { const nicknameElem = messageElem.querySelector('.live_chatting_username_nickname__dDbbj'); const textElem = messageElem.querySelector('.live_chatting_message_text__DyleH'); 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(); } // 채팅 리스트 컨테이너 찾기 ([class*="live_chatting_list_wrapper__"]) const chatContainer = document.querySelector('[class*="live_chatting_list_wrapper__"]'); if (!chatContainer) { setTimeout(setupChatObserver, 500); return; } // 기존 채팅 메시지 처리: [class^="live_chatting_message_chatting_message__"] 요소를 기준으로 처리 const existingMessages = chatContainer.querySelectorAll('[class^="live_chatting_message_chatting_message__"]'); existingMessages.forEach(msg => processChatMessage(msg)); // MutationObserver로 새로 추가되는 메시지 감시 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 }); } // SPA 대응: URL 변경 시 채팅 옵저버 재설정 function setupSPADetection() { let lastUrl = location.href; function onUrlChange() { if (location.href !== lastUrl) { lastUrl = location.href; // DOM 로딩 시간을 고려하여 1초 후 옵저버 재설정 setTimeout(setupChatObserver, 1000); } } // pushState, replaceState 후킹 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); } // 초기화: 채팅 옵저버와 SPA 감지 설정 function init() { setupChatObserver(); setupSPADetection(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();