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

دليل: ارفع أول فيديو لك وشغّله

ثبّت @videohati/node، وارفع ملفًا مُجزّأً، وانتظر حتى يصبح جاهزًا، ثم أنشئ جلسة تشغيل — من البداية إلى النهاية.

ينقلك هذا الدليل من مشروع فارغ إلى فيديو قابل للتشغيل باستخدام حزمة Node الرسمية. تعمل كل خطوة في الوضع التجريبي، فتستطيع المتابعة دون المساس بالبيانات الفعلية.

قبل أن تبدأ

تحتاج إلى:

  • Node.js بإصدار 18 أو أحدث (تعتمد الحزمة على fetch وAbortSignal المدمجين).
  • مفتاح واجهة برمجية تجريبي للمشروع. أنشئه من لوحة التحكم ضمن المشروع ← مفاتيح الواجهة البرمجية. يبدأ المفتاح التجريبي بـ vh_test_.
  • ملف فيديو قصير للرفع، مثل lecture-01.mp4.

احتفظ بمفتاح الواجهة البرمجية على الخادم. فهو مرتبط بالمشروع ويمنح صلاحية الكتابة. لا تُرسل مفتاح vh_live_ أو vh_test_ إلى المتصفح أبدًا.

1. ثبّت الحزمة

npm install @videohati/node

2. هيّئ العميل

يتبع الوضع بادئة المفتاح: مفتاح vh_test_ يضع العميل في الوضع التجريبي تلقائيًا.

import { Videohati } from "@videohati/node";

const videohati = new Videohati({
  apiKey: process.env.VIDEOHATI_API_KEY, // vh_test_...
});

console.log(videohati.mode); // "test"

3. ارفع ملفًا مُجزّأً

ينفّذ videos.upload() تدفّق الرفع المُجزّأ كاملًا في استدعاء واحد: ينشئ الفيديو، ويفتح جلسة رفع، ويرسل كل جزء عبر PUT إلى نقطة الرفع، ثم يكمل الرفع. مرّر مسار ملف، أو Uint8Array/Buffer، أو Blob/File.

const uploaded = await videohati.videos.upload("./lecture-01.mp4", {
  onProgress: ({ partsCompleted, totalParts }) => {
    console.log(`Uploaded part ${partsCompleted}/${totalParts}`);
  },
});

console.log(uploaded.videoId); // 01JZ9WV3N8GQ5T2M7K4C6XBARH
console.log(uploaded.state); // "uploaded"

تريد تحكّمًا يدويًا بدل المساعد ذي الاستدعاء الواحد؟ يتوفّر التدفّق نفسه عبر videos.create() وvideos.startUpload() ثم طلبات PUT لكل جزء و videos.completeUpload().

4. انتظر حتى يصبح الفيديو جاهزًا

بعد اكتمال الرفع يجري الترميز في الخلفية. استعلم عن الفيديو عبر videos.waitForState() حتى يبلغ الحالة ready (أو failed).

const video = await videohati.videos.waitForState(uploaded.videoId, {
  targetStates: ["ready", "failed"],
});

if (video.state === "failed") {
  throw new Error(`Encoding failed: ${video.errorMessage ?? video.errorCode}`);
}

console.log("Video is ready to stream.");

5. أنشئ جلسة تشغيل

تُنشئ جلسة التشغيل رابط بيان HLS موقّعًا قصير العمر مع sessionToken للمشغّل. أنشئها من جانب الخادم وسلّم الجلسة وحدها — لا مفتاح الواجهة البرمجية — إلى الصفحة.

const session = await videohati.playback.createSession({
  videoId: video.id,
  viewerDisplayText: "[email protected]", // يظهر في العلامة المائية
});

console.log(session.manifestUrl); // رابط master.m3u8 موقّع
console.log(session.sessionToken); // مرّره إلى المشغّل

تتضمّن الاستجابة كل ما يحتاجه المشغّل:

الحقلالمعنى
manifestUrlرابط قائمة تشغيل HLS الرئيسية الموقّع.
sessionTokenرمز ملكية الجلسة للمشغّل المُضمَّن.
heartbeatIntervalSecondsعدد الثواني بين كل إعادة تأكيد للجلسة.
expiresAtوقت انتهاء صلاحية الجلسة ورابطها الموقّع.

6. ضمّن المشغّل

سلّم videoId وprojectId وsessionToken إلى مشغّل الويب. تقرأ الحزمة المستقلّة عن أُطر العمل هذه القيم من سمات data-:

<script src="https://cdn.videohati.com/player.js" async></script>
<div
  data-videohati-video-id="01JZ9WV3N8GQ5T2M7K4C6XBARH"
  data-videohati-project-id="01JZ9WV3N8GQ5T2M7K4C6XBARP"
  data-videohati-session-token="01JZ9WV3N8GQ5T2M7K4C6XBARK.1781485200.bXktbWFj"
></div>

ولتطبيق React، راجع تضمين مشغّل فيديوهاتي في تطبيق Next.js 15.

السكربت الكامل

import { Videohati } from "@videohati/node";

async function main() {
  const videohati = new Videohati({ apiKey: process.env.VIDEOHATI_API_KEY });

  const uploaded = await videohati.videos.upload("./lecture-01.mp4", {
    onProgress: ({ partsCompleted, totalParts }) =>
      console.log(`Uploaded part ${partsCompleted}/${totalParts}`),
  });

  const video = await videohati.videos.waitForState(uploaded.videoId);
  if (video.state === "failed") {
    throw new Error(`Encoding failed: ${video.errorMessage ?? video.errorCode}`);
  }

  const session = await videohati.playback.createSession({
    videoId: video.id,
    viewerDisplayText: "[email protected]",
  });

  console.log("Manifest:", session.manifestUrl);
  console.log("Session token:", session.sessionToken);
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});