OpenSite optimal video component with progressive enhancement and conditional streaming.
npm install @opensite/videoHigh‑performance, native‑like HTML5 video for the OpenSite ecosystem. It accepts a numeric mediaId, fetches the optimal variants from the DashTrack CDN, and renders the best source for the viewer’s device and browser. It upgrades to adaptive streaming on demand to keep initial bundles tiny.
Key points
- Renders a plain element (no wrapper, no default styles).
- Accepts all native props and ref; drop‑in replacement.
- Chooses the best source: native HLS (Safari) → WebM → MP4.
- Optional streaming upgrade using hls.js / dashjs via dynamic import.
- Poster behavior: poster prop overrides, false disables, or defaults to CDN poster_url.
Custom controls
- Renders custom controls when controls prop is set; native are always hidden.
- Autohides controls on inactivity; shows a centered play button overlay when paused.
- Clicking the poster/video toggles play/pause.
---
Core (required):
```
npm i @opensite/video
Streaming libraries (optional; only needed for non‑Safari HLS/DASH playback):
``
npm i hls.js dashjs
Notes
- hls.js and dashjs are dynamically imported at runtime only when needed.
- The component works without these packages for progressive playback and for native HLS on Safari/iOS.
---
Minimal (progressive playback, tiny bundle):
`tsx
import { Video } from '@opensite/video';
export function Hero({ mediaId }: { mediaId: number }) {
return (
mediaId={mediaId}
autoPlay
muted
loop
controls={false}
preload="metadata"
className="hero-video"
/>
);
}
`
Upgrade to adaptive streaming only on user interaction (e.g., first play):
`tsx`
Force adaptive streaming immediately (if available):
`tsx`
Prefer a progressive codec/size (optional):
`tsx`
Poster behavior:
- poster={"https://…"} → use provided URL.poster={false}
- → disable poster entirely.poster_url
- Poster omitted → auto‑use from CDN payload if provided.
---
Required
- mediaId: number — DashTrack media record ID used to fetch the media snapshot.
Optional
- cdnHost?: string — Override CDN origin. Default: https://edge.dashtrack.com.adaptiveStreaming?: boolean
- — Immediately attach HLS/DASH adapter when applicable.streamingOnInteraction?: boolean
- — Progressive first, upgrade on first play.streamingUpgrade?: boolean
- — Allow upgrades at all (default: true). Set false to force progressive.preferCodec?: 'HLS' | 'DASH' | 'WEBM' | 'MP4'
- — Preferred codec when multiple are present.preferSize?: 'sm' | 'md' | 'lg' | 'full'
- — Preferred progressive size variant.poster?: string | false
- — Poster override or disable; omitted defaults to CDN poster_url.onVideoData?: (data: VideoData) => void
- — Callback when CDN payload is loaded.
- All native
Direct src fallback
- You can omit mediaId and provide src to play a direct progressive asset (MP4/WebM). In this mode, no CDN request is performed and streaming adapters are not attached.
Ref
- The component forwards a ref to the underlying
---
- Default fetch URL: https://edge.dashtrack.com/assets/videos/.cdnHost
- Override origin via prop; path shape is fixed by the module.
- The response is cached at the module level to avoid redundant network calls.
Expected payload (subset)
`ts`
type VideoData = {
id: number;
name?: string;
media_type?: string;
poster_url?: string | null;
meta?: {
duration?: number;
duration_iso8601?: string;
content_manifest?: {
optimized_filename?: string;
title?: string;
summary?: string;
description?: string;
};
};
variants_data: {
variants: {
HLS?: {
cdn_master_playlist_url?: string;
origin_master_playlist_url?: string;
full_size?: string; // chosen playlist URL (CDN or origin)
rungs?: { height?: number; width?: number; bandwidth?: number; average_bandwidth?: number; bitrate_kbps?: number; segment_count?: number; encode_seconds?: number }[];
};
DASH?: {
cdn_manifest_url?: string;
origin_manifest_url?: string;
full_size?: string; // chosen manifest URL (CDN or origin)
};
PROGRESSIVE_MP4?: Partial
WEBM?: Partial
};
metadata?: { width?: number; height?: number };
};
};
---
Order of preference (auto mode)
1. Native HLS (Safari/iOS) via application/vnd.apple.mpegurl.hls.js
2. Progressive WebM (modern browsers) by preferred/available size.
3. Progressive MP4 (universal fallback) by preferred/available size.
4. If only streaming manifests exist and not natively supported, attach or dashjs when allowed.
You can override with preferCodec and preferSize as hints; the component will still ensure the final result is playable on the current browser.
---
- adaptiveStreaming — Attach streaming adapter immediately if an HLS or DASH manifest exists and the browser needs an adapter.streamingOnInteraction
- — Keep progressive first, then upgrade on first play event (recommended to minimize initial JS).streamingUpgrade={false}
- — Disable all upgrades and stick to progressive assets.
Adapters (dynamic imports)
- HLS (non‑Safari): hls.js via src/streaming/hls-adapter.dashjs
- DASH: via src/streaming/dash-adapter.
These imports happen only when required by the chosen streaming path.
---
- The component renders a custom control wrapper around a
- aria-label maps to meta.content_manifest.summary (trimmed to ~120 chars).title
- maps to meta.content_manifest.title when not provided.poster
- defaults to poster_url when not provided.preload
- defaults to metadata.width
- /height default to variants_data.metadata.{width,height} when not provided.controlsList
- automatically includes nodownload when rendering the download link to avoid the browser’s incorrect default file naming.
- A separate download link is rendered (by default) next to the
Example
`tsx`
---
- All network requests and capability detection happen in useEffect, so nothing runs on the server.
- On the server, the component renders a bare
---
Types are exported from the root module:
`ts`
import type { VideoData, PreferredCodec, PreferredSize } from '@opensite/video';
Useful types
- VideoData, Variants, VariantRungBrowserCapabilities
- , SelectedSourcePreferredCodec
- , PreferredSize
---
Recommended
`ts`
import { Video } from '@opensite/video';
Sub‑paths (advanced)
- @opensite/video/core — capability/source helpers@opensite/video/streaming/hls
- — HLS adapter (dynamic import normally handles this)@opensite/video/streaming/dash
- — DASH adapter (dynamic import normally handles this)
Package.json sets sideEffects: false and an exports map for optimal tree‑shaking.
---
Hero/Background (progressive only)
`tsx`
Interactive B‑Roll (upgrade on play)
`tsx`
Short‑Form (full streaming)
`tsx`
Custom poster and sizing
`tsx`
Using a ref
`tsx
const ref = useRef
// later
ref.current?.play();
`
Accessibility (reduced motion)
`tsx`
const prefersReducedMotion = window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
---
- Safari/iOS: native HLS supported.
- Chrome/Edge/Firefox: progressive WebM/MP4; optional HLS/DASH via adapters.
- The component automatically chooses the best playable source.
---
- No video appears
- Check mediaId and network tab for the CDN request.hls.js
- Verify your CDN returns at least one progressive asset or a streaming manifest.
- Streaming doesn’t start on non‑Safari
- Install and/or dashjs.adaptiveStreaming
- Ensure or streamingOnInteraction is set.poster
- Poster not shown
- If is omitted and the payload has no poster_url, no poster will be used.
---
- Capability detection and source selection are in src/core/.src/streaming/
- Streaming adapters (HLS/DASH) live in and are imported dynamically.src/utils/api.ts
- CDN integration is isolated in with lightweight caching.ECOSYSTEM_GUIDELINES.md`.
- The module follows the patterns outlined in
---
- Keep the component free of wrappers and default CSS.
- Preserve progressive‑first behavior; treat streaming as an upgrade.
- Maintain tree‑shakability and small initial bundle size.
- When extending functionality (e.g., custom controls), ensure features are optional and tree‑shakable.
---
Private module for the OpenSite ecosystem.