محوّلات المواقعدليل التطوير

🔌 دليل تطوير المحوّلات

تُكتب محوّلات 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 المُرسل بتحقق الخادم — يبدو المخطط الجذري هكذا:

الحقلالنوعمطلوبالوصف
schemastringمطلوبسلسلة إصدار حرفية forcedskin-adapter-formula/v1
idstringمطلوبمعرّف المحوّل المنطقي — عادة اسم رمز الموقع، مثال bilibili
prioritynumberاختياريترتيب التنفيذ (تصاعدي). محوّلات المواقع المحددة تستخدم عادة 100
match.hostnameRule[]مطلوبمصفوفة كائنات قواعد اسم المضيف (انظر الجدول أدناه)
layersLayer[]مطلوبطبقات طلاء مرتبة — الأنواع موثّقة في جدول الطبقات

قواعد 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.

🔌 أرسل محوّلاً