BustPlay
VI

BustPlay — bắt đầu nhanh

Năm phút từ trang trống đến trình phát có quảng cáo. Mọi thứ bên dưới là API đang hoạt động của các bản build hiện tại (npm run build ở thư mục gốc kho mã), không phải kế hoạch.

1. Trình phát bằng thẻ script (một phút)

<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 hoặc chính phần tử
    sources: 'https://cdn.example/video.mp4',  // chuỗi hoặc [{src, type}]
    muted: true,                               // đã xử lý chính sách autoplay của trình duyệt
  });
  BustPlayUI.createUI(player, { title: 'Tên video' });
</script>

Các file lấy từ packages/*/dist/ (cho đến khi phát hành lên npm). Biến toàn cục UMD: BustPlay (core), BustPlayUI, BustPlayHls, BustPlayAds, BustPlayAnalytics.

2. Tương tự với 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ên video',
  chapters: [{ t: 0, name: 'Mở đầu' }, { t: 96, name: 'Chương hai' }],
  skin: 'studio',            // studio | minimal | vertical
  accent: '#5B8CFF',         // white-label chỉ với một biến
});

Import an toàn cho SSR: không chạm vào window cho đến createPlayer.

3. HLS

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

const player = createPlayer({ container: 'player', sources: [] }); // adapter điều khiển nguồn
const ui = createUI(player, { title: 'Trực tiếp' });
const hls = await attachHls(player, 'https://cdn.example/stream.m3u8');
bindQualityMenu(hls, ui.menu); // các mức chất lượng tự xuất hiện trong menu

Safari phát native; các trình duyệt khác tải hls.js theo kiểu lười: options.lib → biến toàn cục Hls trên trang → import('hls.js').

4. Quảng cáo

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

const scheduler = createAdScheduler(player, {
  ui,                                    // bộ đếm “Quảng cáo 1/2”, chặn tua
  breaks: [
    { offset: 'pre',              tags: [TAG_A, TAG_B] }, // A không có quảng cáo — thử B
    { offset: { percent: 0.5 },   tags: [TAG_MID], pod: 2 },
    { offset: 'post',             tags: [TAG_POST] },
  ],
  consent: { gdpr: '1', gdprConsent: TCF_STRING },  // → macro {gdpr}/{gdpr_consent}
});

// Pre-roll sạch, nội dung không nháy:
await scheduler.runPreRoll();
void player.play();

// Hoặc toàn bộ từ VMAP:
createAdScheduler(player, { ui, breaks: breaksFromVmap(vmapXml) });

5. Phân tích

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

createAnalytics(player, {
  endpoint: 'https://stats.example.com/v1/events',
  video: 'video-42',       // id video của bạn, không phải PII
  sampleRate: 1,           // tỷ lệ phiên được thu thập
});

Sự kiện (view_start kèm TTFF, quartile, rebuffer, lỗi, session_end kèm QoE) gửi theo lô; đóng tab vẫn gửi được nhờ sendBeacon. Phía nhận là services/stats (README ở đó).

6. React và Web Component

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

<BustPlayer sources="https://cdn.example/video.mp4" title="Video"
  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="Video" muted></bust-play>

Đổi sources/src sẽ tạo lại trình phát; phần trang trí (title, skin) áp dụng khi tạo. <bust-play> không dùng Shadow DOM — cần ui.css có trên trang.

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 của hls.js
await attachDash(player, src, { protectionData: toDashProtectionData(drm) });
const off = enableFairPlay(player.media, drm.fairplay);                  // HLS native của Safari

Widevine/PlayReady do hls.js/dash.js xử lý; FairPlay trên đường native do lớp EME của chúng tôi đảm nhiệm (SPC/CKC dạng byte thô; biến thể phía server qua hook licenseBody/licenseResponse). Chạy thật cần máy chủ cấp phép.

Tiếp theo