Injectionche

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

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Advertisement:

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

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);
    }

})();