NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Лог дозора // @namespace http://tampermonkey.net/ // @version 1.0.0.2 // @description Дозорим приятнее // @author pid0r // @match https://catwar.su/cw3/ // @license MIT; https://opensource.org/licenses/MIT // ==/UserScript== (function () { 'use strict'; const WIN_WID = 180; const WIN_HEI_EXP = 300; const WIN_HEI_COL = 'auto'; const WIN_BG = 'rgb(34, 34, 34)'; const TXT_COL = 'rgb(131, 131, 131)'; const BTN_BG = 'rgb(131, 131, 131)'; const BTN_TXT = 'rgb(34, 34, 34)'; let isExp = true; let isSound = true; let catSet = new Set(); const cont = document.createElement('div'); cont.style.position = 'fixed'; cont.style.width = `${WIN_WID}px`; cont.style.backgroundColor = WIN_BG; cont.style.color = TXT_COL; cont.style.zIndex = 10000; cont.style.top = '10px'; cont.style.left = '10px'; cont.style.borderRadius = '10px'; cont.style.boxShadow = '0px 2px 4px rgba(0, 0, 0, 0.3)'; cont.style.overflow = 'hidden'; const head = document.createElement('div'); head.style.display = 'flex'; head.style.justifyContent = 'space-between'; head.style.alignItems = 'center'; head.style.padding = '5px'; head.style.fontWeight = 'bold'; head.style.cursor = 'move'; head.innerHTML = 'Лог дозора'; const togBtn = document.createElement('button'); togBtn.innerText = '-'; togBtn.style.backgroundColor = BTN_BG; togBtn.style.color = BTN_TXT; togBtn.style.border = 'none'; togBtn.style.cursor = 'pointer'; togBtn.style.fontWeight = 'bold'; togBtn.style.fontSize = '20px'; togBtn.style.width = '30px'; togBtn.style.height = '30px'; togBtn.style.borderRadius = '5px'; head.appendChild(togBtn); const contInner = document.createElement('div'); contInner.style.display = 'block'; contInner.style.padding = '5px'; const sndLbl = document.createElement('label'); sndLbl.style.display = 'flex'; sndLbl.style.alignItems = 'center'; sndLbl.style.marginBottom = '5px'; const sndChk = document.createElement('input'); sndChk.type = 'checkbox'; sndChk.checked = isSound; sndChk.style.marginRight = '5px'; sndLbl.appendChild(sndChk); sndLbl.appendChild(document.createTextNode('Включить звук')); const catList = document.createElement('div'); catList.style.maxHeight = '200px'; catList.style.overflowY = 'auto'; catList.style.marginBottom = '5px'; const clrBtn = document.createElement('button'); clrBtn.innerText = 'Очистить лог'; clrBtn.style.backgroundColor = BTN_BG; clrBtn.style.color = BTN_TXT; clrBtn.style.border = 'none'; clrBtn.style.cursor = 'pointer'; clrBtn.style.width = '100%'; clrBtn.style.borderRadius = '5px'; const saveState = () => { localStorage.setItem('dozorLogExpanded', isExp); localStorage.setItem('dozorLogCats', JSON.stringify([...catSet])); localStorage.setItem('dozorLogHeight', cont.style.height); localStorage.setItem('dozorLogSound', isSound); localStorage.setItem('dozorLogPosition', JSON.stringify({ top: cont.style.top, left: cont.style.left })); }; const restoreState = () => { const savedPos = JSON.parse(localStorage.getItem('dozorLogPosition')); if (savedPos) { cont.style.top = savedPos.top; cont.style.left = savedPos.left; } isExp = JSON.parse(localStorage.getItem('dozorLogExpanded')); if (!isExp) { cont.style.height = `${WIN_HEI_COL}px`; contInner.style.display = 'none'; togBtn.innerText = '+'; } isSound = JSON.parse(localStorage.getItem('dozorLogSound')); sndChk.checked = isSound; const savedCats = JSON.parse(localStorage.getItem('dozorLogCats')); if (savedCats) { savedCats.forEach(cat => { catSet.add(cat); const catElem = document.createElement('div'); catElem.innerText = cat; catList.appendChild(catElem); }); } const savedHeight = localStorage.getItem('dozorLogHeight'); if (savedHeight && isExp) { cont.style.height = savedHeight; } }; let isDrag = false; let startX, startY, initTop, initLeft; const onMouseMove = (e) => { if (isDrag) { const dx = e.clientX - startX; const dy = e.clientY - startY; cont.style.top = `${initTop + dy}px`; cont.style.left = `${initLeft + dx}px`; } }; const onMouseUp = () => { if (isDrag) { isDrag = false; document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); saveState(); } }; head.addEventListener('mousedown', (e) => { if (e.target === togBtn) return; isDrag = true; startX = e.clientX; startY = e.clientY; initTop = cont.offsetTop; initLeft = cont.offsetLeft; document.addEventListener('mousemove', onMouseMove); document.addEventListener('mouseup', onMouseUp); e.preventDefault(); // Prevent text selection }); const onTouchMove = (e) => { if (isDrag) { const touch = e.touches[0]; const dx = touch.clientX - startX; const dy = touch.clientY - startY; cont.style.top = `${initTop + dy}px`; cont.style.left = `${initLeft + dx}px`; e.preventDefault(); } }; const onTouchEnd = () => { if (isDrag) { isDrag = false; document.removeEventListener('touchmove', onTouchMove); document.removeEventListener('touchend', onTouchEnd); saveState(); } }; head.addEventListener('touchstart', (e) => { if (e.target === togBtn) return; isDrag = true; const touch = e.touches[0]; startX = touch.clientX; startY = touch.clientY; initTop = cont.offsetTop; initLeft = cont.offsetLeft; document.addEventListener('touchmove', onTouchMove, { passive: false }); document.addEventListener('touchend', onTouchEnd); }); togBtn.addEventListener('click', () => { isExp = !isExp; if (isExp) { cont.style.height = 'auto'; } else { cont.style.height = `${WIN_HEI_COL}px`; } contInner.style.display = isExp ? 'block' : 'none'; togBtn.innerText = isExp ? '-' : '+'; saveState(); }); sndChk.addEventListener('change', () => { isSound = sndChk.checked; saveState(); }); clrBtn.addEventListener('click', () => { catSet.clear(); catList.innerHTML = ''; saveState(); }); const addCatToList = (name, id) => { const catId = `${name} (${id})`; if (!catSet.has(catId)) { catSet.add(catId); const catElem = document.createElement('div'); catElem.innerText = catId; catList.appendChild(catElem); if (isSound) { const audio = new Audio('https://abstract-class-shed.github.io/cwshed/action_end.mp3'); audio.volume = 0.5; audio.play(); } cont.style.height = 'auto'; if (cont.clientHeight > WIN_HEI_EXP) { cont.style.height = `${WIN_HEI_EXP}px`; } saveState(); } }; const observer = new MutationObserver((mutations) => { mutations.forEach(mutation => { if (mutation.type === 'childList' && mutation.addedNodes.length) { mutation.addedNodes.forEach(node => { if (node.nodeType === 1) { const catElems = node.querySelectorAll('.cat_tooltip a'); catElems.forEach(catElem => { const name = catElem.innerText; const id = catElem.href.match(/cat(\d+)/)[1]; addCatToList(name, id); }); } }); } }); }); observer.observe(document.body, { childList: true, subtree: true }); const chatObserver = new MutationObserver((mutations) => { mutations.forEach(mutation => { if (mutation.type === 'childList' && mutation.addedNodes.length) { mutation.addedNodes.forEach(node => { if (node.nodeType === 1 && node.matches('.cws_chat_wrapper')) { if (isSound) { const audio = new Audio('https://abstract-class-shed.github.io/cwshed/action_end.mp3'); audio.volume = 0.5; audio.play(); } } }); } }); }); const chatContainer = document.querySelector('#cws_chat_msg'); if (chatContainer) { chatObserver.observe(chatContainer, { childList: true, subtree: true }); } else { const bodyObserver = new MutationObserver((mutations) => { mutations.forEach(mutation => { if (mutation.type === 'childList' && mutation.addedNodes.length) { mutation.addedNodes.forEach(node => { if (node.nodeType === 1 && node.id === 'cws_chat_msg') { chatObserver.observe(node, { childList: true, subtree: true }); } }); } }); }); bodyObserver.observe(document.body, { childList: true, subtree: true }); } restoreState(); contInner.appendChild(sndLbl); contInner.appendChild(catList); contInner.appendChild(clrBtn); cont.appendChild(head); cont.appendChild(contInner); document.body.appendChild(cont); })();