🔌 Panduan pengembangan adapter
Adapter ForcedSkin ditulis sebagai formula JSON deklaratif ( forcedskin-adapter-formula/v1 ) yang menjelaskan hostname target dan lapisan selektor yang diwarnai. Server hanya menyimpan JSON; ekstensi membawa interpreter tetap yang menerapkan aturan pewarnaan — tidak pernah JavaScript sembarang.
Cara kerja
Mesin inti mulai dengan overlay variabel CSS + gaya inline untuk pewarnaan dasar.
Saat hostname cocok, adapter berjalan menaik menurut prioritas — semakin kecil angkanya, semakin dulu interpreter dijalankan (adapter situs yang disarankan memakai 100).
Setiap adapter menyesuaikan node target lewat helper engineApi yang diekspos; lewati overlay transparan / tumpukan pemutar sesuai catatan praktik terbaik.
Runtime sudah mengamati delta DOM dan menerapkan ulang adapter secara tertahan — Anda tidak perlu boilerplate MutationObserver.
Formula datang dari GET /api/pub/extension-adapters ; blob JSON setiap catatan di-cache secara lokal. Memperbarui salinan di portal berlaku setelah pengguna menyegarkan adapter atau membuka ulang peramban — tanpa instal ulang.
Contoh 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"]
}
]
}Formula adapter forcedskin-adapter-formula/v1
JSON yang dikirim harus lolos validasi server — skema akar seperti ini:
| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
| schema | string | Wajib | String versi literal forcedskin-adapter-formula/v1 |
| id | string | Wajib | Id adapter logis — biasanya nama kode situs, mis. bilibili |
| priority | number | Opsional | Urutan eksekusi (menaik). Adapter khusus situs biasanya memakai 100 |
| match.hostname | Rule[] | Wajib | Array objek aturan hostname (lihat tabel di bawah) |
| layers | Layer[] | Wajib | Lapisan pewarnaan berurutan — jenis didokumentasikan di tabel lapisan |
Aturan match.hostname
| Operator | Arti |
|---|---|
| equals | Hostname sama dengan value (tidak peka huruf besar/kecil) |
| suffixDomain | Hostname sama dengan value atau diakhiri .value (mencakup example.com dan *.example.com) |
Kunci palet (richText cssVars / color)
| Field | Deskripsi |
|---|---|
| background | Latar halaman |
| foreground | Teks utama |
| surface | Isian kartu / panel |
| surfaceMuted | Kontainer redup / isian hover |
| border | Warna tepi |
| muted | Teks sekunder |
| primary500 | Penekanan utama (tautan) dipetakan dari theme primary.500 |
| primary700 | Keadaan primary lebih dalam dipetakan dari primary.700 atau 800 |
Jenis lapisan yang disarankan
Pikir secara semantik — bukan hanya nama elemen. Lihat contoh yang sudah di-commit home/server/seeds/bilibili-adapter.formula.json untuk panduan lengkap.
| Jenis lapisan | Kegunaan | Pemetaan khas | markApplied |
|---|---|---|---|
| surface | Panel, baris daftar, cangkang navigasi | background→surface, color→foreground, border→border | bg + teks + tepi |
| accent | Tab aktif / baris daftar saat ini | background+border→primary700, color→background untuk kontras | bg + teks + tepi |
| canvas | Lempeng hero dengan latar raster | Hapus background-image, background→palette background | Biasanya hanya latar |
| richText | Situs yang mengekspos web component bermerek | Keluarkan variabel CSS yang diperlukan + pemetaan warna teks | teks (kadang + latar) |
| svgRecolor | Glif SVG inline | fill/stroke default→currentColor; kunci palet fill/stroke opsional untuk warna tetap | Penandaan opsional agar tidak mengganggu pembersihan |
Lewati wilayah berisiko: Mesin sudah mengabaikan media, canvas, iframe, lapisan blend/backdrop berat, dan node yang kelasnya mengisyaratkan mask atau overlay — perluas pagar itu untuk chrome pemutar tembus pandang.
Opt-out host: Tandai subtree (mis. pratinjau) dengan data-gts-ignore agar turunannya melewati pewarnaan global.
Kutipan contoh lengkap
{
"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"]
}
]
}Praktik terbaik
JSON harus valid secara ketat
Skema/lapisan/aturan host yang tidak valid ditolak saat tinjauan — lipat contoh minimal dan seed panduan ini sebelum mengirim.
Aktifkan skipOverlayLike pada surface
Selaras dengan pengamanan mesin agar HUD tembus / tumpukan video tidak diratakan menjadi isian padat.
Jangan kirim JavaScript
Field code hanya JSON; ekstensi tidak lagi mengevaluasi string lewat new Function.
Daftar periksa pengiriman
🔐 Masuk sebelum mengirim.
📋 Berikan nama tampilan, domain dipisah koma, dan tempel JSON ke textarea kode adapter.
⏳ Server memvalidasi skema JSON dan aturan keamanan; JavaScript atau kode berisiko lainnya ditolak.
✅ Formula valid dipublikasikan otomatis dan didistribusikan ke pengguna ekstensi yang menyinkronkan adapter.
❌ Selektor terlalu luas atau JSON tidak valid akan dikembalikan — perbaiki dan kirim ulang.
Format domain target
siteDomain adalah daftar yang ditampilkan; pencocokan sebenarnya memakai match.hostname seperti:
[
{ "op": "equals", "value": "bilibili.com" },
{ "op": "suffixDomain", "value": "bilibili.com" }
]Siap? Buka galeri adapter dan kirim JSON Anda.
🔌 Kirim adapter