Skip to content

Instantly share code, notes, and snippets.

@oexlkinq
Last active December 13, 2021 08:01
Show Gist options
  • Save oexlkinq/523821df7b2a7c2868a5f3bcb35f7a7e to your computer and use it in GitHub Desktop.
Save oexlkinq/523821df7b2a7c2868a5f3bcb35f7a7e to your computer and use it in GitHub Desktop.
trovo nickname colorizer tampermonkey script
// ==UserScript==
// @name trovonicknamecolorizer
// @namespace http://tampermonkey.net/
// @version 0.2.7
// @description colorize nicknames in Trovo chat
// @author yyko
// @match https://trovo.live/*
// @icon https://icons.duckduckgo.com/ip2/trovo.live.ico
// @run-at document-end
// @grant GM_addStyle
// ==/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"],//индиго
["springgreen","#00FF7F"],//салатовый
]);
const colorNames=Array.from(colorMap.keys());
// Palette icon made by 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/.*');
// local storage tools
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));
}
// --
// users tools
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);
}
// --
// color tools
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];
}
}
// --
// stylesheet
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}`;
}
// --
// pallete
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));
// processing a color change command
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('color is not available');
}
}
}
// applying the color
nameel.classList.add(getUserClassName(name));
}
}
}
}
// initialization
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('started');
}else{
if(attemptsLeft>0){
console.warn('attempts left to start: ',attemptsLeft--);
attemptsTimer=setTimeout(initChat,attmeptDelay);
}else{
console.warn('cant find chat element');
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('cant find base-container');
}
}
function onbasechanged(){
if(findChatElement()){
if(!launching&&!launched)
initChat();
}else{
if(launched){
console.warn('stopping');
chatObserver.disconnect();
ss.remove();
attemptsLeft=maxAttemptsCount;
launched=launching=false;
}
}
}
function init(){
initBaseObs();
initChat();
}
init();
// --
})();
@oexlkinq
Copy link
Author

v0.2.5:
--добавлена возможность отключать команды на смену цвета

@oexlkinq
Copy link
Author

v0.2.6.2:
коротко:
--теперь можно изменить только свой цвет
--цвет меняется для всех сообщений
--кнопки палитры теперь нет

@oexlkinq
Copy link
Author

oexlkinq commented Nov 7, 2021

v0.2.6.3:
--цвета новых пользователей генеририруются исходя из их имени = ваш цвет будет одинаковым у всех пользователей

@oexlkinq
Copy link
Author

v0.2.7:
--при нажатии на никнейм пользователя в чате, рядом со всплывающим окном доп.информации появляется палитра, с помощью которой можно выбрать цвет ника для этого пользователя (цвет меняется только для вас)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment