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

})();