فيديوهاتيالتوثيق

حزمة 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 اختياريًا للنماذج الأولية — مع الخطّافات.

الخاصيةالافتراضيماذا تفعل
baseUrlhttps://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:

الخاصيةالنوعماذا تفعل
videoIdstring (مطلوب)الفيديو المراد تشغيله.
projectIdstring (مطلوب)المشروع المالك للفيديو.
sessionTokenstring (مطلوب)رمز من جلسة تشغيل مُنشأة في الخادم.
autoplayboolean | "muted""muted" يشغّل تلقائيًا مكتومًا؛ true يحاول بلا كتم؛ الافتراضي false.
widthnumberعرض المشغّل بالبكسل.
heightnumberارتفاع المشغّل بالبكسل.
lang"ar" | "en"لغة الواجهة. الافتراضي العربية.
viewerTextstringنص العلامة المائية؛ يعود إلى نص المشاهد في الجلسة.
apiOriginstringتجاوز أصل واجهة API (بيئة التجهيز، تجاوزات محلية).
classNamestringصنف على عنصر الحاوية.
styleCSSPropertiesنمط مضمّن على الحاوية.
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>يبدأ الرفع.
progressUploadProgress | nullعدّاد حيّ للبايتات والأجزاء.
state"idle" | "creating" | "uploading" | "completing" | "done" | "error"المرحلة الحالية.
error{ status, code, message } | nullالإخفاق، إن وُجد.
videoUploadResult | 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.