Adaptive Bitrate Streaming (ABR)
Ключевая технология видеоплатформ. Видео разбито на сегменты по 2–6 секунд, каждый доступен в нескольких качествах. Плеер измеряет bandwidth и переключает качество в реальном времени:
// Настройка hls.js с ABR
const hls = new Hls({
startLevel: -1, // -1 = авто, определяет quality по bandwidth
capLevelToPlayerSize: true, // не грузить 4K на маленьком экране
maxBufferLength: 30, // буфер 30 секунд вперёд
maxMaxBufferLength: 60,
abrEwmaDefaultEstimate: 500000, // начальная оценка bandwidth (bps)
});
hls.loadSource(manifestUrl);
hls.attachMedia(videoElement);
capLevelToPlayerSize: true — важная оптимизация: если плеер 360px шириной (мобильный), нет смысла загружать 1080p. Экономит трафик и ускоряет загрузку.
Preload стратегия
Несколько уровней preloading для ускорения старта видео:
- Hover preload — при наведении на карточку фильма загружаем манифест и первый сегмент видео (~500KB). К моменту клика первый кадр готов.
- Метаданные — при открытии страницы фильма сразу запрашиваем
/stream endpoint, не дожидаясь клика Play.
- Next Episode — за 30 секунд до конца текущей серии начинаем загружать манифест следующей.
Skeleton UI и быстрый FCP
Каталог использует скелетоны вместо спиннеров. Скелетоны повторяют layout контента — пользователь воспринимает загрузку быстрее. Для карусели постеров — placeholder с blur-up эффектом:
// ContentCard с blur-up placeholder
<div className="relative aspect-[2/3] overflow-hidden rounded-lg">
<img
src={video.posterUrl}
alt={video.title}
loading="lazy"
decoding="async"
className="h-full w-full object-cover transition-opacity"
style={{ backgroundImage: `url(${video.lqipUrl})`,
backgroundSize: "cover" }}
/>
</div>
Code splitting
- Плеер (~200KB) — загружается только на странице видео через
dynamic import.
- Комментарии — lazy load при скролле ниже плеера.
- Модуль поиска — загружается при фокусе на поисковую строку.
Кэширование
- Service Worker — кэширует каталог (HTML, постеры) для мгновенного открытия. Стратегия: stale-while-revalidate для каталога, cache-first для постеров.
- IndexedDB — watch progress, предпочтения пользователя. Синхронизация с сервером в фоне.
- Video segments — не кэшируем (DRM-сегменты одноразовые), но буферизируем 30–60 секунд вперёд.
Prefetch рекомендаций
Пока пользователь смотрит видео, в фоне загружаем рекомендации — они понадобятся после окончания фильма. Используем requestIdleCallback, чтобы не конкурировать с видеопотоком за bandwidth.