BustPlay

BustPlay — быстрый старт

Пять минут от пустой страницы до плеера с рекламой. Всё ниже — работающий API текущих сборок (npm run build в корне репозитория), не планы.

1. Плеер тегом (минута)

<link rel="stylesheet" href="bustplay/ui.css">
<div id="player"></div>

<script src="bustplay/core.umd.cjs"></script>
<script src="bustplay/ui.umd.cjs"></script>
<script>
  const player = BustPlay.createPlayer({
    container: 'player',                       // id или сам элемент
    sources: 'https://cdn.example/video.mp4',  // строка или [{src, type}]
    muted: true,                               // авто-политики браузеров учтены
  });
  BustPlayUI.createUI(player, { title: 'Название ролика' });
</script>

Файлы берутся из packages/*/dist/ (до публикации в npm). UMD-глобали: BustPlay (core), BustPlayUI, BustPlayHls, BustPlayAds, BustPlayAnalytics.

2. То же в сборке (ESM)

import { createPlayer } from '@bustplay/core';
import { createUI } from '@bustplay/ui';
import '@bustplay/ui/ui.css';

const player = createPlayer({ container: 'player', sources: 'https://cdn.example/video.mp4' });
const ui = createUI(player, {
  title: 'Название ролика',
  chapters: [{ t: 0, name: 'Пролог' }, { t: 96, name: 'Глава вторая' }],
  skin: 'studio',            // studio | minimal | vertical
  accent: '#5B8CFF',         // white-label одной переменной
});

Импорт SSR-safe: window не трогается до createPlayer.

3. HLS

import { attachHls, bindQualityMenu } from '@bustplay/hls';

const player = createPlayer({ container: 'player', sources: [] }); // источник ведёт адаптер
const ui = createUI(player, { title: 'Эфир' });
const hls = await attachHls(player, 'https://cdn.example/stream.m3u8');
bindQualityMenu(hls, ui.menu); // уровни качества появляются в меню сами

Safari играет нативно; в остальных браузерах hls.js подхватывается лениво: options.lib → глобаль Hls на странице → import('hls.js').

4. Реклама

import { createAdScheduler, breaksFromVmap } from '@bustplay/ads';

const scheduler = createAdScheduler(player, {
  ui,                                    // счётчик «Реклама 1 из 2», стоп перемотки
  breaks: [
    { offset: 'pre',              tags: [TAG_A, TAG_B] }, // не заполнился A — пробуем B
    { offset: { percent: 0.5 },   tags: [TAG_MID], pod: 2 },
    { offset: 'post',             tags: [TAG_POST] },
  ],
  consent: { gdpr: '1', gdprConsent: TCF_STRING },  // → макросы {gdpr}/{gdpr_consent}
});

// Чистый pre-roll без мигания контента:
await scheduler.runPreRoll();
void player.play();

// Или целиком из VMAP:
createAdScheduler(player, { ui, breaks: breaksFromVmap(vmapXml) });

5. Аналитика

import { createAnalytics } from '@bustplay/analytics';

createAnalytics(player, {
  endpoint: 'https://stats.example.com/v1/events',
  video: 'video-42',       // ваш id ролика, не PII
  sampleRate: 1,           // доля сессий со сбором
});

События (view_start c TTFF, квартили, rebuffer, ошибки, session_end с QoE) уходят батчами; закрытие вкладки переживают через sendBeacon. Приёмная сторона — services/stats (README там же).

6. React и Web Component

import { BustPlayer } from '@bustplay/react';
import '@bustplay/ui/ui.css';

<BustPlayer sources="https://cdn.example/video.mp4" title="Ролик"
  onReady={({ player, ui }) => console.log(player.getState())} />
<script src="bustplay/element.umd.cjs"></script>
<script>BustPlayElement.define()</script>
<bust-play src="https://cdn.example/video.mp4" title="Ролик" muted></bust-play>

Смена sources/src пересоздаёт плеер; косметика (title, skin) применяется при создании. <bust-play> без Shadow DOM — ему нужен подключённый ui.css.

7. DRM

import { toHlsDrmConfig, toDashProtectionData, enableFairPlay } from '@bustplay/drm';

const drm = {
  widevine:  { licenseUrl: 'https://lic.example/wv', headers: { 'X-Auth': token } },
  playready: { licenseUrl: 'https://lic.example/pr' },
  fairplay:  { licenseUrl: 'https://lic.example/fps', certificateUrl: 'https://lic.example/cert' },
};

await attachHls(player, src, { config: toHlsDrmConfig(drm) });          // hls.js EME
await attachDash(player, src, { protectionData: toDashProtectionData(drm) });
const off = enableFairPlay(player.media, drm.fairplay);                  // нативный Safari-HLS

Widevine/PlayReady исполняют hls.js/dash.js; FairPlay на нативном пути ведёт наша EME-обвязка (SPC/CKC сырыми байтами; серверные вариации — хуками licenseBody/licenseResponse). Живой прогон требует лицензионного сервера.

Что дальше