Something went wrong. Try again.
Mirror of https://github.com/kualta/site — web infrastructure
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687import type Hls from "hls.js";import type { Fragment, Level } from "hls.js";
// Kept for the page session, as bsky.app does: later videos start from the measured// bandwidth instead of hls.js's 500 kbps guess, and a picked quality carries over.let bandwidthEstimate: number | undefined;let preferredQuality: string | undefined;
function levelLabel(level: Level): string { // Bluesky labels portrait renditions by their short side too (720x1280 is 720p). const size = Math.min(level.width, level.height) || level.height; return size ? `${size}p` : `${Math.round(level.bitrate / 1000)} kbps`;}
/** * A feed preview is muted, small and may never be watched, so it takes the * rendition that fits the card and buffers only a few seconds ahead. */export function createPreviewStream(HlsPlayer: typeof Hls): Hls { const hls = new HlsPlayer({ capLevelToPlayerSize: true, maxBufferLength: 10, startLevel: bandwidthEstimate === undefined ? -1 : HlsPlayer.DefaultConfig.startLevel, }); if (bandwidthEstimate !== undefined) hls.bandwidthEstimate = bandwidthEstimate; hls.on(HlsPlayer.Events.FRAG_LOADED, () => { bandwidthEstimate = hls.bandwidthEstimate; }); return hls;}
export function createVideoStream(HlsPlayer: typeof Hls, frame: HTMLElement): Hls { const quality = frame.querySelector<HTMLSelectElement>(".video-quality")!; const hls = new HlsPlayer({ // -1 measures bandwidth with a discarded fragment before choosing the first level. // Without an estimate, hls.js assumes 500 kbps and starts at the lowest rendition. startLevel: bandwidthEstimate === undefined && preferredQuality === undefined ? -1 : HlsPlayer.DefaultConfig.startLevel, }); if (bandwidthEstimate !== undefined) hls.bandwidthEstimate = bandwidthEstimate; hls.on(HlsPlayer.Events.FRAG_LOADED, () => { bandwidthEstimate = hls.bandwidthEstimate; });
// Buffered frames keep their quality after an upswitch, so flush them once auto picks better. let lowQualityFragments: Fragment[] = []; hls.on(HlsPlayer.Events.FRAG_BUFFERED, (_event, { frag }) => { if (frag.level < hls.levels.length - 1) lowQualityFragments.push(frag); }); hls.on(HlsPlayer.Events.FRAG_CHANGED, (_event, { frag }) => { if (!hls.autoLevelEnabled) return; const target = hls.nextAutoLevel; const kept: Fragment[] = []; for (const low of lowQualityFragments) { // The playing fragment cannot be replaced without a visible stall. if (low.level >= target || Math.abs(low.start - frag.start) < 0.1) { kept.push(low); continue; } hls.trigger(HlsPlayer.Events.BUFFER_FLUSHING, { startOffset: low.start, endOffset: low.end, type: "video" }); } lowQualityFragments = kept; });
hls.on(HlsPlayer.Events.MANIFEST_PARSED, () => { const options = hls.levels.map((level, index) => new Option(levelLabel(level), String(index))); quality.replaceChildren(new Option("Auto", "-1"), ...options.reverse()); quality.hidden = hls.levels.length < 2; const preferred = hls.levels.findIndex((level) => levelLabel(level) === preferredQuality); if (preferred > -1) { hls.currentLevel = preferred; quality.value = String(preferred); } }); hls.on(HlsPlayer.Events.LEVEL_SWITCHED, (_event, { level }) => { quality.options[0].text = hls.autoLevelEnabled ? `Auto (${levelLabel(hls.levels[level])})` : "Auto"; }); quality.addEventListener("change", () => { const index = Number(quality.value); preferredQuality = index < 0 ? undefined : levelLabel(hls.levels[index]); // A picked quality replaces the buffer at once; auto takes over from the next fragment. if (index < 0) hls.loadLevel = -1; else hls.currentLevel = index; }); return hls;}