حزمة React
حزمة @videohati/react الرسمية — مكوّن VideohatiPlayer مع خطّافات الرفع والبيانات الوصفية وتسليمات Webhook لـ React 18+ وNext.js.
تمنحك @videohati/react مكوّن <VideohatiPlayer> الذي يغلّف
@videohati/player، مع خطّافات لرفع المتصفح والبيانات
الوصفية للفيديو وتسليمات Webhook. الإصدار 1.0.0-rc.0.
التثبيت
React الإصدار 18 فأحدث. المشغّل تبعية نظير، فثبّت الاثنين.
npm install @videohati/react @videohati/playerالمزوّد
غلّف تطبيقك مرة واحدة. يشارك VideohatiProvider أصل واجهة API — ومفتاح API
اختياريًا للنماذج الأولية — مع الخطّافات.
| الخاصية | الافتراضي | ماذا تفعل |
|---|---|---|
baseUrl | https://api.videohati.com | أصل واجهة API. |
apiKey | — | مفتاح API اختياري لطلبات المتصفح. غير مستحسَن. |
children | — | تطبيقك. |
import { VideohatiProvider } from "@videohati/react";
<VideohatiProvider baseUrl="https://api.videohati.com">
<App />
</VideohatiProvider>;تُعيد useVideohatiConfig() القيمة الحالية { baseUrl, apiKey? } عند الحاجة.
لا تُرسل مفتاح API حيًّا إلى المتصفح أبدًا. يستخدم التشغيل رموز جلسات مُنشأة في
الخادم. خاصية apiKey للنماذج الأولية بمفاتيح vh_test_ فقط.
تشغيل فيديو
يأتي sessionToken من POST /v1/playback/sessions في الخادم — استخدم
@videohati/node في معالِج المسار أو في إجراء الخادم.
"use client";
import { VideohatiPlayer } from "@videohati/react";
export function Lesson({ sessionToken }: { sessionToken: string }) {
return (
<VideohatiPlayer
videoId="01JZ9WV3N8GQ5T2M7K4C6XBARH"
projectId="01JZ9WV3N8GQ5T2M7K4C6XBARF"
sessionToken={sessionToken}
autoplay="muted"
lang="ar"
width={640}
height={360}
onStateChange={(state) => console.log(state)}
/>
);
}خصائص VideohatiPlayerProps:
| الخاصية | النوع | ماذا تفعل |
|---|---|---|
videoId | string (مطلوب) | الفيديو المراد تشغيله. |
projectId | string (مطلوب) | المشروع المالك للفيديو. |
sessionToken | string (مطلوب) | رمز من جلسة تشغيل مُنشأة في الخادم. |
autoplay | boolean | "muted" | "muted" يشغّل تلقائيًا مكتومًا؛ true يحاول بلا كتم؛ الافتراضي false. |
width | number | عرض المشغّل بالبكسل. |
height | number | ارتفاع المشغّل بالبكسل. |
lang | "ar" | "en" | لغة الواجهة. الافتراضي العربية. |
viewerText | string | نص العلامة المائية؛ يعود إلى نص المشاهد في الجلسة. |
apiOrigin | string | تجاوز أصل واجهة API (بيئة التجهيز، تجاوزات محلية). |
className | string | صنف على عنصر الحاوية. |
style | CSSProperties | نمط مضمّن على الحاوية. |
onStateChange | (state) => void | يُطلَق عند كل تغيّر في حالة التشغيل. |
onError | ({ code, message }) => void | يُطلَق عند خطأ في التشغيل. |
onTimeUpdate | ({ currentTime, duration }) => void | يُطلَق مع حركة مؤشّر التشغيل. |
playerRef | (player | null) => void | يستقبل كائن المشغّل الأساسي — استدعِ عليه play/seek/setQuality. |
الرفع من المتصفح
useVideohatiUpload({ projectId?, partConcurrency? }) يُنفّذ تدفّق الرفع المُجزّأ
نفسه في حزمة Node (إنشاء ← بدء ← رفع الأجزاء ← إكمال)، بثلاثة أجزاء متوازية
افتراضيًا.
يُعيد:
| الحقل | النوع | ما هو |
|---|---|---|
upload | (file: File) => Promise<UploadResult | null> | يبدأ الرفع. |
progress | UploadProgress | null | عدّاد حيّ للبايتات والأجزاء. |
state | "idle" | "creating" | "uploading" | "completing" | "done" | "error" | المرحلة الحالية. |
error | { status, code, message } | null | الإخفاق، إن وُجد. |
video | UploadResult | null | الفيديو المكتمل، حين تصبح state هي done. |
reset | () => void | يُعيد الخطّاف إلى idle (يُتجاهَل أثناء الانشغال). |
"use client";
import { useVideohatiUpload } from "@videohati/react";
function Uploader({ projectId }: { projectId: string }) {
const { upload, progress, state, error, video, reset } = useVideohatiUpload({
projectId,
});
return (
<form onSubmit={(e) => e.preventDefault()}>
<input
type="file"
accept="video/*"
disabled={state === "creating" || state === "uploading" || state === "completing"}
onChange={(e) => e.target.files?.[0] && upload(e.target.files[0])}
/>
{progress && (
<progress value={progress.uploadedBytes} max={progress.totalBytes} />
)}
{state === "done" && <p>تم الرفع: {video?.videoId}</p>}
{state === "error" && <p role="alert">{error?.message}</p>}
{(state === "done" || state === "error") && (
<button type="button" onClick={reset}>
رفع فيديو آخر
</button>
)}
</form>
);
}قراءة البيانات الوصفية للفيديو
useVideohatiVideo(videoId, { projectId?, pollIntervalMs? }) يقرأ فيديو ويُبقيه
محدّثًا.
import { useVideohatiVideo } from "@videohati/react";
const { video, error, isLoading, refresh } = useVideohatiVideo(videoId, {
projectId,
});يُخزَّن عبر عمليات التركيب، ويُعاد التحقّق منه عند التركيب، ويُستقصى كل 5 ثوانٍ
ما دامت video.state هي uploading أو uploaded أو encoding — فيتحدّث الفيديو
قيد المعالجة تلقائيًا. اضبط pollIntervalMs: 0 لتعطيل الاستقصاء. وتُعيد
clearVideohatiVideoCache() ضبط الذاكرة المؤقتة المشتركة.
تسليمات Webhook
useWebhookDeliveries(projectId, endpointId, { state?, eventType?, limit? })
يقرأ صفحة واحدة من محاولات التسليم لنقطة نهاية Webhook.
import { useWebhookDeliveries } from "@videohati/react";
const { deliveries, nextCursor, error, isLoading, refresh } = useWebhookDeliveries(
projectId,
endpointId,
{ limit: 20 },
);بنفس التخزين المؤقت لـ useVideohatiVideo. وتُعيد clearWebhookDeliveriesCache()
ضبط ذاكرته المؤقتة.
موجّه Next.js App Router
المشغّل وكل خطّاف مخصّصان للعميل فقط — ضعها في مكوّن يبدأ بـ "use client". سُكّ
رمز الجلسة في الخادم (معالِج مسار أو إجراء خادم) بـ @videohati/node، ثم مرّره
خاصيةً. النمط الكامل في دليل التضمين مع Next.js.
معالجة الأخطاء
تكشف الخطّافات الأخطاء بصيغة { status, code, message } — وcode رمز الآلة من
واجهة API (مثل account_not_approved وvideo_not_found). ويُبلّغ المشغّل عن
أخطاء التشغيل عبر onError.
التحقّق من Webhooks
يتمّ التحقّق من توقيع Webhook في الخادم — استخدم verifyWebhookSignature من
@videohati/node في معالِج المسار. انظر دليل Webhooks.