您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
사용자가 입력한 단어를 이미지로 교체하고 크기 설정 가능, 메뉴로 UI 토글, 새로고침 시 데이터 유지
// ==UserScript== // @name 롤캐 채팅 단어 변환 // @version 0.1 // @description 사용자가 입력한 단어를 이미지로 교체하고 크기 설정 가능, 메뉴로 UI 토글, 새로고침 시 데이터 유지 // @match https://insagirl-toto.appspot.com/chatting/lgic/* // @grant GM_addStyle // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @namespace https://greasyfork.org/users/732026 // ==/UserScript== (function() { 'use strict'; // 단어와 이미지 정보 매핑 객체 (초기화 시 localStorage에서 불러옴) let wordToImageMap = GM_getValue('wordToImageMap', {}) || {}; // UI가 열려 있는지 추적하는 변수 let uiDiv = null; // 텍스트를 이미지로 교체하는 함수 function replaceTextWithImage() { const talks = document.querySelectorAll('.talk'); talks.forEach(talk => { let content = talk.textContent; for (const [word, { url, size }] of Object.entries(wordToImageMap)) { if (content.includes(word)) { talk.innerHTML = talk.innerHTML.replace( new RegExp(word, 'g'), `<img src="${url}" alt="${word}" style="width: ${size}px; height: ${size}px; vertical-align: middle;">` ); } } }); } // 데이터를 저장하는 함수 function saveWordToImageMap() { GM_setValue('wordToImageMap', wordToImageMap); } // 리스트 UI 업데이트 함수 function updateListUI(listContainer) { listContainer.innerHTML = ''; // 기존 리스트 초기화 for (const [word, { url, size }] of Object.entries(wordToImageMap)) { const listItem = document.createElement('div'); listItem.style.margin = '5px 0'; listItem.style.display = 'flex'; listItem.style.alignItems = 'center'; listItem.style.padding = '4px'; listItem.style.backgroundColor = '#f9f9f9'; listItem.style.borderRadius = '3px'; const text = document.createElement('span'); text.textContent = `${word} → ${url} (${size}px)`; text.style.flexGrow = '1'; text.style.wordBreak = 'break-all'; text.style.color = '#333'; text.style.fontSize = '12px'; const deleteButton = document.createElement('button'); deleteButton.textContent = '삭제'; deleteButton.style.marginLeft = '5px'; deleteButton.style.padding = '2px 6px'; deleteButton.style.backgroundColor = '#ff4d4d'; deleteButton.style.color = '#fff'; deleteButton.style.border = 'none'; deleteButton.style.borderRadius = '3px'; deleteButton.style.cursor = 'pointer'; deleteButton.style.fontSize = '12px'; deleteButton.style.transition = 'background-color 0.2s'; deleteButton.addEventListener('mouseover', () => deleteButton.style.backgroundColor = '#e63939'); deleteButton.addEventListener('mouseout', () => deleteButton.style.backgroundColor = '#ff4d4d'); deleteButton.addEventListener('click', () => { delete wordToImageMap[word]; // 객체에서 단어 삭제 saveWordToImageMap(); // 삭제 후 저장 updateListUI(listContainer); // 리스트 갱신 replaceTextWithImage(); // 채팅창 갱신 }); listItem.appendChild(text); listItem.appendChild(deleteButton); listContainer.appendChild(listItem); } } // 입력 및 리스트 UI 생성/표시 함수 function toggleInputUI() { if (uiDiv && document.body.contains(uiDiv)) { // UI가 이미 열려 있으면 닫기 document.body.removeChild(uiDiv); uiDiv = null; return; } // UI 생성 uiDiv = document.createElement('div'); uiDiv.style.position = 'fixed'; uiDiv.style.top = '10px'; uiDiv.style.right = '10px'; uiDiv.style.zIndex = '1000'; uiDiv.style.backgroundColor = '#ffffff'; uiDiv.style.padding = '10px'; uiDiv.style.borderRadius = '6px'; uiDiv.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.1)'; uiDiv.style.maxWidth = '300px'; // 최대 너비 유지 uiDiv.style.fontFamily = 'Arial, sans-serif'; // 닫기 버튼 추가 const closeButton = document.createElement('button'); closeButton.textContent = '×'; closeButton.style.position = 'absolute'; closeButton.style.top = '5px'; closeButton.style.right = '5px'; closeButton.style.width = '20px'; closeButton.style.height = '20px'; closeButton.style.backgroundColor = '#ddd'; closeButton.style.color = '#555'; closeButton.style.border = 'none'; closeButton.style.borderRadius = '50%'; closeButton.style.fontSize = '14px'; closeButton.style.cursor = 'pointer'; closeButton.style.display = 'flex'; closeButton.style.alignItems = 'center'; closeButton.style.justifyContent = 'center'; closeButton.style.transition = 'background-color 0.2s'; closeButton.addEventListener('mouseover', () => closeButton.style.backgroundColor = '#ccc'); closeButton.addEventListener('mouseout', () => closeButton.style.backgroundColor = '#ddd'); closeButton.addEventListener('click', toggleInputUI); uiDiv.appendChild(closeButton); // 입력 영역 const inputContainer = document.createElement('div'); inputContainer.style.marginBottom = '10px'; inputContainer.style.marginTop = '15px'; // 닫기 버튼과 간격 유지 const wordInput = document.createElement('input'); wordInput.type = 'text'; wordInput.placeholder = '단어'; wordInput.style.width = '100%'; // 가로폭 100% wordInput.style.padding = '6px'; wordInput.style.marginBottom = '5px'; // 아래쪽 간격 wordInput.style.border = '1px solid #ddd'; wordInput.style.borderRadius = '3px'; wordInput.style.outline = 'none'; wordInput.style.fontSize = '12px'; wordInput.style.transition = 'border-color 0.2s'; wordInput.addEventListener('focus', () => wordInput.style.borderColor = '#007bff'); const urlInput = document.createElement('input'); urlInput.type = 'text'; urlInput.placeholder = 'URL'; urlInput.style.width = '100%'; // 가로폭 100% urlInput.style.padding = '6px'; urlInput.style.marginBottom = '5px'; // 아래쪽 간격 urlInput.style.border = '1px solid #ddd'; urlInput.style.borderRadius = '3px'; urlInput.style.outline = 'none'; urlInput.style.fontSize = '12px'; urlInput.style.transition = 'border-color 0.2s'; urlInput.addEventListener('focus', () => urlInput.style.borderColor = '#007bff'); const sizeInput = document.createElement('input'); sizeInput.type = 'number'; sizeInput.placeholder = 'px'; sizeInput.style.width = '50px'; // 크기 필드는 작게 유지 sizeInput.style.padding = '6px'; sizeInput.style.border = '1px solid #ddd'; sizeInput.style.borderRadius = '3px'; sizeInput.style.outline = 'none'; sizeInput.style.fontSize = '12px'; sizeInput.style.transition = 'border-color 0.2s'; sizeInput.min = '1'; sizeInput.addEventListener('focus', () => sizeInput.style.borderColor = '#007bff'); const addButton = document.createElement('button'); addButton.textContent = '추가'; addButton.style.padding = '6px 8px'; addButton.style.backgroundColor = '#007bff'; addButton.style.color = '#fff'; addButton.style.border = 'none'; addButton.style.borderRadius = '3px'; addButton.style.cursor = 'pointer'; addButton.style.fontSize = '12px'; addButton.style.transition = 'background-color 0.2s'; addButton.style.marginLeft = '5px'; // 크기 입력과 간격 addButton.addEventListener('mouseover', () => addButton.style.backgroundColor = '#0056b3'); addButton.addEventListener('mouseout', () => addButton.style.backgroundColor = '#007bff'); addButton.addEventListener('click', () => { const word = wordInput.value.trim(); const imgUrl = urlInput.value.trim(); const size = parseInt(sizeInput.value) || 24; // 입력값 없으면 기본 24px if (word && imgUrl) { wordToImageMap[word] = { url: imgUrl, size: size }; saveWordToImageMap(); // 추가 후 저장 replaceTextWithImage(); // 즉시 반영 updateListUI(listContainer); // 리스트 갱신 wordInput.value = ''; urlInput.value = ''; sizeInput.value = ''; } else { alert('단어와 이미지 URL을 모두 입력해주세요.'); } }); // 입력 필드와 버튼을 컨테이너에 추가 inputContainer.appendChild(wordInput); inputContainer.appendChild(urlInput); const sizeAddContainer = document.createElement('div'); sizeAddContainer.style.display = 'flex'; sizeAddContainer.style.alignItems = 'center'; sizeAddContainer.appendChild(sizeInput); sizeAddContainer.appendChild(addButton); inputContainer.appendChild(sizeAddContainer); // 리스트 영역 const listContainer = document.createElement('div'); listContainer.style.maxHeight = '150px'; // 높이 유지 listContainer.style.overflowY = 'auto'; listContainer.style.padding = '4px'; listContainer.style.backgroundColor = '#fff'; listContainer.style.borderRadius = '3px'; listContainer.style.border = '1px solid #eee'; uiDiv.appendChild(inputContainer); uiDiv.appendChild(listContainer); document.body.appendChild(uiDiv); // 초기 리스트 표시 updateListUI(listContainer); } // 탬퍼몽키 메뉴에 "설정" 항목 추가 GM_registerMenuCommand('설정', toggleInputUI); // MutationObserver 설정 const observer = new MutationObserver(replaceTextWithImage); const chattings = document.getElementById('chattings'); if (chattings) { observer.observe(chattings, { childList: true, subtree: true }); replaceTextWithImage(); // 초기 실행 } else { console.error('#chattings 요소를 찾을 수 없습니다.'); } })();