إنشاء تطبيق دفق فيديو باستخدام Nuxt.js و Node و Express
نشرت: 2022-03-10تعمل مقاطع الفيديو مع التدفقات. هذا يعني أنه بدلاً من إرسال الفيديو بالكامل مرة واحدة ، يتم إرسال الفيديو كمجموعة من الأجزاء الأصغر التي تشكل الفيديو الكامل. وهذا يفسر سبب تخزين مقاطع الفيديو مؤقتًا عند مشاهدة مقطع فيديو على نطاق عريض بطيء لأنه يقوم بتشغيل الأجزاء التي تلقاها فقط ويحاول تحميل المزيد.
هذه المقالة للمطورين الراغبين في تعلم تقنية جديدة من خلال بناء مشروع فعلي: تطبيق دفق فيديو مع Node.js كخلفية و Nuxt.js كعميل.
- Node.js هو وقت تشغيل يُستخدم لإنشاء تطبيقات سريعة وقابلة للتطوير. سنستخدمه للتعامل مع جلب مقاطع الفيديو ودفقها ، وإنشاء صور مصغرة لمقاطع الفيديو ، وتقديم التسميات التوضيحية والترجمات المصاحبة لمقاطع الفيديو.
- Nuxt.js هو إطار عمل Vue.js يساعدنا في إنشاء تطبيقات Vue.js التي يعرضها الخادم بسهولة. سنستهلك واجهة برمجة التطبيقات الخاصة بنا لمقاطع الفيديو وسيكون لهذا التطبيق طريقتان لعرض: قائمة بمقاطع الفيديو المتاحة وعرض مشغل لكل مقطع فيديو.
المتطلبات
- فهم HTML و CSS و JavaScript و Node / Express و Vue.
- محرر نصوص (مثل VS Code).
- متصفح ويب (مثل Chrome و Firefox).
- تثبيت FFmpeg على محطة العمل الخاصة بك.
- Node.js. نيفم.
- يمكنك الحصول على الكود المصدري على جيثب.
إعداد تطبيقنا
في هذا التطبيق ، سنبني المسارات لتقديم الطلبات من الواجهة الأمامية:
- يتم توجيه
videos
للحصول على قائمة مقاطع الفيديو وبياناتها. - طريق لجلب مقطع فيديو واحد فقط من قائمة مقاطع الفيديو الخاصة بنا.
- طريق
streaming
لدفق مقاطع الفيديو. - طريق
captions
التوضيحية لإضافة تسميات توضيحية إلى مقاطع الفيديو التي نقوم ببثها.
بعد إنشاء مساراتنا ، سنعمل على دعم واجهة Nuxt
الأمامية ، حيث سننشئ Home
وصفحة player
الديناميكي. ثم نطلب مسار videos
بنا لملء الصفحة الرئيسية ببيانات الفيديو ، وطلب آخر لدفق مقاطع الفيديو على صفحة player
لدينا ، وأخيرًا طلب خدمة ملفات التسميات التوضيحية لاستخدامها بواسطة مقاطع الفيديو.
لإعداد تطبيقنا ، نقوم بإنشاء دليل مشروعنا ،
mkdir streaming-app
إعداد خادمنا
في دليل streaming-app
، نقوم بإنشاء مجلد باسم backend
.
cd streaming-app mkdir backend
في مجلد الخلفية ، نقوم بتهيئة ملف package.json
لتخزين المعلومات حول مشروع الخادم الخاص بنا.
cd backend npm init -y
نحتاج إلى تثبيت الحزم التالية لبناء تطبيقنا.
-
nodemon
بإعادة تشغيل خادمنا تلقائيًا عندما نجري تغييرات. - يعطينا
express
واجهة لطيفة للتعامل مع المسارات. - سيتيح لنا
cors
تقديم طلبات عبر الأصل نظرًا لأن العميل والخادم الخاص بنا سيعملان على منافذ مختلفة.
في دليل الواجهة الخلفية لدينا ، نقوم بإنشاء assets
مجلد للاحتفاظ بمقاطع الفيديو الخاصة بنا للبث.
mkdir assets
انسخ ملف .mp4
إلى مجلد الأصول ، وقم video1
. يمكنك استخدام نماذج فيديو قصيرة .mp4
يمكن العثور عليها في Github Repo.
قم بإنشاء ملف app.js
وأضف الحزم الضرورية لتطبيقنا.
const express = require('express'); const fs = require('fs'); const cors = require('cors'); const path = require('path'); const app = express(); app.use(cors())
تُستخدم وحدة fs
للقراءة والكتابة في الملفات بسهولة على خادمنا ، بينما توفر وحدة path
طريقة للعمل مع الدلائل ومسارات الملفات.
الآن نقوم بإنشاء مسار. ./video
. عند الطلب ، سيرسل ملف فيديو إلى العميل مرة أخرى.
// add after 'const app = express();' app.get('/video', (req, res) => { res.sendFile('assets/video1.mp4', { root: __dirname }); });
يخدم هذا المسار ملف الفيديو video1.mp4
عند الطلب. ثم نستمع إلى الخادم الخاص بنا في المنفذ 3000
.
// add to end of app.js file app.listen(5000, () => { console.log('Listening on port 5000!') });
تمت إضافة نص برمجي في ملف package.json
لبدء خادمنا باستخدام nodemon.
"scripts": { "start": "nodemon app.js" },
ثم أثناء تشغيل المحطة:
npm run start
إذا رأيت الرسالة Listening on port 3000!
في المحطة ، فإن الخادم يعمل بشكل صحيح. انتقل إلى https: // localhost: 5000 / video في متصفحك وسترى تشغيل الفيديو.
الطلبات التي يتعين التعامل معها من قبل الواجهة
فيما يلي الطلبات التي سنقدمها إلى الواجهة الخلفية من الواجهة الأمامية لدينا والتي نحتاج إلى الخادم للتعامل معها.
-
/videos
يقوم بإرجاع مجموعة من بيانات نموذج الفيديو التي سيتم استخدامها لملء قائمة مقاطع الفيديو على الصفحةHome
في الواجهة الأمامية الخاصة بنا. -
/video/:id/data
إرجاع البيانات الوصفية لمقطع فيديو واحد. مستخدمة بواسطة صفحةPlayer
في الواجهة الأمامية لدينا. -
/video/:id
لبث مقطع فيديو بمعرف معين. مستخدمة بواسطة صفحةPlayer
.
لنقم بإنشاء الطرق.
إرجاع بيانات نموذج بالحجم الطبيعي لقائمة مقاطع الفيديو
بالنسبة لهذا التطبيق التجريبي ، سننشئ مصفوفة من الكائنات التي ستحتفظ بالبيانات الوصفية وترسلها إلى الواجهة الأمامية عند الطلب. في تطبيق حقيقي ، من المحتمل أن تقرأ البيانات من قاعدة بيانات ، والتي سيتم استخدامها بعد ذلك لإنشاء مصفوفة مثل هذه. من أجل البساطة ، لن نفعل ذلك في هذا البرنامج التعليمي.
في مجلد الواجهة الخلفية لدينا ، قم بإنشاء ملف mockdata.js
وقم بتعبئته ببيانات وصفية لقائمة مقاطع الفيديو الخاصة بنا.
const allVideos = [ { id: "tom and jerry", poster: 'https://image.tmdb.org/t/p/w500/fev8UFNFFYsD5q7AcYS8LyTzqwl.jpg', duration: '3 mins', name: 'Tom & Jerry' }, { id: "soul", poster: 'https://image.tmdb.org/t/p/w500/kf456ZqeC45XTvo6W9pW5clYKfQ.jpg', duration: '4 mins', name: 'Soul' }, { id: "outside the wire", poster: 'https://image.tmdb.org/t/p/w500/lOSdUkGQmbAl5JQ3QoHqBZUbZhC.jpg', duration: '2 mins', name: 'Outside the wire' }, ]; module.exports = allVideos
يمكننا أن نرى من فوق ، كل كائن يحتوي على معلومات حول الفيديو. لاحظ سمة poster
التي تحتوي على رابط صورة ملصق الفيديو.
لنقم بإنشاء مسار videos
نظرًا لأن كل طلباتنا التي يجب تقديمها بواسطة الواجهة الأمامية مُسبقة مسبقًا بـ /videos
.
للقيام بذلك ، دعنا ننشئ مجلد routes
ونضيف ملف Video.js
/videos
. في هذا الملف ، سنطلب express
ونستخدم جهاز التوجيه السريع لإنشاء طريقنا.
const express = require('express') const router = express.Router()
عندما ننتقل إلى مسار /videos
، نريد الحصول على قائمة مقاطع الفيديو الخاصة بنا ، لذلك دعونا نطلب ملف mockData.js
في ملف Video.js
بنا ونقدم طلبنا.
const express = require('express') const router = express.Router() const videos = require('../mockData') // get list of videos router.get('/', (req,res)=>{ res.json(videos) }) module.exports = router;
تم الآن الإعلان عن مسار /videos
، احفظ الملف ويجب إعادة تشغيل الخادم تلقائيًا. بمجرد أن تبدأ ، انتقل إلى https: // localhost: 3000 / videos وسيتم إرجاع المصفوفة الخاصة بنا بتنسيق JSON.
إعادة البيانات لمقطع فيديو واحد
نريد أن نكون قادرين على تقديم طلب لمقطع فيديو معين في قائمة مقاطع الفيديو الخاصة بنا. يمكننا إحضار بيانات فيديو معينة في المصفوفة الخاصة بنا باستخدام id
الذي قدمناه له. دعنا نقدم طلبًا ، ما زلنا في ملف Video.js
بنا.
// make request for a particular video router.get('/:id/data', (req,res)=> { const id = parseInt(req.params.id, 10) res.json(videos[id]) })
يحصل الكود أعلاه على id
من معلمات المسار ويحوله إلى عدد صحيح. ثم نرسل الكائن الذي يطابق id
من مجموعة videos
إلى العميل.
دفق الفيديو
في ملف app.js
بنا ، أنشأنا مسار /video
يقدم مقطع فيديو إلى العميل. نريد من نقطة النهاية هذه إرسال أجزاء أصغر من الفيديو ، بدلاً من تقديم ملف فيديو كامل عند الطلب.
نريد أن نكون قادرين على تقديم أحد مقاطع الفيديو الثلاثة allVideos
في مجموعة جميع مقاطع الفيديو ديناميكيًا ، ودفق مقاطع الفيديو في أجزاء ، لذلك:
احذف مسار /video
من app.js
نحتاج إلى ثلاثة مقاطع فيديو ، لذا انسخ أمثلة مقاطع الفيديو من الكود المصدري للبرنامج التعليمي إلى assets/
الدليل الخاص بمشروع server
الخاص بك. تأكد من أن أسماء ملفات مقاطع الفيديو مطابقة id
في مجموعة videos
:
بالعودة إلى ملف Video.js
بنا ، أنشئ مسارًا لبث مقاطع الفيديو.
router.get('/video/:id', (req, res) => { const videoPath = `assets/${req.params.id}.mp4`; const videoStat = fs.statSync(videoPath); const fileSize = videoStat.size; const videoRange = req.headers.range; if (videoRange) { const parts = videoRange.replace(/bytes=/, "").split("-"); const start = parseInt(parts[0], 10); const end = parts[1] ? parseInt(parts[1], 10) : fileSize-1; const chunksize = (end-start) + 1; const file = fs.createReadStream(videoPath, {start, end}); const head = { 'Content-Range': `bytes ${start}-${end}/${fileSize}`, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize, 'Content-Type': 'video/mp4', }; res.writeHead(206, head); file.pipe(res); } else { const head = { 'Content-Length': fileSize, 'Content-Type': 'video/mp4', }; res.writeHead(200, head); fs.createReadStream(videoPath).pipe(res); } });
إذا انتقلنا إلى https: // localhost: 5000 / videos / video / outside-the-wire في متصفحنا ، يمكننا مشاهدة تدفق الفيديو.
كيف يعمل طريق دفق الفيديو
يوجد جزء لا بأس به من التعليمات البرمجية المكتوبة في مسار بث الفيديو الخاص بنا ، لذلك دعونا ننظر إليه سطراً بسطر.
const videoPath = `assets/${req.params.id}.mp4`; const videoStat = fs.statSync(videoPath); const fileSize = videoStat.size; const videoRange = req.headers.range;
أولاً ، بناءً على طلبنا ، نحصل على id
من المسار باستخدام req.params.id
لإنشاء videoPath
الفيديو إلى الفيديو. ثم fileSize
الملف باستخدام نظام الملفات fs
الذي قمنا باستيراده. بالنسبة لمقاطع الفيديو ، سيرسل متصفح المستخدم معلمة range
في الطلب. يتيح ذلك للخادم معرفة جزء الفيديو الذي سيتم إرساله مرة أخرى إلى العميل.
ترسل بعض المتصفحات نطاقًا في الطلب الأولي ، لكن البعض الآخر لا يرسل ذلك. بالنسبة لأولئك الذين لا يرسلون نطاقًا ، أو لأي سبب آخر لا يرسل المتصفح نطاقًا ، فإننا نتعامل مع ذلك في كتلة else
. يحصل هذا الرمز على حجم الملف ويرسل الأجزاء القليلة الأولى من الفيديو:
else { const head = { 'Content-Length': fileSize, 'Content-Type': 'video/mp4', }; res.writeHead(200, head); fs.createReadStream(path).pipe(res); }
سنتعامل مع الطلبات اللاحقة بما في ذلك النطاق في كتلة if
.
if (videoRange) { const parts = videoRange.replace(/bytes=/, "").split("-"); const start = parseInt(parts[0], 10); const end = parts[1] ? parseInt(parts[1], 10) : fileSize-1; const chunksize = (end-start) + 1; const file = fs.createReadStream(videoPath, {start, end}); const head = { 'Content-Range': `bytes ${start}-${end}/${fileSize}`, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize, 'Content-Type': 'video/mp4', }; res.writeHead(206, head); file.pipe(res); }
ينشئ هذا الرمز أعلاه دفق قراءة باستخدام قيم start
end
للنطاق. قم بتعيين Content-Length
لرؤوس الاستجابة إلى حجم المقطع الذي يتم حسابه من قيم start
end
. نستخدم أيضًا رمز HTTP 206 ، للإشارة إلى أن الاستجابة تحتوي على محتوى جزئي. هذا يعني أن المتصفح سيستمر في تقديم الطلبات حتى يتم جلب جميع أجزاء الفيديو.
ماذا يحدث عند التوصيلات غير المستقرة
إذا كان المستخدم على اتصال بطيء ، فسيقوم دفق الشبكة بإرسال إشارة إليه عن طريق طلب إيقاف مصدر الإدخال / الإخراج مؤقتًا حتى يصبح العميل جاهزًا لمزيد من البيانات. يُعرف هذا بالضغط العكسي . يمكننا أن نأخذ هذا المثال خطوة إلى الأمام ونرى مدى سهولة تمديد التدفق. يمكننا بسهولة إضافة الضغط أيضًا!
const start = parseInt(parts[0], 10); const end = parts[1] ? parseInt(parts[1], 10) : fileSize-1; const chunksize = (end-start) + 1; const file = fs.createReadStream(videoPath, {start, end});
يمكننا أن نرى أعلاه أنه يتم إنشاء ReadStream
ويخدم مقطع الفيديو قطعة تلو الأخرى.
const head = { 'Content-Range': `bytes ${start}-${end}/${fileSize}`, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize, 'Content-Type': 'video/mp4', }; res.writeHead(206, head); file.pipe(res);
يحتوي رأس الطلب على Content-Range
، وهو تغيير البداية والنهاية للحصول على الجزء التالي من الفيديو ليتم بثه إلى الواجهة الأمامية ، content-length
هو جزء الفيديو الذي تم إرساله. نحدد أيضًا نوع المحتوى الذي نقوم ببثه وهو mp4
. تم تعيين رأس الكتابة لـ 206 للاستجابة مع التدفقات التي تم إنشاؤها حديثًا فقط.
إنشاء ملف تسمية توضيحية لمقاطع الفيديو الخاصة بنا
هذا ما يبدو عليه ملف التسمية التوضيحية .vtt
.
WEBVTT 00:00:00.200 --> 00:00:01.000 Creating a tutorial can be very 00:00:01.500 --> 00:00:04.300 fun to do.
تحتوي ملفات التسميات التوضيحية على نصوص لما يقال في الفيديو. يحتوي أيضًا على رموز زمنية لوقت عرض كل سطر من النص. نريد أن تحتوي مقاطع الفيديو الخاصة بنا على تسميات توضيحية ، ولن ننشئ ملف التسمية التوضيحية الخاص بنا لهذا البرنامج التعليمي ، لذا يمكنك التوجه إلى مجلد التسميات التوضيحية في دليل assets
في الريبو وتنزيل التسميات التوضيحية.
لنقم بإنشاء مسار جديد للتعامل مع طلب التسمية التوضيحية:
router.get('/video/:id/caption', (req, res) => res.sendFile(`assets/captions/${req.params.id}.vtt`, { root: __dirname }));
بناء واجهتنا
للبدء في الجزء المرئي من نظامنا ، سيتعين علينا بناء سقالة أمامية.
ملاحظة : أنت بحاجة إلى vue-cli لإنشاء تطبيقنا. إذا لم يكن مثبتًا لديك على جهاز الكمبيوتر الخاص بك ، فيمكنك تشغيل npm install -g @vue/cli
لتثبيته.
تثبيت
في جذر مشروعنا ، لنقم بإنشاء مجلد الواجهة الأمامية:
mkdir frontend cd frontend
وفيه نقوم بتهيئة ملف package.json
الخاص بنا ، ونسخ ولصق ما يلي فيه:
{ "name": "my-app", "scripts": { "dev": "nuxt", "build": "nuxt build", "generate": "nuxt generate", "start": "nuxt start" } }
ثم قم بتثبيت nuxt
:
npm add nuxt
وقم بتنفيذ الأمر التالي لتشغيل تطبيق Nuxt.js:
npm run dev
هيكل ملف Nuxt الخاص بنا
الآن بعد أن قمنا بتثبيت Nuxt ، يمكننا البدء في وضع الواجهة الأمامية.
أولاً ، نحتاج إلى إنشاء مجلد layouts
في جذر تطبيقنا. يحدد هذا المجلد تخطيط التطبيق ، بغض النظر عن الصفحة التي ننتقل إليها. تم العثور هنا على أشياء مثل شريط التنقل والتذييل. في مجلد الواجهة الأمامية ، نقوم بإنشاء default.vue
الافتراضي عندما نبدأ تطبيق الواجهة الأمامية.
mkdir layouts cd layouts touch default.vue
ثم مجلد components
لإنشاء جميع مكوناتنا. سنحتاج فقط إلى مكونين ، شريط NavBar
ومكون video
. لذلك في المجلد الجذر الخاص بنا للواجهة الأمامية ، نقوم بما يلي:
mkdir components cd components touch NavBar.vue touch Video.vue
أخيرًا ، مجلد صفحات حيث يمكن إنشاء جميع صفحاتنا مثل home
وما about
. الصفحتان اللتان نحتاجهما في هذا التطبيق ، هما الصفحة home
التي تعرض جميع مقاطع الفيديو ومعلومات الفيديو الخاصة بنا وصفحة مشغل ديناميكي توجه إلى الفيديو الذي ننقر عليه.
mkdir pages cd pages touch index.vue mkdir player cd player touch _name.vue
يبدو دليل الواجهة الأمامية الآن كما يلي:
|-frontend |-components |-NavBar.vue |-Video.vue |-layouts |-default.vue |-pages |-index.vue |-player |-_name.vue |-package.json |-yarn.lock
مكون نافبار
يبدو NavBar.vue
كما يلي:
<template> <div class="navbar"> <h1>Streaming App</h1> </div> </template> <style scoped> .navbar { display: flex; background-color: #161616; justify-content: center; align-items: center; } h1{ color:#a33327; } </style>
يحتوي NavBar
على علامة h1
تعرض تطبيق البث ، مع بعض التصميم البسيط.
دعنا نستورد NavBar
إلى تخطيط default.vue
الخاص بنا.
// default.vue <template> <div> <NavBar /> <nuxt /> </div> </template> <script> import NavBar from "@/components/NavBar.vue" export default { components: { NavBar, } } </script>
يحتوي تخطيط default.vue
الآن على مكون NavBar
الخاص بنا <nuxt />
التي تليها تشير إلى المكان الذي سيتم فيه عرض أي صفحة نقوم بإنشائها.
في index.vue
بنا (وهي صفحتنا الرئيسية) ، دعنا نطلب https://localhost:5000/videos
للحصول على جميع مقاطع الفيديو من خادمنا. تمرير البيانات كعنصر أساسي إلى مكون video.vue
الذي سننشئه لاحقًا. لكن في الوقت الحالي ، قمنا باستيراده بالفعل.
<template> <div> <Video :videoList="videos"/> </div> </template> <script> import Video from "@/components/Video.vue" export default { components: { Video }, head: { title: "Home" }, data() { return { videos: [] } }, async fetch() { this.videos = await fetch( 'https://localhost:5000/videos' ).then(res => res.json()) } } </script>
مكون الفيديو
أدناه ، نعلن أولاً عن دعائمنا. نظرًا لأن بيانات الفيديو متاحة الآن في المكون ، باستخدام Vue's v-for
فإننا نكرر جميع البيانات المستلمة ولكل منها ، نعرض المعلومات. يمكننا استخدام التوجيه v-for
للتكرار خلال البيانات وعرضها كقائمة. تمت إضافة بعض التصميم الأساسي أيضًا.
<template> <div> <div class="container"> <div v-for="(video, id) in videoList" :key="id" class="vid-con" > <NuxtLink :to="`/player/${video.id}`"> <div : class="vid" ></div> <div class="movie-info"> <div class="details"> <h2>{{video.name}}</h2> <p>{{video.duration}}</p> </div> </div> </NuxtLink> </div> </div> </div> </template> <script> export default { props:['videoList'], } </script> <style scoped> .container { display: flex; justify-content: center; align-items: center; margin-top: 2rem; } .vid-con { display: flex; flex-direction: column; flex-shrink: 0; justify-content: center; width: 50%; max-width: 16rem; margin: auto 2em; } .vid { height: 15rem; width: 100%; background-position: center; background-size: cover; } .movie-info { background: black; color: white; width: 100%; } .details { padding: 16px 20px; } </style>
نلاحظ أيضًا أن NuxtLink
له مسار ديناميكي ، وهو التوجيه إلى /player/video.id
.
الوظيفة التي نريدها هي عندما ينقر المستخدم على أي من مقاطع الفيديو ، يبدأ البث. لتحقيق ذلك ، نستفيد من الطبيعة الديناميكية لمسار _name.vue
.
في ذلك ، نقوم بإنشاء مشغل فيديو وتعيين المصدر إلى نقطة النهاية الخاصة بنا لدفق الفيديو ، لكننا this.$route.params.name
.
<template> <div class="player"> <video controls muted autoPlay> <source :src="`https://localhost:5000/videos/video/${vidName}`" type="video/mp4"> </video> </div> </template> <script> export default { data() { return { vidName: '' } }, mounted(){ this.vidName = this.$route.params.name } } </script> <style scoped> .player { display: flex; justify-content: center; align-items: center; margin-top: 2em; } </style>
عندما نضغط على أي مقطع فيديو نحصل على:
إضافة ملف التسمية التوضيحية لدينا
لإضافة ملف المسار الخاص بنا ، نتأكد من أن جميع ملفات .vtt
في مجلد التسميات التوضيحية تحمل نفس اسم id
. قم بتحديث عنصر الفيديو الخاص بنا بالمسار ، مع تقديم طلب للحصول على التسميات التوضيحية.
<template> <div class="player"> <video controls muted autoPlay crossOrigin="anonymous"> <source :src="`https://localhost:5000/videos/video/${vidName}`" type="video/mp4"> <track label="English" kind="captions" srcLang="en" :src="`https://localhost:5000/videos/video/${vidName}/caption`" default> </video> </div> </template>
لقد أضفنا crossOrigin="anonymous"
إلى عنصر الفيديو ؛ وإلا ، فسيفشل طلب التسميات التوضيحية. قم بالتحديث الآن وسترى تمت إضافة التسميات التوضيحية بنجاح.
ما يجب مراعاته عند بناء دفق فيديو مرن.
عند إنشاء تطبيقات دفق مثل Twitch أو Hulu أو Netflix ، هناك عدد من الأشياء التي يتم وضعها في الاعتبار:
- خط أنابيب معالجة بيانات الفيديو
يمكن أن يكون هذا تحديًا تقنيًا حيث يلزم وجود خوادم عالية الأداء لخدمة ملايين مقاطع الفيديو للمستخدمين. يجب تجنب الكمون الكبير أو التعطل بأي ثمن. - التخزين المؤقت
يجب استخدام آليات التخزين المؤقت عند إنشاء هذا النوع من التطبيقات مثل Cassandra و Amazon S3 و AWS SimpleDB. - جغرافيا المستخدمين
يجب التفكير في التوزيع الجغرافي لمستخدميك.
خاتمة
في هذا البرنامج التعليمي ، رأينا كيفية إنشاء خادم في Node.js يقوم ببث مقاطع الفيديو ، وإنشاء تسميات توضيحية لمقاطع الفيديو هذه ، وتقديم البيانات الوصفية لمقاطع الفيديو. لقد رأينا أيضًا كيفية استخدام Nuxt.js على الواجهة الأمامية لاستهلاك نقاط النهاية والبيانات التي تم إنشاؤها بواسطة الخادم.
على عكس الأطر الأخرى ، فإن إنشاء تطبيق باستخدام Nuxt.js و Express.js سهل وسريع للغاية. الجزء الرائع في Nuxt.js هو الطريقة التي يدير بها مساراتك ويجعلك تقوم ببناء تطبيقاتك بشكل أفضل.
- يمكنك الحصول على مزيد من المعلومات حول Nuxt.js هنا.
- يمكنك الحصول على الكود المصدري على جيثب.
موارد
- "إضافة تسميات توضيحية وترجمات إلى فيديو HTML5 ،" MDN Web Docs
- "فهم التسميات التوضيحية والترجمات" ، Screenfont.ca