Розробка системи уроків (текст, відео, аудіо) для LMS

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Розробка системи уроків (текст, відео, аудіо) для LMS
Середня
~2-4 тижні
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Розроблення системи уроків у LMS (текст, відео, аудіо)

Система уроків — це ядро LMS. Кожен урок рендериться за своїм типом: відео з плеєром та субтитрами, текст з форматуванням та вбудованими медіа, аудіо з транскрипціями. Плюс трекинг — скільки переглянуто, коли завершено.

Типи уроків та дані

interface VideoLessonContent {
  videoUrl: string;        // HLS-потік або прямий mp4
  duration: number;        // секунди
  subtitles: Array<{ lang: string; label: string; url: string }>;
  chapters?: Array<{ title: string; time: number }>;
}

interface TextLessonContent {
  body: string;           // HTML або Markdown
  estimatedMinutes: number;
  attachments?: Array<{ name: string; url: string; size: number }>;
}

interface AudioLessonContent {
  audioUrl: string;
  duration: number;
  transcript?: string;    // текстова розшифровка
}

Відеоплеєр з трекингом переглядів

import ReactPlayer from 'react-player';
import { useState, useRef, useCallback } from 'react';

function VideoLesson({ lesson, enrollmentId, onComplete }) {
  const playerRef = useRef<ReactPlayer>(null);
  const [played, setPlayed] = useState(0);
  const [completed, setCompleted] = useState(lesson.progress?.completed ?? false);

  const handleProgress = useCallback(async ({ played: p }) => {
    setPlayed(p);
    // Зберегти кожні 10% прогресу
    if (Math.floor(p * 10) > Math.floor((p - 0.01) * 10)) {
      await saveProgress(enrollmentId, lesson.id, p);
    }
  }, []);

  const handleEnded = useCallback(async () => {
    if (!completed) {
      setCompleted(true);
      await fetch(`/api/enrollments/${enrollmentId}/lessons/${lesson.id}/complete`, {
        method: 'POST',
      });
      onComplete?.(lesson.id);
    }
  }, [completed]);

  // Автозавершення при 90%+ переглядів
  const handleProgress2 = useCallback(({ played: p }) => {
    handleProgress({ played: p });
    if (p >= 0.9 && !completed) {
      handleEnded();
    }
  }, [handleProgress, handleEnded, completed]);

  return (
    <div className="space-y-4">
      <div className="relative aspect-video bg-black rounded-xl overflow-hidden">
        <ReactPlayer
          ref={playerRef}
          url={lesson.content.videoUrl}
          width="100%"
          height="100%"
          controls
          onProgress={handleProgress2}
          onEnded={handleEnded}
          config={{
            file: {
              tracks: lesson.content.subtitles.map(s => ({
                kind: 'subtitles',
                src: s.url,
                srcLang: s.lang,
                label: s.label,
              })),
            },
          }}
        />
      </div>

      {lesson.content.chapters?.length > 0 && (
        <div>
          <h3 className="font-semibold text-gray-800 mb-2">Зміст</h3>
          <ul className="space-y-1">
            {lesson.content.chapters.map((ch, i) => (
              <li key={i}>
                <button
                  onClick={() => playerRef.current?.seekTo(ch.time)}
                  className="text-sm text-blue-600 hover:underline"
                >
                  {formatTime(ch.time)} — {ch.title}
                </button>
              </li>
            ))}
          </ul>
        </div>
      )}

      {completed && (
        <div className="flex items-center gap-2 text-green-600 text-sm">
          <span>✓</span> Урок завершено
        </div>
      )}
    </div>
  );
}

Завантаження та перекодування відео

Прямий MP4 погано працює для великих файлів та повільного інтернету. Використовуйте HLS:

import ffmpeg from 'fluent-ffmpeg';

async function transcodeToHLS(inputPath: string, outputDir: string): Promise<string> {
  await fs.promises.mkdir(outputDir, { recursive: true });

  return new Promise((resolve, reject) => {
    ffmpeg(inputPath)
      .outputOptions([
        '-profile:v baseline',
        '-hls_time 6',      // 6 секунд на сегмент
        '-f hls',
      ])
      .output(path.join(outputDir, 'index.m3u8'))
      .on('end', () => resolve(`${outputDir}/index.m3u8`))
      .on('error', reject)
      .run();
  });
}

videoProcessingQueue.process(async (job) => {
  const { uploadedPath, lessonId } = job.data;
  const outputDir = `storage/lessons/${lessonId}/hls`;

  const hlsPath = await transcodeToHLS(uploadedPath, outputDir);
  const url = await uploadHLSToS3(outputDir, `lessons/${lessonId}`);

  await db.lessons.update(lessonId, {
    content: { videoUrl: url, status: 'ready' }
  });
});

Текстовий урок з редактором

import { useEditor, EditorContent } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import Image from '@tiptap/extension-image';

function TextLessonViewer({ content, onComplete }) {
  const editor = useEditor({
    content: content.body,
    editable: false,
    extensions: [StarterKit, Image],
  });

  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const handleScroll = () => {
      if (containerRef.current) {
        const rect = containerRef.current.getBoundingClientRect();
        const scrolled = window.innerHeight - rect.bottom > 0;
        if (scrolled) onComplete?.();
      }
    };

    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, [onComplete]);

  return <EditorContent editor={editor} ref={containerRef} />;
}

Строки виконання

Відеоурок з плеєром та трекингом — 3–5 днів. Текстові/аудіоуроки з редактором та перекодуванням — 5–7 днів. Повна система уроків — 2–3 тижні.