@cinesend/atlas-player-core
v0.2.0
Published
Framework-free playback engine for the CineSend Atlas player: media selection, DRM attachment and play-event reporting.
Maintainers
Readme
@cinesend/atlas-player-core
The framework-free playback engine behind the CineSend Atlas player: which media to play, how to attach it with DRM, how to report on it — and, since the hosted iframe and the React player were reconciled, how their shared controls behave and look.
Most people want @cinesend/atlas-player-react
instead. Use this package directly only if you are integrating without React.
npm i @cinesend/atlas-player-coreWhat it does
selectPlayback(media, keySystems)— decides what to play. Atlas sends both an HLS and a DASH manifest when both exist, because it cannot know which key system the client supports: FairPlay rides HLS, Widevine rides DASH. This picks, and falls back to whichever manifest is present.detectKeySystems()— asks the browser which key systems it has. Any failure answers "not FairPlay-only", which routes to DASH/Widevine — the path that works everywhere except Safari, so a detection failure degrades to the common case.attachStream(video, url, drm, signal?)— loads shaka-player on demand and attaches to your<video>. It owns none of the DOM.attachSource(video, source, signal?)— thesourcepath: a live channel's own HLS manifest, or a progressive file. Loads hls.js on demand where the browser has no native HLS, and hands the URL to the element where it does — so Safari never downloads the engine.EventsClient— the play-event loop: heartbeats while playing, a position anchor on pause, andplay_endon finish or teardown.bindPageLifecycle(events, options)— reports the page itself going away. A real unload sendsplay_end; a back/forward-cache entry sends a position anchor and leaves the session open, because the page can come back. Returns the unbind.
The chrome layer
The hosted iframe and @cinesend/atlas-player-react render their own markup —
one with innerHTML, one with elements — but everything behind that markup is
here, so the two players cannot drift apart again:
- Behaviour —
createStallWatcher(the 400 ms debounce that stops a spinner flashing over live frames),createIdleWatcher(the 5 s fade, pinned while paused),toggleFullscreen/watchFullscreen(the three fallback paths and both event families),playMaybeMuted,keyCommand,seekBy,seekToRatio,remainingLabel,isIOS,prefersMutedAutoplay. chromeIcons— the icon set as path data, plusiconSvg()for a caller building markup as a string.chromeStyles/ensureChromeStyles()— the stylesheet, and the class contract both players render against. A string rather than a.cssfile, so nothing has to be configured to consume it and nothing is injected unless a player asks.
None of it runs at import and none of it touches a framework. Import only the engine and none of it reaches your bundle.
Attachment ownership
You own the returned handle and must destroy() it, from either attach
function. A shaka Player — and an Hls instance — stays attached to the <video>
until destroyed, so attaching twice without destroying leaves two engines fighting
over one element, and on a live channel the abandoned one keeps pulling segments.
Where attachSource needed no engine at all, destroy() still detaches the
element (native HLS keeps streaming otherwise), and leaves a newer attachment on
the same element alone.
Pass an AbortSignal if the target can change mid-load: the dynamic import, the
FairPlay certificate fetch and the manifest load are all awaited, and without it a
cancelled attach still completes.
const attached = await attachStream(video, stream.dash, stream.drm, controller.signal);
// later
await attached.destroy();shaka-player and hls.js are dependencies but dynamically imported, so each lands
as a separate chunk in your bundle rather than in your entry — and a consumer who
only ever plays one kind of media only ever fetches one of them.
Licence
MIT
