trovonicknamecolorizer

colorize nicknames in Trovo chat

当前为 2021-10-17 提交的版本,查看 最新版本

// ==UserScript==
// @name         trovonicknamecolorizer
// @namespace    http://tampermonkey.net/
// @version      0.2.5.9
// @description  colorize nicknames in Trovo chat
// @author       yyko
// @match        https://trovo.live/*
// @icon         https://www.google.com/s2/favicons?domain=trovo.live
// @run-at       document-end
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const maxAttemptsCount = 20;
    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"],//салатовый
    ]);

    // Palette icon made by Google from www.flaticon.com (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>';

    // 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 users = loadData();
    if(users){
        if(localStorage.getItem('tncts_localUsers')){
            localStorage.removeItem('tncts_localUsers');
        }
    }else{
        users = new Map();
    }

    let settings = loadData('colorizerSettings');
    if(!settings){
        settings = new Map([['baseLock',false],['interfaceState',true]]);
    }

    function addUser(username){
        let userColor = getRandomColor();
        setUserColor(username,userColor,true);
        return userColor;
    }

    function delUser(username){
        users.delete(username);
        saveData(users);
    }

    // --

    // color tools

    let colorNames;
    function getColorNames(){
        if(!colorNames){
            let colorNamesIterator=colorMap.keys();
            colorNames=[];
            for(let colorName of colorNamesIterator){
                colorNames.push(colorName);
            }
        }
        return colorNames
    }

    function getRandomColor(){
        let colors=getColorNames();
        return colors[Math.round(Math.random()*colors.length)];
    }

    function getUserColor(username){
        let userColor;
        if(users.has(username)){
            userColor = users.get(username);
        }else{
            userColor = addUser(username);
        }
        return userColor;
    }

    function setUserColor(username,colorName,force=false){
        if(!settings.get('baseLock')||force){
            let ccr=checkColor(colorName);
            if(ccr){
                let cv;
                if(ccr==1){
                    cv=colorMap.get(colorName.toLocaleLowerCase());
                }else if(ccr==2){
                    cv=colorName;
                }
                users.set(username,cv);
                saveData(users);
            }
        }
    }

    function checkColor(colorName){
        if(colorMap.has(colorName)){
            return 1;
        }else if(colorName.match(/^#[0-9a-f]{3}$|^#[0-9a-f]{4}$|^#[0-9a-f]{6}$|^#[0-9a-f]{8}$/)){
            return 2;
        }else{
            return false;
        }
    }

    // --

    // iterface

    function getSettingsButtonElement(){
        let featureBox=document.getElementsByClassName('input-feature-box')[0];
        if(featureBox){
            return featureBox.getElementsByClassName('cat-button normal icon')[0];
        }
    }

    let cbtn;
    function createColorizerButton(){
        let sbe=getSettingsButtonElement();
        if(sbe){
            cbtn=sbe.cloneNode(false);
            cbtn.setAttribute('data-enclave','colorizer');
            cbtn.innerHTML=colorizerSvg;
            cbtn.color='white';
            if(settings.get('interfaceState')){
                cbtn.classList.add('active');
            }
            getSettingsButtonElement().after(cbtn);
            cbtn.addEventListener('click',toggleInterface);
        }
    }

    function toggleInterface(){
        if(settings.get('interfaceState')){
            // on disable interface
            cbtn.classList.remove('active');
        }else{
            // on enable interface
            cbtn.classList.add('active');
        }
        toggleBaseLock();
        settings.set('interfaceState',!settings.get('interfaceState'));

        saveData(settings,'colorizerSettings');
    }

    // --

    // local users base settings

    function toggleBaseLock(){
        if(settings.get('baseLock')){
            // on unlock base
        }else{
            // on lock base
        }
        settings.set('baseLock',!settings.get('baseLock'));
    }

    // --

    // ***, ****** ******* *****
    let kostyl=true;
    // *--
    function onmessage(mutations,observer){
        if(kostyl){
            kostyl=false;
            createColorizerButton();
        }
        for(let mutation of mutations){
            for(let msgel of mutation.addedNodes){
                let nameel=msgel.getElementsByClassName('nickname-box')[0];
                let nickname;
                if(nameel){
                    nickname=nameel.getElementsByClassName('nick-name')[0].title;

                    // команда на изменение цвета
                    let msgtextel=msgel.getElementsByClassName('content')[0];
                    if(msgtextel){
                        let msgtext=msgtextel.innerText;
                        let res=msgtext.match(/^!color (.*)/);
                        if(res){
                            let args=res[1].split(' ');
                            let colorValue=args[args.length-1];
                            if(checkColor(colorValue)){
                                if(args.length>1){
                                    for(let i=0;i<args.length-1;i++){
                                        if(args[i][0]=='@'){
                                            args[i]=args[i].slice(1);
                                        }
                                        setUserColor(args[i],args[args.length-1]);
                                    }
                                }else{
                                    setUserColor(nickname,res[1]);
                                }
                            }else{
                                console.warn('color is not available');
                            }
                        }
                    }

                    // применение цвета к новому сообщению
                    nameel.style.color=getUserColor(nickname);
                }
            }
        }
    }

    // initialization

    let launched=false;
    let chatElement;
    let chatObserver;
    const obsConfig={childList:true};

    function setChatElement(){
        chatElement = document.getElementsByClassName('chat-list')[0];
        return chatElement;
    }

    let attemptsLeft = maxAttemptsCount;
    let attemptsTimer;

    function initChat(){
        if(setChatElement()){
            chatObserver = new MutationObserver(onmessage);
            chatObserver.observe(chatElement,obsConfig);

            //createColorizerButton();

            console.warn('started');
            launched=true;
        }else{
            if(attemptsLeft>0){
                console.warn('attempts left to start: ',attemptsLeft);
                attemptsLeft--;
                attemptsTimer=setTimeout(initChat,attmeptDelay);
            }else{
                console.warn('cant find chat element');
            }
        }
    }

    function init(){
        initChat();

        let baseElement = document.getElementsByClassName('base-container')[0];
        if(baseElement){
            let baseObserver = new MutationObserver(restart);
            baseObserver.observe(baseElement,obsConfig);
        }else{
            console.warn('cant find base-container');
        }
    }

    function restart(){
        console.warn('restarted');
        attemptsLeft=maxAttemptsCount;
        if(launched){
            chatObserver.disconnect();
            if(cbtn){
                cbtn.remove();
                kostyl=true;
            }
            launched=false;
            initChat();
        }
    }

    init();

    // --
})();