Injectionche

Integre vos collections de stickers personnels dans le picker natif d'Onche.org

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

Advertisement:

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

Advertisement:

// ==UserScript==
// @name         Injectionche
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Integre vos collections de stickers personnels dans le picker natif d'Onche.org
// @author       SilverWolf
// @match        https://onche.org/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    // =========================================================
    //  CONFIG
    // =========================================================
    var collectionsCache           = null;
    var stickersCacheParCollection = {};

    // =========================================================
    //  MutationObserver — injecter l'onglet quand le picker s'ouvre
    // =========================================================

    var _debounceObs = null;
    var observerPicker = new MutationObserver(function() {
        if (_debounceObs) return;
        _debounceObs = setTimeout(function() {
            _debounceObs = null;
            tenterInjectionOnglet();
        }, 100);
    });

    function tenterInjectionOnglet() {
        if (document.getElementById('sp-tab-mes-collections')) return;

        var tabsBar = null;
        var allTabs = document.querySelectorAll('#tooltip .tabs, .tabs');
        for (var i = 0; i < allTabs.length; i++) {
            if (allTabs[i].textContent.indexOf('Stickers') !== -1) {
                tabsBar = allTabs[i];
                break;
            }
        }
        if (!tabsBar) return;

        var tab = document.createElement('button');
        tab.type        = 'button';
        tab.id          = 'sp-tab-mes-collections';
        tab.textContent = '⭐ Mes collections';
        tab.style.cssText = 'padding:6px 10px;background:none;border:none;border-bottom:2px solid transparent;color:#aaa;cursor:pointer;font-size:12px;font-weight:bold;white-space:nowrap;transition:color 0.2s,border-color 0.2s';

        tab.addEventListener('mouseenter', function() { this.style.color = '#4a90d9'; });
        tab.addEventListener('mouseleave', function() {
            if (this.getAttribute('data-active') !== '1') { this.style.color = '#aaa'; this.style.borderBottomColor = 'transparent'; }
        });
        tab.addEventListener('click', function() {
            tabsBar.querySelectorAll('button, [class*="tab"]').forEach(function(t) {
                t.style.borderBottomColor = 'transparent';
                t.style.color = '#aaa';
                t.removeAttribute('data-active');
            });
            tab.style.color            = '#4a90d9';
            tab.style.borderBottomColor = '#4a90d9';
            tab.setAttribute('data-active', '1');
            afficherPanneauCollections();
        });

        tabsBar.appendChild(tab);
    }

    observerPicker.observe(document.body, { childList: true, subtree: true });

    // =========================================================
    //  Panneau collections
    // =========================================================

    function afficherPanneauCollections() {
        var tabBtn = document.getElementById('sp-tab-mes-collections');
        if (!tabBtn) return;

        var tooltip = document.getElementById('tooltip') || tabBtn.closest('.with-margin');
        if (!tooltip) return;

        var ancien = document.getElementById('sp-panneau-collections');
        if (ancien) ancien.remove();

        var panneau      = document.createElement('div');
        panneau.id       = 'sp-panneau-collections';
        var rect         = tooltip.getBoundingClientRect();
        panneau.style.cssText = [
            'position:fixed',
            'top:'    + (rect.top    + 40) + 'px',
            'left:'   +  rect.left         + 'px',
            'width:'  +  rect.width        + 'px',
            'height:' + (rect.height - 40) + 'px',
            'background:#0f1923',
            'z-index:99999',
            'overflow-y:auto',
            'padding:8px',
            'box-sizing:border-box',
            'border-top:1px solid #2c3e50',
            'border-radius:0 0 8px 8px'
        ].join(';');

        panneau.innerHTML = '<div id="sp-contenu-collections"><div style="color:#aaa;text-align:center;padding:20px;font-size:12px">Chargement de tes collections...</div></div>';
        tooltip.appendChild(panneau);

        // Fermer quand on clique sur un onglet natif
        tooltip.querySelectorAll('.tab').forEach(function(t) {
            t.addEventListener('click', function() {
                panneau.remove();
                tabBtn.style.color            = '#aaa';
                tabBtn.style.borderBottomColor = 'transparent';
                tabBtn.removeAttribute('data-active');
            });
        });

        chargerCollections(function(collections) {
            afficherListeCollections(collections);
        });
    }

    // =========================================================
    //  Charger les collections
    // =========================================================

    function chargerCollections(callback) {
        if (collectionsCache) { callback(collectionsCache); return; }
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'https://onche.org/stickers');
        xhr.withCredentials = true;
        xhr.onload = function() {
            var doc         = new DOMParser().parseFromString(xhr.responseText, 'text/html');
            var collections = [];
            doc.querySelectorAll('a[href*="/stickers/collection/"]').forEach(function(lien) {
                var href = lien.getAttribute('href');
                var mId  = href.match(/\/collection\/(\d+)/);
                if (!mId) return;
                var id  = mId[1];
                var nom = lien.textContent.trim() || 'Collection ' + id;
                var imgSrc = null;
                var imgs   = lien.querySelectorAll('img[src*="cloud.onche"]');
                for (var i = 0; i < imgs.length; i++) {
                    if (!imgs[i].className || imgs[i].className.indexOf('avatar') === -1) {
                        imgSrc = imgs[i].getAttribute('src');
                        break;
                    }
                }
                if (!collections.find(function(c) { return c.id === id; })) {
                    collections.push({ id: id, nom: nom, imgSrc: imgSrc });
                }
            });
            collectionsCache = collections;
            callback(collections);
        };
        xhr.onerror = function() { callback([]); };
        xhr.send();
    }

    // =========================================================
    //  Afficher la liste des collections
    // =========================================================

    function afficherListeCollections(collections) {
        var contenu = document.getElementById('sp-contenu-collections');
        if (!contenu) return;
        if (collections.length === 0) { afficherRecherche(contenu); return; }
        contenu.innerHTML = '';

        var recherche       = document.createElement('input');
        recherche.type        = 'text';
        recherche.placeholder = 'Chercher dans mes stickers...';
        recherche.style.cssText = 'width:100%;padding:5px 8px;background:#0d1b2a;color:#eee;border:1px solid #2c3e50;border-radius:4px;font-size:11px;box-sizing:border-box;margin-bottom:8px;outline:none';
        var _rechercheTimeout = null;
        recherche.addEventListener('input', function() {
            clearTimeout(_rechercheTimeout);
            var q = this.value.trim();
            if (q.length > 1) {
                _rechercheTimeout = setTimeout(function() { rechercherStickers(q, contenu); }, 400);
            } else {
                afficherGrilleCollections(collections, contenu);
            }
        });
        contenu.appendChild(recherche);
        afficherGrilleCollections(collections, contenu);
    }

    function afficherGrilleCollections(collections, contenu) {
        var ancienne = contenu.querySelector('#sp-grille-collections');
        if (ancienne) ancienne.remove();
        var grille   = document.createElement('div');
        grille.id    = 'sp-grille-collections';
        grille.style.cssText = 'display:grid;grid-template-columns:repeat(3,1fr);gap:6px';
        collections.forEach(function(col) {
            var item = document.createElement('div');
            item.style.cssText = 'background:#0d1b2a;border:1px solid #2c3e50;border-radius:6px;padding:6px;cursor:pointer;text-align:center;transition:border-color 0.2s';
            if (col.imgSrc) {
                var img = document.createElement('img');
                img.src = col.imgSrc;
                img.style.cssText = 'width:40px;height:40px;object-fit:cover;border-radius:4px;display:block;margin:0 auto 3px';
                item.appendChild(img);
            }
            var span = document.createElement('span');
            span.style.cssText = 'font-size:10px;color:#eee;word-break:break-word';
            span.textContent   = col.nom;
            item.appendChild(span);
            item.addEventListener('mouseenter', function() { this.style.borderColor = '#4a90d9'; });
            item.addEventListener('mouseleave', function() { this.style.borderColor = '#2c3e50'; });
            item.addEventListener('click', function() { chargerStickersCollection(col, contenu); });
            grille.appendChild(item);
        });
        contenu.appendChild(grille);
    }

    // =========================================================
    //  Charger les stickers d'une collection
    // =========================================================

    function chargerStickersCollection(collection, contenu) {
        if (stickersCacheParCollection[collection.id]) {
            afficherStickers(stickersCacheParCollection[collection.id], collection.nom, contenu);
            return;
        }
        var ancien = contenu.querySelector('#sp-grille-collections, #sp-grille-stickers');
        if (ancien) ancien.style.opacity = '0.5';
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'https://onche.org/stickers/collection/' + collection.id);
        xhr.withCredentials = true;
        xhr.onload = function() {
            var doc      = new DOMParser().parseFromString(xhr.responseText, 'text/html');
            var stickers = [];
            doc.querySelectorAll('img[src*="cloud.onche.org"]').forEach(function(img) {
                if (img.className && img.className.indexOf('avatar') !== -1) return;
                var alt  = img.getAttribute('alt') || '';
                var src  = img.getAttribute('src') || '';
                var mNom = alt.match(/^:(.+):$/);
                if (!mNom || !src) return;
                var name = mNom[1];
                if (src.indexOf('/128') === -1 && src.indexOf('!') !== -1) {
                    src = src.split('!')[0] + '!' + src.split('!')[1].split('/')[0] + '/128';
                }
                if (!stickers.find(function(s) { return s.name === name; })) {
                    stickers.push({ name: name, image: src });
                }
            });
            if (stickers.length === 0) {
                rechercherStickersCollection(collection.nom, function(results) {
                    stickersCacheParCollection[collection.id] = results;
                    afficherStickers(results, collection.nom, contenu);
                });
                return;
            }
            stickersCacheParCollection[collection.id] = stickers;
            afficherStickers(stickers, collection.nom, contenu);
        };
        xhr.onerror = function() { afficherStickers([], collection.nom, contenu); };
        xhr.send();
    }

    // =========================================================
    //  Recherche API
    // =========================================================

    function rechercherStickers(q, contenu) {
        var ancien = contenu.querySelector('#sp-grille-collections, #sp-grille-stickers');
        if (ancien) ancien.remove();
        var loader = document.createElement('div');
        loader.id  = 'sp-grille-stickers';
        loader.style.cssText = 'color:#aaa;text-align:center;padding:15px;font-size:12px';
        loader.textContent   = 'Recherche...';
        contenu.appendChild(loader);
        var xhr = new XMLHttpRequest();
        xhr.open('POST', 'https://onche.org/stickers/search');
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xhr.withCredentials = true;
        xhr.onload  = function() {
            try { afficherStickers(JSON.parse(xhr.responseText), 'Resultats pour "' + q + '"', contenu); }
            catch(e) { afficherStickers([], 'Aucun resultat', contenu); }
        };
        xhr.onerror = function() { afficherStickers([], 'Erreur reseau', contenu); };
        xhr.send('q=' + encodeURIComponent(q));
    }

    function rechercherStickersCollection(nom, callback) {
        var xhr = new XMLHttpRequest();
        xhr.open('POST', 'https://onche.org/stickers/search');
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xhr.withCredentials = true;
        xhr.onload  = function() { try { callback(JSON.parse(xhr.responseText)); } catch(e) { callback([]); } };
        xhr.onerror = function() { callback([]); };
        xhr.send('q=' + encodeURIComponent(nom));
    }

    function afficherRecherche(contenu) {
        contenu.innerHTML = '';
        var info = document.createElement('div');
        info.style.cssText = 'color:#aaa;font-size:11px;margin-bottom:8px;text-align:center';
        info.textContent   = 'Recherche dans tous tes stickers :';
        contenu.appendChild(info);
        var recherche       = document.createElement('input');
        recherche.type        = 'text';
        recherche.placeholder = 'Nom du sticker...';
        recherche.style.cssText = 'width:100%;padding:5px 8px;background:#0d1b2a;color:#eee;border:1px solid #2c3e50;border-radius:4px;font-size:11px;box-sizing:border-box;margin-bottom:8px;outline:none';
        var timeout = null;
        recherche.addEventListener('input', function() {
            clearTimeout(timeout);
            var q = this.value.trim();
            if (q.length > 1) timeout = setTimeout(function() { rechercherStickers(q, contenu); }, 400);
        });
        contenu.appendChild(recherche);
    }

    // =========================================================
    //  Grille de stickers
    // =========================================================

    function afficherStickers(stickers, titre, contenu) {
        var ancienne = contenu.querySelector('#sp-grille-stickers, #sp-grille-collections');
        if (ancienne) ancienne.remove();

        var header = document.createElement('div');
        header.id  = 'sp-grille-stickers';
        header.style.cssText = 'margin-top:4px';

        var headerBar = document.createElement('div');
        headerBar.style.cssText = 'display:flex;align-items:center;gap:6px;margin-bottom:8px';

        var btnRetour = document.createElement('button');
        btnRetour.type        = 'button';
        btnRetour.id          = 'sp-btn-retour';
        btnRetour.textContent = '← Retour';
        btnRetour.style.cssText = 'background:none;border:1px solid #2c3e50;color:#aaa;border-radius:3px;cursor:pointer;padding:2px 6px;font-size:10px';
        btnRetour.addEventListener('click', function() {
            chargerCollections(function(cols) { header.remove(); afficherGrilleCollections(cols, contenu); });
        });

        var titreSpan = document.createElement('span');
        titreSpan.style.cssText = 'color:#4a90d9;font-size:11px;font-weight:bold';
        titreSpan.textContent   = titre + ' (' + stickers.length + ')';

        headerBar.appendChild(btnRetour);
        headerBar.appendChild(titreSpan);
        header.appendChild(headerBar);

        if (stickers.length === 0) {
            var vide = document.createElement('div');
            vide.style.cssText = 'color:#aaa;text-align:center;padding:15px;font-size:11px';
            vide.textContent   = 'Aucun sticker trouve';
            header.appendChild(vide);
        } else {
            var grille = document.createElement('div');
            grille.style.cssText = 'display:grid;grid-template-columns:repeat(4,1fr);gap:5px';
            stickers.forEach(function(s) {
                var item = document.createElement('div');
                item.style.cssText = 'cursor:pointer;border-radius:4px;padding:2px;border:2px solid transparent;transition:border-color 0.15s;text-align:center';
                item.title = s.name;
                var sImg = document.createElement('img');
                sImg.src   = s.image;
                sImg.style.cssText = 'width:100%;max-width:56px;height:56px;object-fit:contain;border-radius:3px';
                sImg.loading = 'lazy';
                sImg.alt     = s.name;
                var sNom = document.createElement('div');
                sNom.style.cssText = 'font-size:9px;color:#888;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:64px';
                sNom.textContent   = s.name;
                item.appendChild(sImg);
                item.appendChild(sNom);
                item.addEventListener('mouseenter', function() { this.style.borderColor = '#4a90d9'; });
                item.addEventListener('mouseleave', function() { this.style.borderColor = 'transparent'; });
                item.addEventListener('click', function() { insererSticker(s); });
                grille.appendChild(item);
            });
            header.appendChild(grille);
        }
        contenu.appendChild(header);
    }

    // =========================================================
    //  Inserer le sticker dans le textarea
    // =========================================================

    function insererSticker(sticker) {
        // Cacher le panneau
        var panneau = document.getElementById('sp-panneau-collections');
        if (panneau) panneau.style.display = 'none';

        // Format confirme : :nom_sticker: dans textarea[name="message"]
        var textarea = document.querySelector('textarea[name="message"]');
        if (!textarea) return;

        var val    = textarea.value || '';
        var insert = (val && !val.endsWith(' ') ? ' ' : '') + ':' + sticker.name + ':';
        textarea.value = val + insert;
        textarea.dispatchEvent(new Event('input',  { bubbles: true }));
        textarea.dispatchEvent(new Event('change', { bubbles: true }));
        textarea.focus();
        textarea.setSelectionRange(textarea.value.length, textarea.value.length);
    }

})();