BustPlay — inicio rápido
Cinco minutos desde una página vacía hasta un reproductor con publicidad. Todo lo que sigue es la API real de los builds actuales (npm run build en la raíz del repositorio), no planes.
1. Reproductor con etiqueta script (un minuto)
<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 o el propio elemento
sources: 'https://cdn.example/video.mp4', // cadena o [{src, type}]
muted: true, // políticas de autoplay del navegador cubiertas
});
BustPlayUI.createUI(player, { title: 'Título del vídeo' });
</script>
Los archivos salen de packages/*/dist/ (hasta la publicación en npm). Globales UMD: BustPlay (core), BustPlayUI, BustPlayHls, BustPlayAds, BustPlayAnalytics.
2. Lo mismo con un bundler (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: 'Título del vídeo',
chapters: [{ t: 0, name: 'Prólogo' }, { t: 96, name: 'Capítulo dos' }],
skin: 'studio', // studio | minimal | vertical
accent: '#5B8CFF', // marca blanca con una sola variable
});
La importación es segura para SSR: no se toca window hasta createPlayer.
3. HLS
import { attachHls, bindQualityMenu } from '@bustplay/hls';
const player = createPlayer({ container: 'player', sources: [] }); // el adaptador gestiona la fuente
const ui = createUI(player, { title: 'En directo' });
const hls = await attachHls(player, 'https://cdn.example/stream.m3u8');
bindQualityMenu(hls, ui.menu); // los niveles de calidad aparecen solos en el menú
Safari reproduce de forma nativa; el resto de navegadores carga hls.js de forma perezosa: options.lib → el global Hls de la página → import('hls.js').
4. Publicidad
import { createAdScheduler, breaksFromVmap } from '@bustplay/ads';
const scheduler = createAdScheduler(player, {
ui, // contador «Anuncio 1 de 2», búsqueda bloqueada
breaks: [
{ offset: 'pre', tags: [TAG_A, TAG_B] }, // si A no rellena, probamos B
{ offset: { percent: 0.5 }, tags: [TAG_MID], pod: 2 },
{ offset: 'post', tags: [TAG_POST] },
],
consent: { gdpr: '1', gdprConsent: TCF_STRING }, // → macros {gdpr}/{gdpr_consent}
});
// Pre-roll limpio sin parpadeo del contenido:
await scheduler.runPreRoll();
void player.play();
// O todo desde VMAP:
createAdScheduler(player, { ui, breaks: breaksFromVmap(vmapXml) });
5. Analítica
import { createAnalytics } from '@bustplay/analytics';
createAnalytics(player, {
endpoint: 'https://stats.example.com/v1/events',
video: 'video-42', // tu id de vídeo, no PII
sampleRate: 1, // proporción de sesiones recogidas
});
Los eventos (view_start con TTFF, cuartiles, rebuffer, errores, session_end con QoE) se envían por lotes; el cierre de la pestaña se sobrevive con sendBeacon. El lado receptor es services/stats (README allí).
6. React y Web Component
import { BustPlayer } from '@bustplay/react';
import '@bustplay/ui/ui.css';
<BustPlayer sources="https://cdn.example/video.mp4" title="Vídeo"
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="Vídeo" muted></bust-play>
Cambiar sources/src recrea el reproductor; la cosmética (title, skin) se aplica al crearlo. <bust-play> no usa Shadow DOM: necesita ui.css en la página.
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) }); // EME de hls.js
await attachDash(player, src, { protectionData: toDashProtectionData(drm) });
const off = enableFairPlay(player.media, drm.fairplay); // HLS nativo de Safari
Widevine/PlayReady los gestionan hls.js/dash.js; FairPlay en la ruta nativa lo lleva nuestra capa EME (SPC/CKC como bytes crudos; variaciones del servidor con los hooks licenseBody/licenseResponse). Una prueba real necesita un servidor de licencias.
¿Qué sigue?
- Demo en vivo:
apps/demo/index.html(trasnpm run build). - Sistema de diseño de la interfaz:
UI_DESIGN.md. - Hoja de ruta y estado sincero:
README.md§6.