# مرجع منشئ الويدجت

> مرجع الكود لويدجت منشئ الويدجت في KickBot: كل أسماء أحداث Kick وبياناتها، و globalValues و userVariables، وأدوات الدردشة، وطريقة تشغيل المعاينة للكود.

Source: https://kickbot.com/ar/docs/widgets/widget-builder-reference

تسرد هذه الصفحة ما يستطيع الكود الخاص بك استخدامه في ويدجت من [منشئ الويدجت](https://kickbot.com/ar/docs/widgets/widget-builder) في KickBot: أحداث `widgetEvent`، والكائن `globalValues`، والكائن `userVariables`، والأدوات المساعدة في `window.kickbotWidget`. كل ويدجت هو HTML و CSS و JavaScript عادية تعمل كمصدر متصفح (browser source) في OBS. يتصل KickBot بـ Kick نيابةً عنك ويرسل الأحداث إلى الكود الخاص بك.

## كيف يعمل الويدجت

عندما يفتح OBS رابط الويدجت، يقوم KickBot بما يلي:

1. يحمّل صفحة الويدجت بخلفية شفافة.
2. يضيف CSS الخاص بك في عنصر `<style>` ويضع HTML الخاص بك في الصفحة.
3. يحمّل بيانات قناتك من Kick (عدد المتابعين، وعدد المشاهدين، وحالة البث، والدردشة الأخيرة) إلى `globalValues`.
4. يشغّل JavaScript الخاص بك. يعمل مرة واحدة، بعد الخطوة 3، فيكون `globalValues` جاهزًا عندما يبدأ الكود.
5. يرسل الأحداث المباشرة إلى الكود الخاص بك كأحداث `widgetEvent` على `document`.

يستطيع JavaScript الخاص بك قراءة كائنين دون استيراد أي شيء: `globalValues` و `userVariables`. الأدوات المساعدة موجودة في `window.kickbotWidget`.

الحدود:

| العنصر | الحد |
| --- | --- |
| العرض والارتفاع | تُضبط في **الإعدادات الأساسية**. الويدجت الفارغ الجديد بحجم 800 × 600. تقبل نافذة ويدجت جديد حتى 7680 × 4320. |
| HTML و CSS و JavaScript | حتى 2,000,000 حرف لكل ملف |
| اسم الويدجت | حتى 500 حرف |
| ملفات متغيرات المستخدم | حتى 25 ميغابايت لكل ملف |
| ويدجت المنشئ في الخطة المجانية | 10 (بلا حد في Premium) |

## الاستماع إلى الأحداث

أضف مستمعًا واحدًا لـ `widgetEvent` على `document`. لكل حدث `event.detail` فيه ثلاثة حقول:

| الحقل | النوع | القيمة |
| --- | --- | --- |
| `event_name` | string | الحدث، مثلًا `followEvent` |
| `source` | string | دائمًا `kick` |
| `data` | object | بيانات الحدث (انظر أدناه) |

```javascript
document.addEventListener('widgetEvent', (event) => {
    const { event_name, data } = event.detail;

    if (event_name === 'followEvent') {
        showAlert(data.user.username + ' followed!');
    }
    if (event_name === 'subEvent') {
        showAlert(data.username + ' subscribed for ' + data.months + ' months');
    }
});
```

### قائمة الأحداث

| اسم الحدث | متى يحدث | زر الاختبار |
| --- | --- | --- |
| `subEvent` | يشترك مشاهد | Sub |
| `subGiftEvent` | يُهدي مشاهد اشتراكات | Sub مهداة |
| `kicksEvent` | يرسل مشاهد KICKs | KICKs |
| `followEvent` | يتابعك مشاهد | Follow |
| `unfollowEvent` | يلغي مشاهد متابعتك | Unfollow |
| `chatMessageEvent` | تُرسل رسالة في الدردشة | رسالة |
| `chatMessageDeletedEvent` | يحذف مشرف رسالة | رسالة محذوفة |
| `chatMessagePinnedEvent` | تُثبَّت رسالة | رسالة مثبتة |
| `chatMessageUnpinnedEvent` | تُزال الرسالة المثبتة | إلغاء تثبيت رسالة |
| `chatClearedEvent` | يمسح مشرف الدردشة | تم مسح الدردشة |
| `followerCountUpdatedEvent` | يرسل Kick عددًا جديدًا للمتابعين | تحديث عدد المتابعين |
| `subCountUpdatedEvent` | تغيّر عدد المشتركين على Kick | تحديث عدد الـ subs |
| `viewerCountUpdatedEvent` | يرسل Kick عددًا جديدًا للمشاهدين | تحديث عدد المشاهدين |
| `raidEvent` | تقوم قناة أخرى برايد (استضافة) عليك | Raid |
| `streamOnline` | يبدأ بثك | البث متصل |
| `streamOffline` | ينتهي بثك | البث منقطع |

لا يوجد حدث للإكراميات. لتنبيهات الإكراميات، استخدم [ويدجت تنبيهات الإكراميات](https://kickbot.com/ar/docs/tipping/tip-alerts).

### بيانات الأحداث

هذه هي البيانات في `event.detail.data`. تطابق الأحداث التجريبية في المحرر. قد تحتوي الأحداث الحقيقية على حقول أكثر. الأسماء والأرقام والمعرّفات هنا أمثلة.

`subEvent`

```javascript
{
    months: 1,
    username: 'viewer_one',
    chatroom_id: 3847194
}
```

`subGiftEvent`

```javascript
{
    chatroom_id: 3847194,
    gifted_usernames: ['viewer_one', 'viewer_two', 'viewer_three'],
    gifter_username: 'big_gifter'
}
```

`kicksEvent`

```javascript
{
    message: 'Great stream!',
    sender: { id: 12345678, username: 'viewer_one', username_color: '#93EBE0' },
    gift: {
        gift_id: 'full_send',
        name: 'Full Send',
        amount: 100,
        type: 'BASIC',
        tier: 'BASIC',
        character_limit: 0,
        pinned_time: 0
    },
    channel: 'channel_3984507'
}
```

`followEvent` و `unfollowEvent` (الشكل نفسه؛ `followers_count` هو العدد الجديد)

```javascript
{
    id: 'd4e5f6a7-89b0-12c3-d456-78901e2f3a4b',
    channel: { id: 3984507, slug: 'kickbotdev' },
    user: { id: 14873539, slug: 'viewer_one', username: 'viewer_one' },
    followers_count: 36,
    created_at: '2024-05-13T22:19:07+00:00'
}
```

`chatMessageEvent`

```javascript
{
    id: '85c884b3-7377-478c-b6aa-22b7db752b93',
    chatroom_id: 3974112,
    content: 'hello [emote:37226:KEKW]',
    type: 'message',
    created_at: '2024-05-13T22:29:52+00:00',
    sender: {
        id: 4063326,
        username: 'viewer_one',
        slug: 'viewer_one',
        identity: {
            color: '#72ACED',
            badges: [{ type: 'subscriber', text: 'Subscriber', count: 3 }]
        }
    }
}
```

إيموتات Kick موجودة في `content` بالشكل `[emote:ID:NAME]`. استخدم `createChatMessageFragment` (راجع [اعرض نص الدردشة بأمان](#show-chat-text-safely)) لتحويلها إلى صور.

`chatMessageDeletedEvent`

```javascript
{
    id: '9cd3788a-ecd2-4051-a162-a7ea9be8ce7a',
    message: { id: '89d6be86-63db-4581-922e-14a6c4a9c2e6' }
}
```

استخدم `data.message.id` لتجد الرسالة التي عرضتها وتزيلها.

`chatMessagePinnedEvent` (لـ `data.message` شكل بيانات `chatMessageEvent` نفسه)

```javascript
{
    message: {
        id: '5d798a38-ad17-45e4-8169-bda2faa85b79',
        chatroom_id: 3974112,
        content: 'This is a pinned message!',
        type: 'message',
        created_at: '2024-05-13T22:30:41+00:00',
        sender: { id: 4063326, username: 'kickbotdev', slug: 'kickbotdev', identity: { color: '#72ACED', badges: [] } }
    }
}
```

`chatMessageUnpinnedEvent`: قيمة `data` مصفوفة فارغة (`[]`).

`chatClearedEvent`

```javascript
{ id: '47e3596f-0274-46e0-85b1-029fa3bfc5ea' }
```

`followerCountUpdatedEvent` (لاحظ `followersCount` بصيغة camelCase)

```javascript
{ followersCount: 1532, channel_id: 4599, created_at: 1715639984 }
```

`subCountUpdatedEvent`

```javascript
{ subscriber_count: 184, channel_id: 4599 }
```

`viewerCountUpdatedEvent`

```javascript
{ viewer_count: 320, channel_id: 5937485 }
```

`raidEvent`

```javascript
{
    chatroom_id: 839485,
    optional_message: 'gg stream',
    number_viewers: 150,
    host_username: 'raiding_channel'
}
```

`streamOnline`

```javascript
{
    livestream: {
        id: 3984507,
        channel_id: 3984507,
        session_title: 'Test stream!',
        created_at: '2024-05-13T22:30:41+00:00'
    }
}
```

`streamOffline`

```javascript
{
    livestream: {
        id: 3984507,
        channel: { id: 3984507, is_banned: false }
    }
}
```

## القيم العامة

يحمل `globalValues` الحالة الحالية لقناتك. يملؤه KickBot قبل تشغيل الكود ويحدّثه مع وصول الأحداث. استخدمه لرسم الويدجت في البداية، قبل وصول أي حدث.

```javascript
globalValues = {
    subCount: 184,
    followerCount: 1532,
    viewerCount: 320,
    lastFollower: { /* the last follow */ },
    lastSub: { /* the last sub, for example { username, months } */ },
    lastGiftedSub: { /* the last gift, for example { gifter_username, gifted_usernames } */ },
    chatMessages: [ /* chatMessageEvent payloads */ ],
    streamerInfo: {
        kick: {
            username: 'KickBotDev',
            slug: 'kickbotdev',
            profile_picture: 'https://files.kick.com/images/user/.../fullsize.webp',
            user_id: '4063326',
            channel_id: '3984507',
            chatroom_id: '3974112',
            bio: 'Channel bio',
            subscriber_badges: [ /* your channel's sub badges from Kick */ ]
        }
    },
    currentStream: {
        is_live: true,
        title: 'Stream title',
        started_at: '2026-10-24 18:00:00'
    }
}
```

| القيمة | كيف تتحدّث |
| --- | --- |
| `subCount` | تُحمَّل من Kick. تزيد 1 مع كل `subEvent` و 1 مع كل اشتراك مُهدى، ويضبطها `subCountUpdatedEvent` من جديد. |
| `followerCount` | تُحمَّل من Kick. يضبطها `followEvent` و `unfollowEvent` و `followerCountUpdatedEvent`. |
| `viewerCount` | تُحمَّل من Kick (0 عندما لا تبث). يضبطها `viewerCountUpdatedEvent`. |
| `lastFollower`، `lastSub`، `lastGiftedSub` | آخر واحد رصده KickBot في قناتك، أو `null`. يحدّثها الحدث المطابق. |
| `chatMessages` | الدردشة الأخيرة من Kick عند تحميل الويدجت، ثم كل رسالة جديدة. تحتفظ بأحدث 100 رسالة. يفرغها `chatClearedEvent`. لإخفاء الرسائل المحذوفة، تعامل مع `chatMessageDeletedEvent` في الكود الخاص بك. |
| `streamerInfo.kick` | ملفك الشخصي على Kick. لا يتغيّر أثناء عمل الويدجت. |
| `currentStream` | تُحمَّل من Kick عند تحميل الويدجت. لا يحدّثها `streamOnline` ولا `streamOffline`. استمع إلى هذين الحدثين إذا احتجت إلى حالة البث المباشر. |

## متغيرات المستخدم

متغيرات المستخدم هي الإعدادات التي يراها المذيعون عندما يفتحون ويدجتك في الويدجت المحفوظة. تضيفها تحت **متغيرات المستخدم** في المحرر. في الكود، اقرأ القيمة بـ `userVariables.<variable name>.value`.

```javascript
const goal = Number(userVariables.follower_goal.value);
document.body.style.color = userVariables.text_color.value;
```

حقول المتغير:

| الحقل | ما هو |
| --- | --- |
| العنوان | التسمية التي يراها المذيعون. |
| اسم المتغير | الاسم في الكود. حروف وأرقام و `_` فقط. لا يمكنك تغييره بعد إنشاء المتغير. |
| Tooltip | نص مساعدة إضافي تحت العنوان. |
| نوع المتغير | راجع الجدول أدناه. |
| القيمة الافتراضية | القيمة قبل أن يغيّرها المذيع. يمكن أن تكون فارغة. |
| مطلوب | يجب على المذيعين إدخال قيمة قبل أن يستطيعوا الحفظ. |

| النوع | ما يراه المذيع | `value` في الكود |
| --- | --- | --- |
| نص | مربع نص | سلسلة نصية (string) |
| رقم | مربع رقم | رقم أو سلسلة نصية رقمية. استخدم `Number()` للأمان. |
| لون | أداة اختيار اللون | سلسلة لون hex، مثلًا `#ffffff` |
| قائمة منسدلة | قائمة بخياراتك | الخيار المختار كسلسلة نصية. الافتراضي هو الخيار الأول. |
| مفتاح تبديل | مفتاح تشغيل وإيقاف | `true` أو `false` |
| صورة/GIF | مربع رابط وزر رفع | رابط الملف |
| فيديو | مربع رابط وزر رفع | رابط الملف |
| صوت | مربع رابط وزر رفع | رابط الملف |

يخزّن KickBot الملفات المرفوعة، وتكون `value` رابط الملف. استخدم القائمة بجانب المتغير لتحريكه للأعلى أو للأسفل، أو تعديله، أو حذفه. الترتيب في المحرر هو الترتيب الذي يراه المذيعون.

## اعرض نص الدردشة بأمان

تعامل مع كل حقل في الأحداث وكل متغير مستخدم كنص من شخص غريب. ينظّف KickBot نص الدردشة والأحداث قبل أن يصل إلى الكود، فيكون آمنًا كنص HTML، لكن ليس كرابط أو CSS أو سكربت. لا تضع حقول الأحداث الخام في `innerHTML`. استخدم هذه الأدوات المساعدة:

| الأداة المساعدة | ماذا تفعل |
| --- | --- |
| `window.kickbotWidget.createChatMessageFragment(content, font_size)` | تُرجع `DocumentFragment` فيه عُقد نصية وصور إيموتات Kick. حجم الإيموتات `font_size + 3` بكسل. القيمة الافتراضية لـ `font_size` هي 20. |
| `window.kickbotWidget.createTextNode(value)` | تُرجع عقدة نصية لأي قيمة. |
| `window.kickbotWidget.escapeHtmlText(value)` | تهرّب النص لاستخدامه بين وسوم HTML عندما يجب أن تبني سلسلة HTML. لا تستخدمها للروابط أو CSS أو السكربت. |

```javascript
document.addEventListener('widgetEvent', (event) => {
    if (event.detail.event_name !== 'chatMessageEvent') return;
    const data = event.detail.data;

    const line = document.createElement('div');
    line.id = 'msg-' + data.id;
    const name = document.createElement('strong');
    name.style.color = data.sender.identity.color;
    name.append(window.kickbotWidget.createTextNode(data.sender.username + ': '));
    line.append(name);
    line.append(window.kickbotWidget.createChatMessageFragment(data.content, 20));
    document.getElementById('chat').append(line);
});
```

لأي نص آخر، استخدم `textContent` أو `createTextNode`.

## المعاينة

تعمل المعاينة في المحرر مثل OBS، مع بعض الفروق للاختبار:

- عندما تغيّر الكود أو متغير مستخدم، تشغّل المعاينة JavaScript الخاص بك من جديد. يزيل KickBot أولًا مستمعات `widgetEvent` من التشغيل السابق. المؤقتات من `setInterval` و `setTimeout` لا تُزال، فاضغط على زر إعادة التحميل إذا تراكمت.
- عندما تغيّر العرض أو الارتفاع، يُعاد تحميل المعاينة.
- الأحداث التجريبية تصل إلى المعاينة فقط. يضيف **Follow** التجريبي 1 إلى `globalValues.followerCount`، ويطرح **Unfollow** 1. يرسل **تحديث عدد المشاهدين** رقمًا نموذجيًا. يزيل **رسالة محذوفة** رسالة عشوائية من دردشة المعاينة.
- إذا لم يكن لقناتك بعد آخر متابع أو آخر اشتراك أو آخر اشتراك مُهدى، تستخدم المعاينة بيانات نموذجية لـ `lastFollower` و `lastSub` و `lastGiftedSub`.
- لرؤية مخرجات `console.log` والأخطاء، اضغط على زر الفتح في نافذة منفصلة وافتح أدوات المطوّر في تلك النافذة.

## مثال: هدف المتابعين

هذا هدف متابعين قصير. يستخدم مستمع أحداث، و `globalValues`، ومتغيرَي مستخدم: `follower_goal` (رقم) و `bar_color` (لون).

HTML:

```html
<div class="goal">
    <span id="count"></span> / <span id="target"></span>
    <div class="bar"><div class="fill"></div></div>
</div>
```

CSS:

```css
body { margin: 0; font-family: Arial, sans-serif; color: #fff; }
.goal { padding: 12px; background: #100c28; border-radius: 16px; font-size: 32px; font-weight: bold; }
.bar { height: 24px; margin-top: 8px; background: #3d3957; border-radius: 12px; overflow: hidden; }
.fill { height: 100%; width: 0; transition: width 0.3s ease; }
```

JavaScript:

```javascript
const target = Number(userVariables.follower_goal.value) || 100;
document.getElementById('target').textContent = target;
document.querySelector('.fill').style.background = userVariables.bar_color.value;

function update(count) {
    document.getElementById('count').textContent = count;
    document.querySelector('.fill').style.width = Math.min((count / target) * 100, 100) + '%';
}

document.addEventListener('widgetEvent', (event) => {
    const { event_name, data } = event.detail;
    if (event_name === 'followEvent' || event_name === 'unfollowEvent') update(data.followers_count);
    if (event_name === 'followerCountUpdatedEvent') update(data.followersCount);
});

update(globalValues.followerCount);
```

لنسخة كاملة بإعدادات أكثر، ابدأ ويدجت جديدًا من قالب **Simple Follower Goal**.

## نصائح

- ارسم الحالة الأولى من `globalValues`، ثم غيّرها مع الأحداث. الويدجت الذي ينتظر حدثًا يبدو فارغًا حتى يحدث شيء.
- لا تعرض الويدجت المحفوظة أزرار الاختبار إلا لأسماء الأحداث الموجودة في JavaScript الخاص بك. اكتب اسم الحدث كاملًا (مثلًا `'followEvent'`) في الكود ليستطيع المذيعون اختبار ويدجتك.
- اترك الخلفية شفافة إلا إذا كانت الخلفية جزءًا من التصميم، ليظهر الويدجت فوق المشهد.
- يمكنك أيضًا إدارة ويدجت المنشئ باستخدام KickBot API. راجع [مرجع API للويدجت](https://kickbot.com/docs/api/reference/widgets).
