🔌 Guide de développement des adaptateurs
Les adaptateurs ForcedSkin sont rédigés sous forme de formules JSON déclaratives ( forcedskin-adapter-formula/v1 ) décrivant les noms d'hôte cibles et les calques de sélecteurs à teinter. Le serveur ne stocke que du JSON ; l'extension embarque un interpréteur fixe qui applique les règles de peinture — jamais de JavaScript arbitraire.
Fonctionnement
Le moteur de base commence par des superpositions de variables CSS + styles inline pour un recoloriage de base.
Lorsqu'un nom d'hôte correspond, les adaptateurs s'exécutent par priorité croissante — plus le nombre est petit, plus tôt l'interpréteur s'exécute (les adaptateurs de site recommandés utilisent 100).
Chaque adaptateur ajuste les nœuds ciblés via les helpers engineApi exposés ; ignorez les superpositions transparentes / piles lecteur selon les bonnes pratiques.
Le runtime observe déjà les deltas du DOM et réapplique les adaptateurs de façon limitée — pas besoin de MutationObserver.
Les formules arrivent via GET /api/pub/extension-adapters ; le blob JSON de chaque enregistrement est mis en cache localement. Mettre à jour la copie du portail prend effet une fois que les utilisateurs actualisent les adaptateurs ou rouvrent le navigateur — aucune réinstallation.
Exemple minimal
{
"schema": "forcedskin-adapter-formula/v1",
"id": "example-site",
"priority": 100,
"match": {
"hostname": [
{ "op": "suffixDomain", "value": "example.com" }
]
},
"layers": [
{
"kind": "surface",
"skipOverlayLike": true,
"selectors": [".site-navbar", ".site-header"]
}
]
}Formule d'adaptateur forcedskin-adapter-formula/v1
Le JSON soumis doit passer la validation serveur — le schéma racine ressemble à ceci :
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
| schema | string | Obligatoire | Chaîne de version littérale forcedskin-adapter-formula/v1 |
| id | string | Obligatoire | Identifiant logique de l'adaptateur — généralement le nom de code du site, ex. bilibili |
| priority | number | Facultatif | Ordre d'exécution (croissant). Les adaptateurs spécifiques à un site utilisent généralement 100 |
| match.hostname | Rule[] | Obligatoire | Tableau d'objets de règles de nom d'hôte (voir le tableau ci-dessous) |
| layers | Layer[] | Obligatoire | Calques de peinture ordonnés — types documentés dans le tableau des calques |
Règles match.hostname
| Opérateur | Signification |
|---|---|
| equals | Le nom d'hôte est égal à value (insensible à la casse) |
| suffixDomain | Le nom d'hôte est égal à value ou se termine par .value (couvre example.com et *.example.com) |
Clés de palette (richText cssVars / color)
| Champ | Description |
|---|---|
| background | Fond de page |
| foreground | Texte principal |
| surface | Remplissage carte / panneau |
| surfaceMuted | Conteneurs atténués / fonds de survol |
| border | Couleur de bordure |
| muted | Texte secondaire |
| primary500 | Accent principal (liens) mappé depuis theme primary.500 |
| primary700 | État primary plus profond mappé depuis primary.700 ou 800 |
Types de calques recommandés
Pensez sémantiquement — pas seulement par nom d'élément. Voir l'exemple versionné home/server/seeds/bilibili-adapter.formula.json pour un parcours complet.
| Type de calque | Usage | Correspondance typique | markApplied |
|---|---|---|---|
| surface | Panneaux, lignes de liste, coques de navigation | background→surface, color→foreground, border→border | bg + texte + bordure |
| accent | Onglets actifs / lignes de liste courantes | background+border→primary700, color→background pour le contraste | bg + texte + bordure |
| canvas | Dalles hero avec fonds raster | Retirer background-image, background→palette background | Généralement le fond uniquement |
| richText | Sites qui exposent des web components de marque | Émettre les variables CSS requises + correspondance de couleur textuelle | texte (parfois + fond) |
| svgRecolor | Glyphes SVG inline | fill/stroke par défaut→currentColor ; clés de palette fill/stroke optionnelles pour une couleur fixe | Marquage optionnel pour ne pas perturber le nettoyage |
Zones à éviter : Le moteur ignore déjà media, canvas, iframe, les calques blend/backdrop lourds, et les nœuds dont les classes évoquent des masques ou superpositions — étendez ces garde-fous pour le chrome translucide des lecteurs.
Opt-out d'hôte : Marquez les sous-arbres (ex. aperçus) avec data-gts-ignore pour que leurs descendants échappent au repeint global.
Extrait d'exemple complet
{
"schema": "forcedskin-adapter-formula/v1",
"id": "bilibili",
"priority": 100,
"match": {
"hostname": [
{ "op": "equals", "value": "bilibili.com" },
{ "op": "suffixDomain", "value": "bilibili.com" }
]
},
"layers": [
{
"kind": "surface",
"skipOverlayLike": true,
"selectors": ["[class*='bili-']", "[class*='bpx-']"]
},
{
"kind": "accent",
"selectors": ["[class*='active']", ".bili-dyn-list-tabs__item.active"]
},
{
"kind": "canvas",
"selectors": [".message-bg", ".message-bgc"]
},
{
"kind": "richText",
"selectors": ["bili-rich-text"],
"cssVars": {
"--bili-rich-text-color": "foreground",
"--bili-rich-text-link-color": "primary500",
"--bili-rich-text-link-color-hover": "primary700"
},
"color": "foreground"
},
{
"kind": "svgRecolor",
"selectors": ["svg path", "svg rect", "svg circle"]
}
]
}Bonnes pratiques
Le JSON doit être strictement valide
Schéma / calques / règles d'hôte invalides sont rejetés à la validation — partez de l'exemple minimal et des seeds de ce guide avant de soumettre.
Activez skipOverlayLike sur surface
Alignez-vous sur les garde-fous du moteur pour que les HUD translucides / piles vidéo ne soient pas aplatis en aplats opaques.
N'envoyez jamais de JavaScript
Le champ code est du JSON uniquement ; l'extension n'évalue plus de chaînes via new Function.
Liste de contrôle de soumission
🔐 Connectez-vous avant de déposer une soumission.
📋 Fournissez un nom affiché, des domaines séparés par des virgules, et collez le JSON dans la zone de code de l'adaptateur.
⏳ Le serveur valide le schéma JSON et les règles de sécurité ; le JavaScript ou tout code à risque est rejeté.
✅ Les formules valides sont publiées automatiquement et déployées auprès des utilisateurs d'extension qui synchronisent les adaptateurs.
❌ Des sélecteurs trop larges ou un JSON invalide renvoient un retour — corrigez et renvoyez.
Format du domaine cible
siteDomain est la liste affichée ; la correspondance réelle s'appuie sur match.hostname comme :
[
{ "op": "equals", "value": "bilibili.com" },
{ "op": "suffixDomain", "value": "bilibili.com" }
]Prêt ? Ouvrez la galerie d'adaptateurs et soumettez votre JSON.
🔌 Soumettre un adaptateur