Adaptateurs de sitesGuide de développement

🔌 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 :

ChampTypeObligatoireDescription
schemastringObligatoireChaîne de version littérale forcedskin-adapter-formula/v1
idstringObligatoireIdentifiant logique de l'adaptateur — généralement le nom de code du site, ex. bilibili
prioritynumberFacultatifOrdre d'exécution (croissant). Les adaptateurs spécifiques à un site utilisent généralement 100
match.hostnameRule[]ObligatoireTableau d'objets de règles de nom d'hôte (voir le tableau ci-dessous)
layersLayer[]ObligatoireCalques de peinture ordonnés — types documentés dans le tableau des calques

Règles match.hostname

OpérateurSignification
equalsLe nom d'hôte est égal à value (insensible à la casse)
suffixDomainLe 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)

ChampDescription
backgroundFond de page
foregroundTexte principal
surfaceRemplissage carte / panneau
surfaceMutedConteneurs atténués / fonds de survol
borderCouleur de bordure
mutedTexte secondaire
primary500Accent 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 calqueUsageCorrespondance typiquemarkApplied
surfacePanneaux, lignes de liste, coques de navigationbackground→surface, color→foreground, border→borderbg + texte + bordure
accentOnglets actifs / lignes de liste courantesbackground+border→primary700, color→background pour le contrastebg + texte + bordure
canvasDalles hero avec fonds rasterRetirer background-image, background→palette backgroundGénéralement le fond uniquement
richTextSites qui exposent des web components de marqueÉmettre les variables CSS requises + correspondance de couleur textuelletexte (parfois + fond)
svgRecolorGlyphes SVG inlinefill/stroke par défaut→currentColor ; clés de palette fill/stroke optionnelles pour une couleur fixeMarquage 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