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

Представьте: студент на слабом интернете пытается досмотреть видеоурок, но плеер тормозит, а после перемотки прогресс обнуляется — приходится пересматривать заново. Именно с такими проблемами сталкиваются многие LMS, собранные без продуманной архитектуры. Разработка системы уроков — это комплексная

Разработка и обслуживание любых видов сайтов:

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

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

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

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

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1422
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1287
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    984
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1250
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    986
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    1000

Представьте: студент на слабом интернете пытается досмотреть видеоурок, но плеер тормозит, а после перемотки прогресс обнуляется — приходится пересматривать заново. Именно с такими проблемами сталкиваются многие LMS, собранные без продуманной архитектуры. Разработка системы уроков — это комплексная задача: нужно обеспечить стабильный трекинг для видео, текста и аудио, адаптивную доставку контента и отказоустойчивость. Мы разрабатываем систему уроков, где каждый тип контента имеет надёжный трекинг и адаптивную доставку. На основе опыта 50+ учебных порталов мы выделили ключевые технические проблемы: хрупкий трекинг при перемотке видео, долгая загрузка больших файлов, отсутствие синхронизации аудио с транскрипцией. Ниже — как мы их решаем.

Какие технические проблемы решает система уроков?

Трекинг прогресса видео — пользователь может мотать назад, и прогресс должен фиксировать только максимальную позицию. Мы сохраняем её каждые 10% и завершаем урок при 90%+ просмотра, а не только при окончании.

Транскодирование больших файлов — прямой MP4 тормозит на медленном интернете. Мы перегоняем видео в HLS с несколькими битрейтами (360p–1080p) и используем фоновые воркеры (Bull) для асинхронной обработки.

Текстовые уроки без отметки о прочтении — просто пролистать до конца недостаточно. Мы используем Intersection Observer для детекции 90% прокрутки и автоматически завершаем урок.

Аудио без синхронизации — слушатель теряет нить без текста. Мы выводим транскрипцию рядом с плеером и подсвечиваем текущее слово (опционально).

Разработка системы уроков: как обеспечить надёжный трекинг прогресса?

Ключевая сложность — пользователь может перематывать назад, но прогресс должен только расти. В компоненте ReactPlayer мы запоминаем максимальное значение played (0–1) и сохраняем его каждые 10%.

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 maxPlayedRef = useRef(lesson.progress?.progress ?? 0); const handleProgress = useCallback(async ({ played: p }) => { setPlayed(p); if (p > maxPlayedRef.current) { maxPlayedRef.current = p; 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]); 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> ); } 

Почему мы используем HLS вместо прямого MP4?

Прямой MP4 загружается целиком — при плохом соединении пользователь ждёт минуты. HLS режет видео на 6-секундные сегменты: плеер начинает показ сразу, переключая качество в зависимости от скорости. HLS начинает воспроизведение в 3-10 раз быстрее MP4, а в условиях слабого интернета разница достигает 15 раз. Мы транскодируем загруженное видео через ffmpeg в фоне.

Стандарт HTTP Live Streaming описывает адаптивную передачу видео и обеспечивает плавное воспроизведение.

import { createReadStream } from 'fs'; 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', '-level 3.0', '-start_number 0', '-hls_time 6', '-hls_list_size 0', '-f hls', ]) .output(path.join(outputDir, 'index.m3u8')) .outputOptions([ '-vf scale=-2:720', '-b:v 2500k', ]) .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`; await job.progress(10); const hlsPath = await transcodeToHLS(uploadedPath, outputDir); await job.progress(80); const url = await uploadHLSToS3(outputDir, `lessons/${lessonId}`); await db.lessons.update(lessonId, { content: { videoUrl: url, status: 'ready' } }); await job.progress(100); }); 
Подробнее о фоновом транскодировании Мы используем очередь Bull для асинхронной обработки видео. После загрузки файла на сервер задача попадает в очередь, и рабочий процесс транскодирует видео в HLS через ffmpeg. Это не блокирует основной поток и позволяет масштабировать обработку на несколько воркеров. Время транскодирования зависит от размера видео: 10-минутный ролик в 1080p обрабатывается около 5 минут.

Текстовые и аудиоуроки

Как работает Intersection Observer для фиксации прочтения?

Для текстовых уроков используем редактор Tiptap (на базе ProseMirror). Контент хранится в HTML или Markdown. Чтобы засчитать прочтение, отслеживаем прокрутку до конца через Intersection Observer.

