🔌 دليل تطوير المحوّلات
تُكتب محوّلات ForcedSkin كـ صيغ JSON تصريحية ( forcedskin-adapter-formula/v1 ) تصف أسماء المضيف المستهدفة وطبقات المحددات للتلوين. يخزّن الخادم JSON فقط؛ وتشحن الإضافة مفسّراً ثابتاً يطبق قواعد الطلاء — وليس JavaScript عشوائياً أبداً.
كيف يعمل
يبدأ المحرّك الأساسي بطبقات متغيرات CSS وأنماط مضمّنة لإعادة التلوين الأساسية.
عندما يطابق اسم مضيف، تعمل المحوّلات تصاعدياً حسب الأولوية — كلما صغر الرقم نُفّذ المفسّر أبكر (محوّلات المواقع الموصى بها تستخدم 100).
يعدّل كل محوّل العقد المستهدفة عبر مساعدات engineApi المكشوفة؛ تجاوز الطبقات الشفافة / مكدسات المشغّل وفق أفضل الممارسات.
يراقب وقت التشغيل بالفعل دلتا DOM ويعيد تطبيق المحوّلات بمعدل محدود — لا تحتاج إلى MutationObserver.
تصل الصيغ من GET /api/pub/extension-adapters ؛ يُخزَّن JSON لكل سجل محلياً. يسري تحديث نسخة البوابة عندما يحدّث المستخدمون المحوّلات أو يعيدون فتح المتصفح — دون إعادة تثبيت.
مثال أدنى
{
"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"]
}
]
}صيغة المحوّل forcedskin-adapter-formula/v1
يجب أن يمر JSON المُرسل بتحقق الخادم — يبدو المخطط الجذري هكذا:
| الحقل | النوع | مطلوب | الوصف |
|---|---|---|---|
| schema | string | مطلوب | سلسلة إصدار حرفية forcedskin-adapter-formula/v1 |
| id | string | مطلوب | معرّف المحوّل المنطقي — عادة اسم رمز الموقع، مثال bilibili |
| priority | number | اختياري | ترتيب التنفيذ (تصاعدي). محوّلات المواقع المحددة تستخدم عادة 100 |
| match.hostname | Rule[] | مطلوب | مصفوفة كائنات قواعد اسم المضيف (انظر الجدول أدناه) |
| layers | Layer[] | مطلوب | طبقات طلاء مرتبة — الأنواع موثّقة في جدول الطبقات |
قواعد match.hostname
| المشغّل | المعنى |
|---|---|
| equals | اسم المضيف يساوي value (غير حسّاس لحالة الأحرف) |
| suffixDomain | اسم المضيف يساوي value أو ينتهي بـ .value (يغطي example.com و *.example.com) |
مفاتيح اللوحة (richText cssVars / color)
| الحقل | الوصف |
|---|---|
| background | خلفية الصفحة |
| foreground | النص الأساسي |
| surface | تعبئة البطاقة / اللوحة |
| surfaceMuted | حاويات خافتة / تعبئة التحويم |
| border | لون الحدود |
| muted | نص ثانوي |
| primary500 | تأكيد أساسي (روابط) من theme primary.500 |
| primary700 | حالة primary أعمق من primary.700 أو 800 |
أنواع الطبقات الموصى بها
فكّر دلالياً — لا بأسماء العناصر فقط. انظر المثال المودَع home/server/seeds/bilibili-adapter.formula.json لشرح كامل.
| نوع الطبقة | الغرض | التعيين المعتاد | markApplied |
|---|---|---|---|
| surface | لوحات وصفوف قوائم وأصداف تنقل | background→surface, color→foreground, border→border | خلفية + نص + حدود |
| accent | تبويبات نشطة / صفوف قائمة حالية | background+border→primary700, color→background للتباين | خلفية + نص + حدود |
| canvas | كتل بطولية بخلفيات نقطية | إزالة background-image، background→palette background | عادة الخلفية فقط |
| richText | مواقع تعرض مكوّنات ويب ذات علامة | إصدار متغيرات CSS المطلوبة + تعيين لون النص | نص (أحياناً + خلفية) |
| svgRecolor | رموز SVG مضمّنة | fill/stroke الافتراضي→currentColor؛ مفاتيح لوحة fill/stroke اختيارية للون ثابت | وسم اختياري لتفادي التداخل مع التنظيف |
تجاوز المناطق الخطرة: يتجاهل المحرّك مسبقاً media و canvas و iframe وطبقات المزج/الخلفية الثقيلة والعقد التي توحي فئاتها بأقنعة أو طبقات — وسّع هذه الحواجز لإطار المشغّل الشفاف.
انسحاب المضيف: علّم الأشجار الفرعية (مثل المعاينات) بـ data-gts-ignore حتى تتجاوز نسلها إعادة التلوين العامة.
مقتطف مثال كامل
{
"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"]
}
]
}أفضل الممارسات
يجب أن يتحقق JSON بصرامة
المخطط/الطبقات/قواعد المضيف غير الصالحة تُرفض أثناء المراجعة — اعتمد مثال هذا الدليل الأدنى والبذور قبل الإرسال.
فعّل skipOverlayLike على surface
يتوافق مع حواجز المحرّك حتى لا تُسطَّح واجهات HUD الشفافة / مكدسات الفيديو إلى تعبئة صلبة.
لا ترسل JavaScript أبداً
حقل code هو JSON فقط؛ لم تعد الإضافة تقيّم السلاسل عبر new Function.
قائمة تحقق الإرسال
🔐 سجّل الدخول قبل تقديم إرسال.
📋 قدّم الاسم المعروض والنطاقات مفصولة بفواصل والصق JSON في منطقة كود المحوّل.
⏳ يتحقق الخادم من مخطط JSON وقواعد الأمان؛ يُرفض JavaScript وأي شيفرة خطرة.
✅ تُنشر الصيغ الصالحة تلقائياً وتصل إلى مستخدمي الإضافة الذين يزامنون المحوّلات.
❌ المحددات الواسعة جداً أو JSON غير الصالح يعيدان ملاحظات — صحّح وأعد الإرسال.
صيغة النطاق المستهدف
siteDomain هي القائمة المعروضة؛ المطابقة الفعلية تعتمد على match.hostname مثل:
[
{ "op": "equals", "value": "bilibili.com" },
{ "op": "suffixDomain", "value": "bilibili.com" }
]جاهز؟ افتح معرض المحوّلات وأرسل JSON.
🔌 أرسل محوّلاً