NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Trovo Цветные Ники // @name:ru Trovo: Цветные Ники // @name:en Trovo: Color Nick (Names) // @namespace http:/mjkey.ru/ // @version 0.0.2 * Больше цветов! // @description Цветные ники для Trovo | EN Author (Owner): yyko // @description:ru Цветные ники для Trovo | EN Author (Owner): yyko // @description:en Color nicknames for Trovo | EN Author (Owner): yyko // @author MjKey | Owner: yyko // @match https://trovo.live/* // @icon https://icons.duckduckgo.com/ip2/trovo.live.ico // @license MIT // @run-at document-end // @updateURL https://openuserjs.org/meta/MjKey/Trovo_Цветные_Ники.meta.js // @downloadURL https://openuserjs.org/install/MjKey/Trovo_Цветные_Ники.user.js // @grant GM_addStyle // @copyright yyko // @collaborator MjKey // ==/UserScript== (function () { 'use strict'; const maxAttemptsCount = 10; const attmeptDelay = 2000; const colorMap = new Map([ ["red", "#FF0000"], //красный ["blue", "#0000FF"], //синий ["green", "#008000"], //зелёный ["firebrick", "#B22222"], //кирпичный ["coral", "#FF7F50"], //коралловый ["yellowgreen", "#9ACD32"], //лайм ["orangered", "#FF4500"], //красно-оранжевый ["seagreen", "#2E8B57"], //морская волна ["goldenrod", "#DAA520"], //красное золото ["chocolate", "#D2691E"], //шоколадный ["cadetblue", "#5F9EA0"], //серо-голубой ["dodgerblue", "#1E90FF"], //васильковый ["hotpink", "#FF69B4"], //ярко-розовый ["blueviolet", "#8A2BE2"], //индиго ["aqua", "#00FFFF"], //аква ]); const colorNames = Array.from(colorMap.keys()); // Значёк палитры от Google (https://www.flaticon.com/authors/google) const colorizerSvg = '<svg aria-hidden="true" class="svg-icon btn-icon size24" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="24" height="24"><path d="M12 1.5C6.202 1.5 1.5 6.202 1.5 12S6.202 22.5 12 22.5a1.748 1.748 0 0 0 1.295-2.923 1.733 1.733 0 0 1-.437-1.16c0-.969.781-1.75 1.75-1.75h2.059a5.835 5.835 0 0 0 5.833-5.834C22.5 5.677 17.798 1.5 12 1.5zM5.583 12c-.968 0-1.75-.782-1.75-1.75s.782-1.75 1.75-1.75c.969 0 1.75.782 1.75 1.75S6.552 12 5.583 12zm3.5-4.667c-.968 0-1.75-.781-1.75-1.75 0-.968.782-1.75 1.75-1.75.969 0 1.75.782 1.75 1.75 0 .969-.781 1.75-1.75 1.75zm5.834 0c-.969 0-1.75-.781-1.75-1.75 0-.968.781-1.75 1.75-1.75.968 0 1.75.782 1.75 1.75 0 .969-.782 1.75-1.75 1.75zm3.5 4.667c-.969 0-1.75-.782-1.75-1.75s.781-1.75 1.75-1.75c.968 0 1.75.782 1.75 1.75S19.385 12 18.417 12z" style="stroke-width:.0546871"/></svg>'; const obsConfig = { childList: true }; const classPrefix = 'clrz_'; const cpCSSbase = '.cp_list,.cp_color{display: inline-block;line-height: 0px;}.cp_list{max-width: 125px;}.cp_color{margin: 0px;width: 25px;height: 25px;transition: all 0.2s ease;}.cp_color_active{box-shadow: 0 0 0 5px white inset;}'; const onlyChat = !!document.location.href.match('https://trovo.live/chat/.*'); // локальное хранилище function mapToStr(map) { return JSON.stringify(Object.fromEntries(map)); } function strToMap(str) { return new Map(Object.entries(JSON.parse(str))); } function loadData(entryName = 'users') { let data = localStorage.getItem(entryName); if (data) { return strToMap(data); } else { return null; } } function saveData(data, entryName = 'users') { localStorage.setItem(entryName, mapToStr(data)); } // -- // инструменты пользователя let sessionUsers = new Map(); let users = loadData(); if (users) { if (localStorage.getItem('tncts_localUsers')) { localStorage.removeItem('tncts_localUsers'); } } else { users = new Map(); } function addUser(name) { let userColor = getRandomColorName(); createUserClass(name, userColor); changeUserColor(name, userColor); return userColor; } function delUser(name) { users.delete(name); saveData(users); } // -- // инструменты цвета function getRandomColorName() { return colorNames[Math.round(Math.random() * colorNames.length)]; } function getUserColor(name) { return users.get(name); } function changeUserColor(name, colorName) { let ccr = checkColor(colorName); if (ccr) { let cv; if (ccr == 1) { cv = colorMap.get(colorName.toLocaleLowerCase()); } else if (ccr == 2) { cv = colorName; } changeUserClass(name, cv); users.set(name, cv); saveData(users); } } function checkColor(colorName) { if (colorMap.has(colorName)) { return 1; } else if (colorName.match(/^#[0-9a-f]{3,4}$|^#(?:[0-9a-f]{2}){3,4}$/)) { return 2; } else { return false; } } function findColorByCode(cc) { for (let i of colorMap) { if (i[1] == cc) return i[0]; } } // -- // стилизация let ss; function initSS() { if (ss) document.head.appendChild(ss); else ss = GM_addStyle(makeStyleText()); } function createUserClass(name, color) { ss.innerHTML = ss.innerHTML + `.${getUserClassName(name)}{color:${color} !important;}`; sessionUsers.set(name, color); } function changeUserClass(name, newcolor) { let ucn = getUserClassName(name); ss.innerHTML = ss.innerHTML.replace(`.${ucn}{color:${getUserColor(name)} !important;}`, `.${ucn}{color:${newcolor} !important;}`); } function getUserClassName(name) { return `${classPrefix}${name}`; } // -- // палитра function makeStyleText(lumshift = 0.2) { let cpCSS = cpCSSbase; function cpbCSS(cn, cc) { function parseCol(a) { let outp = []; a = a.slice(1); for (let i = 0; i < 3; i++) { outp.push(parseInt(a.slice(i * a.length / 3, (i + 1) * a.length / 3), 16)); if (a.length == 3) outp[i] *= 16; } return outp; } function clamp(a, min, max) { return (a < min) ? min : (a > max) ? max : a; } function hex(from) { let outp = '#', tl = true, t; for (let i in from) from[i] = Math.round(from[i]); for (let i of from) tl = tl & (i % 0x11 == 0); for (let i of from) { t = i.toString(16); outp += (tl) ? t[0] : (t.length > 1) ? t : '0' + t; } return outp; } function slum(col, s) { col = col.slice(); let as = s * 3 * 0xff; let sow = 0; if (s > 0) { for (let i of col) sow += 1 - i / 0xff; for (let i = 0; i < 3; i++) col[i] = clamp(col[i] + (1 - col[i] / 0xff) / sow * as, 0, 0xff); return col; } else { for (let i of col) sow += i / 0xff; for (let i = 0; i < 3; i++) col[i] = clamp(col[i] + col[i] / 0xff / sow * as, 0, 0xff); return col; } } function shiftCol(col, s) { return hex(slum(parseCol(col), s)); } return `.cp_color_${cn}{background-color: ${cc};}.cp_color_${cn}:hover{background-color: ${shiftCol(cc,lumshift)};}`; } for (let i of colorMap) cpCSS += cpbCSS(i[0], i[1]); return cpCSS; } function createPalleteElement(lstn) { function n(t) { return document.createElement(t); } let outp = n('div'); outp.className = 'cp_list'; function onselect(e, me, silent = false) { me = me || this; for (let i of outp.childNodes) i.classList.remove('cp_color_active'); me.classList.toggle('cp_color_active'); if (!silent && lstn) lstn(outp.nick, me.getAttribute('mycolor')); } let colblock; outp.colblocks = []; for (let i of colorMap) { colblock = n('div'); colblock.className = 'cp_color cp_color_' + i[0]; colblock.setAttribute('mycolor', i[0]); colblock.addEventListener('click', onselect); outp.appendChild(colblock); outp.colblocks.push(colblock); } outp.style.position = 'fixed'; outp.style.zIndex = '99999'; outp.style.display = 'none'; outp.setPos = function (x, y) { outp.style.left = x + 'px'; outp.style.top = y + 'px'; }; outp.select = function (color) { for (let i of outp.colblocks) { if (i.getAttribute('mycolor') == color) { onselect(null, i, true); break; } } }; return outp; } function onclick(e) { switch (true) { case e.target.classList.contains('nick-name'): palleteElement.nick = e.target.getAttribute('title'); palleteElement.select(findColorByCode(getUserColor(palleteElement.nick))); //kostyl setTimeout(function () { try { let boxpos = document.getElementsByClassName('card-container')[0].getBoundingClientRect(); palleteElement.setPos((onlyChat) ? boxpos.x + boxpos.width : boxpos.x - palleteElement.getBoundingClientRect().width, boxpos.y); } catch (e) { console.log('увы, костыль не сработал', e); } }, 123); //--kostyl case e.target.classList.contains('cp_color'): palleteElement.style.display = 'block'; break; default: palleteElement.style.display = 'none'; palleteElement.nick = null; break; } //return false; } // -- function onmessage(mutations, observer) { for (let mutation of mutations) { for (let msgel of mutation.addedNodes) { let nameel = msgel.getElementsByClassName('nickname-box')[0]; let name; if (nameel) { name = nameel.getElementsByClassName('nick-name')[0].title; if (!users.has(name)) addUser(name); else if (!sessionUsers.has(name)) createUserClass(name, getUserColor(name)); // обработка команды изменения цвета let msgtextel = msgel.getElementsByClassName('content')[0]; if (msgtextel) { let msgtext = msgtextel.innerText; let res = msgtext.match(/^!color (.*)/); if (res) { let colorValue = res[1]; if (checkColor(colorValue)) { changeUserColor(name, res[1]); } else { console.warn('цвет недоступен'); } } } // применение цвета nameel.classList.add(getUserClassName(name)); } } } } // инициализация let launched; let launching; let chatElement; let chatObserver; let palleteElement; function findChatElement() { return document.getElementsByClassName('chat-list')[0]; } let attemptsLeft = maxAttemptsCount; let attemptsTimer; function initChat() { launched = false; launching = true; chatElement = findChatElement(); if (chatElement) { initSS(); palleteElement = createPalleteElement(changeUserColor); document.body.appendChild(palleteElement); window.addEventListener('mouseup', onclick); chatObserver = new MutationObserver(onmessage); chatObserver.observe(chatElement, obsConfig); launched = true; launching = false; console.warn('стартуем'); } else { if (attemptsLeft > 0) { console.warn('Попыток старта: ', attemptsLeft--); attemptsTimer = setTimeout(initChat, attmeptDelay); } else { console.warn('не найден чат'); launching = false; } } } function initBaseObs() { let baseElement = document.getElementsByClassName('base-container')[0]; if (baseElement) { let baseObserver = new MutationObserver(onbasechanged); baseObserver.observe(baseElement, obsConfig); } else { console.warn('не найден базовый контейнер'); } } function onbasechanged() { if (findChatElement()) { if (!launching && !launched) initChat(); } else { if (launched) { console.warn('остановка'); chatObserver.disconnect(); ss.remove(); attemptsLeft = maxAttemptsCount; launched = launching = false; } } } function init() { initBaseObs(); initChat(); } init(); // -- })();