import { useEditor, EditorContent } from '@tiptap/react'; import StarterKit from '@tiptap/starter-kit'; import Image from '@tiptap/extension-image'; import { Youtube } from '@tiptap/extension-youtube'; function TextLessonViewer({ content, onComplete }) { const editor = useEditor({ content: content.body, editable: false, extensions: [StarterKit, Image, Youtube], }); const containerRef = useRef<HTMLDivElement>(null); useEffect(() => { const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) onComplete?.(); }, { threshold: 0.9 } ); const marker = containerRef.current?.querySelector('.lesson-end-marker'); if (marker) observer.observe(marker); return () => observer.disconnect(); }, []); return ( <div ref={containerRef} className="prose prose-lg max-w-none"> <EditorContent editor={editor} /> {content.attachments?.length > 0 && ( <div className="mt-8 border-t pt-6"> <h3 className="font-semibold">Материалы урока</h3> <ul className="space-y-2 mt-3"> {content.attachments.map(att => ( <li key={att.url}> <a href={att.url} download className="flex items-center gap-2 text-blue-600 hover:underline"> <span>📎</span> <span>{att.name}</span> <span className="text-gray-400 text-sm">({formatFileSize(att.size)})</span> </a> </li> ))} </ul> </div> )} <div className="lesson-end-marker h-1" /> </div> ); } 

Аудиоуроки с транскрипцией

Аудиоуроки проще: используем нативный audio с кастомным оформлением. Транскрипция выводится под плеером, что помогает слабослышащим и тем, кто не может включить звук.

function AudioLesson({ lesson, onComplete }) { const audioRef = useRef<HTMLAudioElement>(null); const [currentTime, setCurrentTime] = useState(0); return ( <div className="space-y-6"> <div className="bg-gradient-to-br from-purple-50 to-blue-50 rounded-2xl p-8"> {lesson.content.thumbnailUrl && ( <img src={lesson.content.thumbnailUrl} className="w-32 h-32 rounded-full mx-auto mb-6 object-cover" alt="" /> )} <audio ref={audioRef} src={lesson.content.audioUrl} controls className="w-full" onTimeUpdate={() => setCurrentTime(audioRef.current?.currentTime ?? 0)} onEnded={onComplete} /> </div> {lesson.content.transcript && ( <div className="prose"> <h3>Транскрипция</h3> <p className="text-gray-700 whitespace-pre-line"> {lesson.content.transcript} </p> </div> )} </div> ); } 

Сравнение форматов

Тип Рендеринг Прогресс Хранение Сложность
Видео ReactPlayer (HLS) 90% просмотра или конец HLS-сегменты в S3 Высокая (транскодинг)
Текст Tiptap (HTML/MD) 90% прокрутки База данных (JSON) Средняя (редактор)
Аудио Нативный audio 90% прослушивания MP3 в S3 Низкая

При переходе на HLS вы экономите до 50% трафика по сравнению с MP4, а использование адаптивного битрейта снижает расходы на полосу пропускания на 30-50%.

Характеристика HLS MP4
Адаптивный битрейт Да Нет
Время начала воспроизведения 1-3 секунды 10+ секунд
Экономия трафика До 50% по сравнению с MP4 Неэффективен
Поддержка субтитров Да Только встроенные
Поддержка браузеров Все современные Все

Процесс работы и сроки

  1. Аналитика — изучаем ваши требования: типы контента, необходимое количество уроков, интеграции (SCORM, SSO).
  2. Проектирование — рисуем архитектуру: модели данных, API-эндпоинты, компоненты фронтенда.
  3. Реализация — пишем код с нуля или на основе вашей CMS. Используем TypeScript, React, Next.js, Laravel (или ваш стек).
  4. Тестирование — проверяем трекинг на всех типах контента, эмулируем медленный интернет, тестируем загрузку больших файлов.
  5. Деплой — разворачиваем на вашем хостинге или нашем инфраструктуре. Даём доступ к исходному коду и документации.

Ориентировочные сроки: от 1 до 2 недель на базовую систему с видео (HLS), текстом и аудио. Если нужны дополнительные типы (SCORM, live-уроки) или сложная аналитика — срок обговаривается отдельно. Стоимость рассчитывается индивидуально. Закажите разработку системы уроков – мы подготовим индивидуальное коммерческое предложение в течение 24 часов.

Что входит и гарантии

  • Исходный код системы уроков (фронтенд + бэкенд)
  • API для интеграции с существующей LMS
  • Документация по развёртыванию и доработке
  • Консоль администрирования уроков (загрузка, редактирование, порядок)
  • Поддержка после запуска: 2 недели бесплатно

Более 5 лет мы разрабатываем LMS для школ, университетов и корпоративных порталов. Все проекты сдаём в срок и сопровождаем до полной стабильности. Гарантируем, что трекинг будет работать при любых действиях пользователя (перемотка, пауза, повтор). Получите бесплатную консультацию по вашему проекту – свяжитесь с нами. Это бесплатно.