Integre vos collections de stickers personnels dans le picker natif d'Onche.org
// ==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);
}
})();