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). Живой прогон требует лицензионного сервера.
Что дальше
- Живое демо:
apps/demo/index.html(послеnpm run build). - Дизайн-система интерфейса:
UI_DESIGN.md. - Дорожная карта и статус по-честному:
README.md§6.