@sentinel-nvr/web 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/player/rlog.ts","../../src/player/webrtc.ts","../../src/player/controller.ts"],"sourcesContent":["/**\n * Client telemetry → the plugin's `api/clientlog` → its server log as `[client]`\n * lines (phones have no console; this is how playback problems on a device get\n * diagnosed). `brand` tags which host emitted the line (e.g. 'sentinel', 'hapulse').\n */\n\nimport type { SentinelClient } from '../api';\n\nlet brand = 'web';\n\nlet client: SentinelClient | null = null;\n\nexport function setRlogClient(c: SentinelClient | null, b?: string): void {\n client = c;\n if (b) brand = b;\n}\n\nexport function rlog(tag: string, data?: Record<string, unknown>): void {\n if (!client) return;\n let line: string;\n try {\n line = JSON.stringify({ tag, b: brand, d: data ?? null, ua: navigator.userAgent.slice(0, 80) });\n } catch {\n line = JSON.stringify({ tag, b: brand });\n }\n client.postText('api/clientlog', line);\n}\n","/**\n * WebRTC session over the plugin's WebSocket signaling (docs/API.md §6).\n * Battle-tested flow: options first, createLocalDescription/setRemoteDescription\n * RPCs, trickle ICE, stream composed from ALL receivers (Safari attached an\n * audio-only stream forever when the audio track arrived first), fresh offer on\n * renegotiation, dec-check after connect with a one-time TURN-relay retry on a\n * media blackhole. The API client is injected (hosts may run on another origin).\n */\nimport type { SentinelClient } from '../api';\nimport { rlog } from './rlog';\n\nexport interface SessionCallbacks {\n onStream: (ms: MediaStream) => void;\n onFail: (reason: string) => void;\n onSessionId?: (id: string) => void;\n}\nexport interface SessionOptions { camId: string; mode: 'live' | 'recorded'; startMs?: number; compat?: boolean; forceRelay?: boolean; kind?: string; }\n\nlet forceRelayGlobal = false;\n\nexport function mobileClient(): boolean {\n return /iPhone|iPod|Android|Mobile/i.test(navigator.userAgent) || (navigator.maxTouchPoints > 1 && Math.min(screen.width || 9999, screen.height || 9999) < 920);\n}\nfunction rtcOptions() {\n let capabilities: unknown;\n try { capabilities = RTCRtpReceiver.getCapabilities ? { audio: RTCRtpReceiver.getCapabilities('audio'), video: RTCRtpReceiver.getCapabilities('video') } : undefined; } catch { /* none */ }\n return { userAgent: navigator.userAgent, capabilities, screen: { devicePixelRatio: window.devicePixelRatio || 1, width: screen.width || 1920, height: screen.height || 1080 } };\n}\n\nexport class WebRtcSession {\n ws: WebSocket | undefined; pc: RTCPeerConnection | undefined; id: string | undefined; active = false;\n private connectT: number | undefined; private trackSig = ''; private api: SentinelClient; private opts: SessionOptions; private cb: SessionCallbacks;\n constructor(api: SentinelClient, opts: SessionOptions, cb: SessionCallbacks) { this.api = api; this.opts = opts; this.cb = cb; }\n get connected(): boolean { const s = this.pc?.iceConnectionState; return s === 'connected' || s === 'completed'; }\n\n start(): void {\n const params: Record<string, string> = {};\n if (this.opts.mode === 'recorded') { params.mode = 'recorded'; params.start = String(Math.round(this.opts.startMs || 0)); }\n if (this.opts.compat ?? mobileClient()) params.compat = '1';\n let ws: WebSocket;\n try { ws = new WebSocket(this.api.signalingUrl(this.opts.camId, params)); } catch { this.cb.onFail('ws'); return; }\n this.ws = ws; this.active = true;\n this.connectT = window.setTimeout(() => {\n if (this.active && this.ws === ws && !this.connected) {\n rlog('connect-timeout', { kind: this.opts.mode, ice: this.pc?.iceConnectionState });\n if (!forceRelayGlobal) { forceRelayGlobal = true; rlog('retry-relay-only', { kind: this.opts.mode }); this.stop(); this.start(); return; }\n this.fail('timeout');\n }\n }, 12000);\n ws.onopen = () => { try { ws.send(JSON.stringify({ type: 'options', options: rtcOptions() })); } catch { /* ignore */ } };\n ws.onerror = () => { if (this.active && this.ws === ws && !this.pc) this.fail('ws-error'); };\n ws.onclose = () => { if (this.active && this.ws === ws && !this.connected) this.fail('ws-closed'); };\n ws.onmessage = (ev) => {\n let msg: any; try { msg = JSON.parse(ev.data); } catch { return; }\n if (msg.type === 'createLocalDescription') this.createLocal(ws, msg);\n else if (msg.type === 'setRemoteDescription') this.setRemote(ws, msg);\n else if (msg.type === 'addIceCandidate') this.pc?.addIceCandidate(msg.candidate).catch(() => { /* ignore */ });\n else if (msg.type === 'sessionStarted') { this.id = msg.id; this.cb.onSessionId?.(msg.id); }\n else if (msg.type === 'error') { if (this.active && this.ws === ws) this.fail(msg.reason || 'error'); }\n };\n }\n\n stop(): void {\n this.active = false;\n if (this.connectT) { clearTimeout(this.connectT); this.connectT = undefined; }\n try { if (this.ws) { this.ws.onmessage = null; this.ws.onclose = null; this.ws.onerror = null; this.ws.close(); } } catch { /* ignore */ }\n try { if (this.pc) { this.pc.ontrack = null; this.pc.oniceconnectionstatechange = null; this.pc.onicecandidate = null; this.pc.close(); } } catch { /* ignore */ }\n this.ws = undefined; this.pc = undefined; this.id = undefined; this.trackSig = '';\n }\n\n private fail(reason: string): void { if (!this.active) return; this.stop(); this.cb.onFail(reason); }\n\n private ensurePc(setup: any): RTCPeerConnection {\n if (this.pc) return this.pc;\n let cfg: RTCConfiguration = (setup && setup.configuration) || { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] };\n if (forceRelayGlobal) cfg = { ...cfg, iceTransportPolicy: 'relay' };\n const pc = new RTCPeerConnection(cfg);\n this.pc = pc;\n if (setup?.datachannel) { try { const dc = pc.createDataChannel(setup.datachannel.label, setup.datachannel.dict); dc.binaryType = 'arraybuffer'; } catch { /* ignore */ } }\n if (setup?.audio) { try { pc.addTransceiver('audio', { direction: setup.audio.direction || 'recvonly' }); } catch { /* ignore */ } }\n if (setup?.video) { try { pc.addTransceiver('video', { direction: setup.video.direction || 'recvonly' }); } catch { /* ignore */ } }\n pc.ontrack = () => {\n if (!this.active || this.pc !== pc) return;\n const ms = new MediaStream();\n pc.getReceivers().forEach(r => { if (r.track) ms.addTrack(r.track); });\n if (!ms.getVideoTracks().length) return; // audio-first: wait for the video event\n const sig = ms.getTracks().map(t => t.id).sort().join(',');\n if (this.trackSig === sig) return;\n this.trackSig = sig;\n this.cb.onStream(ms);\n };\n pc.oniceconnectionstatechange = () => {\n if (!this.active || this.pc !== pc) return;\n const st = pc.iceConnectionState;\n if (st === 'connected' || st === 'completed') {\n if (this.connectT) { clearTimeout(this.connectT); this.connectT = undefined; }\n window.setTimeout(() => {\n if (!this.active || this.pc !== pc) return;\n pc.getStats().then(s => {\n let dec = -1, recv = -1, vBytes = -1, aBytes = -1;\n s.forEach((r: any) => {\n if (r.type === 'inbound-rtp' && (r.kind || r.mediaType) === 'video') { dec = r.framesDecoded || 0; recv = r.framesReceived ?? -1; vBytes = r.bytesReceived || 0; }\n if (r.type === 'inbound-rtp' && (r.kind || r.mediaType) === 'audio') aBytes = r.bytesReceived || 0;\n });\n if (dec <= 0) {\n rlog('dec-check-fail', { kind: this.opts.mode, dec, recv, vBytes, aBytes, relayForced: forceRelayGlobal });\n if (!forceRelayGlobal && vBytes <= 0 && aBytes <= 0) { forceRelayGlobal = true; rlog('retry-relay-only', { kind: this.opts.mode }); this.stop(); this.start(); return; }\n this.fail('no-decode');\n }\n else rlog('dec-ok', { kind: this.opts.mode, dec, relayForced: forceRelayGlobal });\n }).catch(() => { /* ignore */ });\n }, this.opts.mode === 'live' ? 5000 : 9000);\n }\n if (st === 'failed') { rlog('ice-failed', { kind: this.opts.mode }); this.fail('ice-failed'); }\n };\n return pc;\n }\n\n private createLocal(ws: WebSocket, msg: any): void {\n const pc = this.ensurePc(msg.setup);\n const mid = this.connected;\n if (mid) rlog('reneg', { dtype: msg.dtype, kind: this.opts.mode });\n const reply = (desc: RTCSessionDescriptionInit) => { try { ws.send(JSON.stringify({ type: 'response', reqId: msg.reqId, description: { type: desc.type, sdp: desc.sdp } })); } catch { /* ignore */ } };\n pc.onicecandidate = (ev) => { if (ev.candidate) { try { ws.send(JSON.stringify({ type: 'iceCandidate', candidate: JSON.parse(JSON.stringify(ev.candidate)) })); } catch { /* ignore */ } } };\n const p = msg.dtype === 'offer'\n ? pc.createOffer({ offerToReceiveAudio: !!msg.setup?.audio, offerToReceiveVideo: !!msg.setup?.video }).then(o => pc.setLocalDescription(o).then(() => reply(o)))\n : pc.createAnswer().then(a => pc.setLocalDescription(a).then(() => reply(a)));\n p.catch(e => { rlog('createLocal-fail', { dtype: msg.dtype, name: e?.name, mid }); if (!mid) this.fail('createLocal'); });\n }\n\n private setRemote(ws: WebSocket, msg: any): void {\n const pc = this.ensurePc(msg.setup);\n const mid = this.connected;\n pc.setRemoteDescription(msg.description)\n .then(() => { try { ws.send(JSON.stringify({ type: 'response', reqId: msg.reqId, ok: true })); } catch { /* ignore */ } })\n .catch(e => { rlog('sRD-fail', { name: e?.name, mid }); try { ws.send(JSON.stringify({ type: 'response', reqId: msg.reqId, ok: false })); } catch { /* ignore */ } if (!mid) this.fail('sRD'); });\n }\n}\n","/**\n * PlayerController — the whole playback brain of the NVR. Framework-free: it owns\n * a <video>, a freeze <canvas> and an MJPEG <img> inside a stage element, and\n * reports state through `onState`; the host only renders what it says.\n *\n * Host seams: the API client is injected; status labels are i18n KEY suffixes\n * (`nvr.player.<label>`) the host translates; `storagePrefix` namespaces the\n * remembered stage aspect per camera; `brand` tags telemetry lines. The MSE paths\n * are gated on `SentinelClient.corsMedia`; posters load with crossOrigin so the\n * freeze canvas stays untainted. The host CSS must define a `.hidden` class.\n *\n * Paths: LIVE = WebRTC (sink) → MSE live (fMP4, no audio) → MJPEG <img>.\n * RECORDED = WebRTC relay (server-seekable, scrub time-lapse in place) →\n * MSE fallback (progressive segments, trick-play chase) → native <video src>.\n */\nimport type { SentinelClip as Clip, SentinelClient } from '../api';\nimport { rlog, setRlogClient } from './rlog';\nimport { WebRtcSession, mobileClient } from './webrtc';\n\n/** `label` is an i18n key suffix: nvr.player.<label> */\nexport type PlayerLabel = 'live' | 'liveWebrtc' | 'liveMse' | 'liveMjpeg' | 'loading' | 'playing' | 'paused' | 'scrub' | 'noRecording' | '';\nexport interface PlayerState {\n live: boolean; label: PlayerLabel; playhead: number | null; rate: number; sound: boolean; paused: boolean;\n transport: 'webrtc' | 'mse' | 'mjpeg' | 'relay' | 'native' | 'none'; muted: boolean;\n}\nexport interface PlayerRefs { video: HTMLVideoElement; freeze: HTMLCanvasElement; img: HTMLImageElement; stage: HTMLElement; }\nexport interface PlayerOptions {\n onState: (s: PlayerState) => void;\n onClipsRefresh: () => Promise<Clip[]>;\n /** localStorage key prefix for the remembered stage aspect per camera (default 'snvr-ar-'). */\n storagePrefix?: string;\n /** telemetry brand tag written into api/clientlog lines (default 'web'). */\n brand?: string;\n}\ntype Opts = PlayerOptions;\n\nconst MSCls: typeof MediaSource | undefined = (window as any).ManagedMediaSource || window.MediaSource;\n\nexport class PlayerController {\n private v!: HTMLVideoElement; private fz!: HTMLCanvasElement; private img!: HTMLImageElement; private stage!: HTMLElement;\n private api: SentinelClient; private opts: Opts;\n camId = ''; camName = ''; clips: Clip[] = []; codecs: string | null = null; rangeStart = 0; rangeEnd = 0;\n live = false; rate = 1; soundOn = false; recPaused = false; recPausedTs: number | null = null;\n recWebrtcDisabled = false; label: PlayerLabel = ''; transport: PlayerState['transport'] = 'none';\n // relay session (RW)\n private rw: WebRtcSession | undefined; private rwStartMs = 0; private rwBase: number | null = null; private rwPosTs: number | null = null; private rwPosAt = 0;\n private rwRate = 1; private rwSrate = 1; private rwScrub = false; private rwSeekBusy = false; private rwPending: { ts: number; rate: number; srate: number } | null = null;\n private rwLastSeekTs: number | null = null; private rwLastSeekAt = 0; private rwRateBusy = false; private rwPendingRate: number | null = null; private rwLastRateAt = 0;\n private relayPoll: number | undefined; private wdLastCt = -1; private wdLastAt = 0; private wdDead = 0; private wdGrace = 0; private wdResumeLogged = false; private recoveries = 0;\n private posterUntilSeek = false; private seekTarget = 0;\n // relay-pos answers are only valid for the command generation they were asked under; a poll sent BEFORE a\n // seek/rate change and answered after it would drag the playhead back to the old position (and the\n // auto-follow timeline with it → visible back-and-forth). seekAt: the server may still report the pre-swap\n // position for a moment after a seek — ignore far-off values in that window.\n private cmdSeq = 0; private seekAt = 0;\n // live session (W) + live MSE (L)\n private w: WebRtcSession | undefined; private L = { active: false, ms: null as MediaSource | null, sb: null as SourceBuffer | null, abort: null as AbortController | null, queue: [] as Uint8Array[], restarts: 0, lastTrim: 0, stallT: 0 };\n // recorded MSE (M)\n private M = { ms: null as MediaSource | null, sb: null as SourceBuffer | null, base: 0, nextIdx: -1, end: 0, active: false, feeding: false, abort: null as AbortController | null, q: [] as Uint8Array[], segFirst: false, segOff: 0, pendingSeek: null as number | null, mmsGo: true };\n private CH = { active: false, target: 0, timer: 0 };\n private curClipId: string | null = null; private playIndex = -1; private lastLoad = 0; private pendingTs: number | null = null; private pendingT: number | undefined;\n // frame counter / freeze\n private fc = { n: 0, tok: {} as object }; private freezeT = 0; private freezeTok: object | null = null;\n private cad = { t: 0, last: -1, lastNew: 0, stalls: 0, maxStall: 0, frames0: -1, t0: 0, gapMax: 0 };\n private stallTimer = 0; private destroyed = false;\n private unlisten: (() => void)[] = [];\n\n private arPrefix: string;\n constructor(api: SentinelClient, opts: Opts) { this.api = api; this.opts = opts; this.arPrefix = opts.storagePrefix ?? 'snvr-ar-'; setRlogClient(api, opts.brand); }\n\n attach(r: PlayerRefs): void {\n this.v = r.video; this.fz = r.freeze; this.img = r.img; this.stage = r.stage;\n const v = this.v;\n const on = (n: string, f: () => void) => { v.addEventListener(n, f); this.unlisten.push(() => v.removeEventListener(n, f)); };\n on('timeupdate', () => { if (this.live) return; if (this.rw?.active && this.rwBase == null && v.currentTime > 0) this.rwBase = v.currentTime; const ts = this.currentTs(); if (ts == null) return; if (this.M.active || this.rw?.active) { const i = this.clipIndexFor(ts); if (i >= 0) this.playIndex = i; } this.feed(); this.emit(); });\n on('waiting', () => { if (this.live) { if (this.L.active && !this.L.stallT) this.L.stallT = window.setTimeout(() => { this.L.stallT = 0; if (this.live && this.L.active && v.readyState < 3) this.liveRestart(); }, 4000); return; } if (!this.rw?.active) this.setLabel('loading'); if (!this.M.active || this.stallTimer) return; this.stallTimer = window.setTimeout(() => { this.stallTimer = 0; this.handleStall(); }, 600); });\n on('seeking', () => { if (!this.live && !this.rw?.active) this.setLabel('loading'); });\n for (const n of ['loadeddata', 'playing', 'canplay', 'seeked']) on(n, () => { if (v.videoWidth) this.freezeHide(); if (!this.live && this.label === 'loading') this.setLabel('playing'); if (this.L.stallT) { clearTimeout(this.L.stallT); this.L.stallT = 0; } this.emit(); });\n on('pause', () => { if (this.L.stallT) { clearTimeout(this.L.stallT); this.L.stallT = 0; } this.emit(); });\n on('play', () => this.emit());\n // the stage box follows the picture's real aspect where the layout uses it (mobile: no letterbox bars for 4:3 cameras)\n on('loadedmetadata', () => this.setAspect(this.v.videoWidth, this.v.videoHeight));\n on('resize', () => this.setAspect(this.v.videoWidth, this.v.videoHeight));\n on('volumechange', () => this.emit());\n on('error', () => { const e = v.error; rlog('video-error', { code: e?.code, msg: e?.message?.slice(0, 120), src: v.getAttribute('src') ? 'src' : 'srcObject' }); });\n on('ended', () => { if (this.live || this.M.active || this.rw?.active) return; const n = this.playIndex + 1; if (n < this.clips.length) { const c = this.clips[n]!; this.curClipId = c.id; this.playIndex = n; v.src = this.api.url(`api/segment?id=${encodeURIComponent(c.videoId || c.id)}`); v.load(); v.onloadedmetadata = () => { v.playbackRate = this.rate; try { v.currentTime = 0; } catch { /* ignore */ } this.safePlay(); }; this.setLabel('playing'); } });\n this.pendingT = window.setInterval(() => { if (this.pendingTs != null && Date.now() - this.lastLoad >= 200) { const t = this.pendingTs; this.pendingTs = null; this.playAt(t, { scrub: true }); } }, 120);\n const vis = () => this.onVisibility(); document.addEventListener('visibilitychange', vis); this.unlisten.push(() => document.removeEventListener('visibilitychange', vis));\n const edge = window.setInterval(() => { if (this.live && this.L.active) this.liveEdge(); }, 1000); this.unlisten.push(() => clearInterval(edge));\n }\n\n destroy(): void {\n this.destroyed = true;\n this.recWebrtcTeardown(); this.webrtcTeardown(); this.mseTeardown(); this.liveTeardown(); this.chaseAbort();\n if (this.pendingT) clearInterval(this.pendingT);\n for (const u of this.unlisten) u();\n try { this.v.pause(); this.v.srcObject = null; this.v.removeAttribute('src'); } catch { /* ignore */ }\n }\n\n setCamera(camId: string, name: string): void {\n if (camId !== this.camId) { this.recWebrtcDisabled = false; }\n this.camId = camId; this.camName = name;\n // last known picture aspect of this camera: the stage has the right shape before any poster/video arrives\n let ar = ''; try { ar = localStorage.getItem(this.arPrefix + camId) || ''; } catch { /* ignore */ }\n if (ar) this.stage.style.setProperty('--stage-ar', ar); else this.stage.style.removeProperty('--stage-ar');\n }\n /** picture aspect → stage box (mobile layout uses it); posters and video both report it */\n private setAspect(w: number, h: number): void {\n if (!w || !h) return;\n const ar = `${w} / ${h}`;\n if (this.stage.style.getPropertyValue('--stage-ar') === ar) return;\n this.stage.style.setProperty('--stage-ar', ar);\n try { localStorage.setItem(this.arPrefix + this.camId, ar); } catch { /* ignore */ }\n }\n /** clips of the loaded range (several days, sorted), codec string, and the range the timeline spans */\n setClips(clips: Clip[], codecs: string | null, rangeStart: number, rangeEnd: number): void { this.clips = clips; this.codecs = codecs; this.rangeStart = rangeStart; this.rangeEnd = rangeEnd; }\n\n // ---- state ---------------------------------------------------------------------\n private setLabel(l: PlayerLabel): void { this.label = l; this.emit(); }\n private emit(): void {\n if (this.destroyed) return;\n this.opts.onState({ live: this.live, label: this.label, playhead: this.live ? null : this.currentTs(), rate: this.rate, sound: this.soundOn, paused: this.recPaused || (this.v.paused && !this.live && !this.rw?.active), transport: this.transport, muted: this.v.muted });\n }\n clipIndexFor(ts: number): number { for (let i = 0; i < this.clips.length; i++) { const c = this.clips[i]!; if (ts >= c.startTime && ts < c.startTime + (c.duration || 60000)) return i; } return -1; }\n private nearNow(ts: number): boolean { return Date.now() - ts < 8000; }\n private clampRange(ts: number): number { return Math.min(Math.max(ts, this.rangeStart), Math.min(this.rangeEnd - 1, Date.now())); }\n\n /** Wall-clock position of the picture on screen (Scrypted's getRecordingStreamCurrentTime). */\n currentTs(): number | null {\n if (this.rw?.active) {\n if (this.rwPosTs != null) return this.rwPosTs + (Date.now() - this.rwPosAt) * (this.rwRate || 1);\n if (this.rwBase != null && this.v.currentTime > 0) return this.rwStartMs + (this.v.currentTime - this.rwBase) * 1000 * (this.rwRate || 1);\n return this.rwStartMs;\n }\n if (this.recPaused) return this.recPausedTs;\n if (this.live) return null;\n if (this.M.active) return this.M.base + this.v.currentTime * 1000;\n const pc = this.playIndex >= 0 ? this.clips[this.playIndex] : undefined; if (pc) return pc.startTime + this.v.currentTime * 1000;\n return null;\n }\n\n // ---- presented frames / freeze / poster -----------------------------------------\n private fcArm(): void { const v: any = this.v; if (!v.requestVideoFrameCallback) return; const tok = {}; this.fc.tok = tok; const tick = () => { if (this.fc.tok !== tok) return; this.fc.n++; try { v.requestVideoFrameCallback(tick); } catch { /* ignore */ } }; try { v.requestVideoFrameCallback(tick); } catch { /* ignore */ } }\n presentedFrames(): number { if ((this.v as any).requestVideoFrameCallback) return this.fc.n; try { return this.v.getVideoPlaybackQuality().totalVideoFrames; } catch { return -1; } }\n private freezeArm(hold: boolean): void {\n if (this.freezeT) clearTimeout(this.freezeT);\n this.freezeT = window.setTimeout(() => this.freezeHide(), hold ? 90000 : 5000);\n const v: any = this.v;\n if (hold && v.requestVideoFrameCallback) { const tok = {}; this.freezeTok = tok; try { v.requestVideoFrameCallback(() => { if (this.freezeTok === tok && this.v.videoWidth) this.freezeHide(); }); } catch { /* ignore */ } }\n }\n freezeShow(hold = false): void {\n try {\n const v = this.v, fc = this.fz;\n if (!v.videoWidth || !v.videoHeight || v.readyState < 2) return;\n if (fc.width !== v.videoWidth) fc.width = v.videoWidth;\n if (fc.height !== v.videoHeight) fc.height = v.videoHeight;\n fc.getContext('2d')!.drawImage(v, 0, 0, fc.width, fc.height);\n fc.classList.remove('hidden'); fc.dataset.src = 'video';\n this.freezeArm(hold);\n } catch { /* ignore */ }\n }\n freezeFromImage(img: HTMLImageElement, hold: boolean, untilSeek = false, kind = 'image'): boolean {\n try {\n if (!img.naturalWidth || !img.naturalHeight) return false;\n const fc = this.fz; fc.width = img.naturalWidth; fc.height = img.naturalHeight; fc.getContext('2d')!.drawImage(img, 0, 0); fc.classList.remove('hidden'); fc.dataset.src = kind;\n this.setAspect(img.naturalWidth, img.naturalHeight);\n if (untilSeek) {\n if (this.freezeT) clearTimeout(this.freezeT); this.freezeTok = null;\n // stays until relay-pos reports the picture AT the target (see startRelayPoll); 6 s safety net\n this.posterUntilSeek = true; this.freezeT = window.setTimeout(() => this.freezeHide(), 6000);\n }\n else this.freezeArm(hold);\n return true;\n } catch { return false; }\n }\n freezeHide(): void { if (this.freezeT) { clearTimeout(this.freezeT); this.freezeT = 0; } this.posterUntilSeek = false; this.fz.classList.add('hidden'); delete this.fz.dataset.src; }\n private posterUp(): boolean { return !this.fz.classList.contains('hidden'); }\n freezeHold(): void { if (this.freezeT) { clearTimeout(this.freezeT); this.freezeT = window.setTimeout(() => this.freezeHide(), 5000); } }\n /** Event click: the stored frame is the poster until the seek lands. */\n posterEvent(ts: number): void { const cam = this.camId; const img = new Image(); img.crossOrigin = 'anonymous'; img.onload = () => { if (this.camId !== cam) return; this.freezeFromImage(img, true, !!this.rw?.active && !!this.rw.id, 'event'); }; img.src = this.api.url(`api/evframe?camera=${encodeURIComponent(cam)}&ts=${ts}`); }\n /** Camera opened: newest snapshot in front of the black stage until live plays. */\n posterFromSnapshot(): void { const cam = this.camId; const img = new Image(); img.crossOrigin = 'anonymous'; img.onload = () => { if (this.camId !== cam || this.rw?.active || this.recPaused || this.posterUp()) return; if (this.v.readyState >= 2 && this.v.videoWidth && !this.v.paused) return; this.freezeFromImage(img, true, false, 'snapshot'); }; img.src = this.api.url(`api/snapshot?camera=${encodeURIComponent(cam)}`) + `&_=${Date.now()}`; }\n private posterShow(ts: number): void { try { if (this.posterUp()) return; if (this.v.readyState >= 2 && this.v.videoWidth) return; const i = this.clipIndexFor(ts); const c = i >= 0 ? this.clips[i] : undefined; if (!c?.thumbnailId) return; const img = new Image(); img.crossOrigin = 'anonymous'; img.onload = () => { if (!this.posterUp()) this.freezeFromImage(img, true, false, 'thumb'); }; img.src = this.api.url(`api/thumb?id=${encodeURIComponent(c.thumbnailId)}`); } catch { /* ignore */ } }\n\n private safePlay(): void {\n let pr: Promise<void>; try { pr = this.v.play(); } catch { return; }\n pr.then(() => this.emit()).catch((e1) => { this.v.muted = true; this.v.play().then(() => this.emit()).catch((e2) => rlog('play-fail', { e1: e1?.name, e2: e2?.name, rs: this.v.readyState, paused: this.v.paused })); });\n }\n\n // ---- LIVE ---------------------------------------------------------------------------\n goLive(): void {\n if (!this.camId) return;\n this.chaseAbort();\n this.freezeShow(true);\n this.exitLiveState(); this.recWebrtcTeardown(); this.recPaused = false; this.live = true; this.playIndex = -1; this.curClipId = null; this.L.restarts = 0;\n this.setLabel('live');\n if (document.visibilityState === 'hidden') return;\n if (window.RTCPeerConnection && window.WebSocket) this.liveStartWebrtc();\n else if (this.liveMseOk()) this.liveStartMse();\n else { try { this.v.pause(); } catch { /* ignore */ } this.liveFallbackImg(); }\n }\n private exitLiveState(): void { if (this.live) { this.live = false; this.webrtcTeardown(); this.liveTeardown(); try { this.v.srcObject = null; } catch { /* ignore */ } this.setMjpeg(false); } }\n private setMjpeg(on: boolean): void { this.img.classList.toggle('hidden', !on); this.v.classList.toggle('hidden', on); if (!on) this.img.removeAttribute('src'); }\n private webrtcTeardown(): void { this.w?.stop(); this.w = undefined; }\n private liveStartWebrtc(): void {\n this.webrtcTeardown(); this.recWebrtcTeardown(); this.mseTeardown(); this.liveTeardown();\n try { this.v.pause(); } catch { /* ignore */ } try { this.v.srcObject = null; } catch { /* ignore */ } this.v.removeAttribute('src');\n this.setMjpeg(false);\n const s = new WebRtcSession(this.api, { camId: this.camId, mode: 'live' }, {\n onStream: (ms) => { if (!this.live || this.w !== s) return; this.setMjpeg(false); this.v.muted = !this.soundOn; try { this.v.removeAttribute('src'); } catch { /* ignore */ } try { this.v.srcObject = ms; } catch { /* ignore */ } this.fcArm(); this.safePlay(); this.transport = 'webrtc'; this.setLabel('liveWebrtc'); },\n onFail: () => { if (this.w === s) this.liveFallbackMse(); },\n });\n this.w = s; this.transport = 'webrtc'; s.start();\n }\n private liveFallbackMse(): void { this.webrtcTeardown(); if (!this.live) return; try { this.v.srcObject = null; } catch { /* ignore */ } if (this.liveMseOk()) this.liveStartMse(); else this.liveFallbackImg(); }\n private liveCodec(): string | null { return this.codecs ? (this.codecs.split(',')[0] ?? null) : null; }\n private liveMseOk(): boolean { try { const c = this.liveCodec(); return !!(this.api.corsMedia && MSCls && c && MSCls.isTypeSupported(`video/mp4; codecs=\"${c}\"`)); } catch { return false; } }\n private liveTeardown(): void { const L = this.L; L.active = false; L.queue = []; if (L.stallT) { clearTimeout(L.stallT); L.stallT = 0; } try { L.abort?.abort(); } catch { /* ignore */ } L.abort = null; if (L.sb && L.ms && L.ms.readyState === 'open') { try { L.sb.abort(); } catch { /* ignore */ } } L.sb = null; L.ms = null; }\n private liveAppend(): void { const L = this.L; if (!L.active || !L.sb || L.sb.updating || !L.queue.length) return; const buf = L.queue.shift()!; try { L.sb.appendBuffer(buf as BufferSource); } catch { this.liveRestart(); } }\n private liveTrim(): void { const L = this.L; if (!L.sb || L.sb.updating) return; try { const b = this.v.buffered; if (b.length && this.v.currentTime - b.start(0) > 30) L.sb.remove(0, this.v.currentTime - 10); } catch { /* ignore */ } }\n private liveEdge(): void { try { const b = this.v.buffered; if (!b.length) return; const end = b.end(b.length - 1); if (end - this.v.currentTime > 2.5) this.v.currentTime = end - 0.7; if (this.v.paused) this.safePlay(); } catch { /* ignore */ } }\n private liveRestart(): void { if (!this.live || !this.L.active) return; this.liveTeardown(); this.L.restarts++; if (this.L.restarts > 5) { this.liveFallbackImg(); return; } window.setTimeout(() => { if (this.live) this.liveStartMse(); }, 1000); }\n private liveStartMse(): void {\n this.liveTeardown(); this.mseTeardown();\n const L = this.L; L.active = true; this.transport = 'mse'; this.setLabel('liveMse'); this.setMjpeg(false);\n const ms = new MSCls!(); L.ms = ms; L.lastTrim = Date.now();\n if ((window as any).ManagedMediaSource && ms instanceof (window as any).ManagedMediaSource) { try { (this.v as any).disableRemotePlayback = true; } catch { /* ignore */ } }\n const u = URL.createObjectURL(ms);\n ms.addEventListener('sourceopen', () => {\n URL.revokeObjectURL(u); if (L.ms !== ms) return;\n let sb: SourceBuffer; try { sb = ms.addSourceBuffer(`video/mp4; codecs=\"${this.liveCodec()}\"`); } catch { this.liveFallbackImg(); return; }\n sb.mode = 'segments';\n sb.addEventListener('updateend', () => { if (Date.now() - L.lastTrim > 10000) { L.lastTrim = Date.now(); this.liveTrim(); } this.liveAppend(); });\n sb.addEventListener('error', () => this.liveRestart());\n L.sb = sb; L.abort = new AbortController();\n fetch(this.api.url(`api/livemse?camera=${encodeURIComponent(this.camId)}`), { credentials: 'same-origin', signal: L.abort.signal })\n .then(r => { if (!r.ok || !r.body) throw new Error(String(r.status)); const rd = r.body.getReader(); const loop = () => { rd.read().then(x => { if (!L.active || L.ms !== ms) return; if (x.done) { this.liveRestart(); return; } L.queue.push(x.value); this.liveAppend(); loop(); }).catch(() => { if (L.active && L.ms === ms) this.liveRestart(); }); }; loop(); })\n .catch(() => { if (L.active && L.ms === ms) this.liveFallbackImg(); });\n });\n try { this.v.srcObject = null; } catch { /* ignore */ }\n this.v.src = u; this.v.playbackRate = 1; this.v.muted = true; this.safePlay();\n }\n private liveFallbackImg(): void { this.liveTeardown(); if (!this.live) return; try { this.v.pause(); } catch { /* ignore */ } this.freezeHide(); this.transport = 'mjpeg'; this.setLabel('liveMjpeg'); this.setMjpeg(true); this.img.src = this.api.url(`api/live?camera=${encodeURIComponent(this.camId)}`) + `&_=${Date.now()}`; }\n\n // ---- RECORDED via relay -----------------------------------------------------------------\n private recWebrtcOk(): boolean { return !this.recWebrtcDisabled && !!(window.RTCPeerConnection && window.WebSocket); }\n private recWebrtcTeardown(): void { this.posterUntilSeek = false; this.stopRelayPoll(); this.rw?.stop(); this.rw = undefined; this.rwBase = null; this.rwPosTs = null; this.rwScrub = false; this.rwSeekBusy = false; this.rwPending = null; this.rwLastSeekTs = null; this.rwSrate = 1; this.rwRate = 1; this.rwRateBusy = false; this.rwPendingRate = null; }\n private recWebrtcStart(ts: number): void {\n this.freezeShow(true); this.posterShow(ts);\n this.live = false;\n this.recWebrtcTeardown(); this.webrtcTeardown(); this.mseTeardown(); this.liveTeardown();\n try { this.v.pause(); } catch { /* ignore */ } try { this.v.removeAttribute('src'); this.v.srcObject = null; } catch { /* ignore */ }\n this.setMjpeg(false); this.transport = 'relay';\n this.setLabel('loading');\n this.rwStartMs = ts; this.rwBase = null; this.rwRate = this.rate; this.rwSrate = 1; this.seekTarget = ts; // event poster clears when relay-pos reaches here\n const compat = mobileClient();\n if (compat) rlog('rec-compat-start', { ts: Math.round(ts) });\n const s = new WebRtcSession(this.api, { camId: this.camId, mode: 'recorded', startMs: ts, compat }, {\n onStream: (ms) => {\n if (this.rw !== s || this.live) return;\n try { s.pc?.getReceivers().forEach(r => { try { (r as any).jitterBufferTarget = 500; } catch { /* ignore */ } try { (r as any).playoutDelayHint = 0.5; } catch { /* ignore */ } }); } catch { /* ignore */ }\n this.setMjpeg(false); this.v.muted = !this.soundOn || this.rate !== 1;\n try { this.v.removeAttribute('src'); } catch { /* ignore */ } try { this.v.srcObject = ms; } catch { /* ignore */ }\n this.fcArm(); this.rwBase = null; this.safePlay(); this.setLabel('playing');\n },\n onFail: () => { if (this.rw === s) this.recFallbackMse(ts); },\n onSessionId: () => { if (this.rw === s && this.rwPending) { const p = this.rwPending; this.rwPending = null; if (Math.abs(p.ts - this.rwStartMs) > 1500) this.recRelaySeek(p.ts, p.rate, p.srate); } },\n });\n this.rw = s; s.start(); this.startRelayPoll(); this.emit();\n }\n private recFallbackMse(ts: number): void { rlog('rec-fallback-mse', { mseOk: this.mseSupported() }); this.recWebrtcDisabled = true; this.recWebrtcTeardown(); if (this.live || this.destroyed) return; this.playAt(ts, {}); }\n /** Hard server-side seek, coalesced: one in flight, latest wins, 150 ms floor. */\n private recRelaySeek(ts: number, rate = 1, srate = 1): void {\n const s = this.rw; if (!s?.id) return;\n if (this.rwSeekBusy) { this.rwPending = { ts, rate, srate }; return; }\n if (this.rwLastSeekTs === ts && this.rwRate === rate && this.rwSrate === srate && Date.now() - this.rwLastSeekAt < 1000) return;\n const wait = 150 - (Date.now() - this.rwLastSeekAt);\n if (wait > 0) { this.rwSeekBusy = true; this.rwPending = { ts, rate, srate }; window.setTimeout(() => { this.rwSeekBusy = false; const p = this.rwPending; this.rwPending = null; if (p && this.rw?.id) this.recRelaySeek(p.ts, p.rate, p.srate); }, wait); return; }\n this.rwStartMs = ts; this.rwSrate = srate; this.rwRate = this.rwScrub ? srate : rate; this.rwPendingRate = null; this.rwLastSeekTs = ts; this.rwLastSeekAt = Date.now();\n this.cad.lastNew = Date.now(); this.wdLastCt = -1; this.wdLastAt = Date.now(); this.wdGrace = Date.now() + 5000;\n this.rwPosTs = ts; this.rwPosAt = Date.now();\n this.setLabel('loading');\n this.rwSeekBusy = true;\n this.seekTarget = ts; this.seekAt = Date.now(); this.cmdSeq++;\n const done = (ok: boolean) => { this.rwSeekBusy = false; if (!ok) { this.relayRecover(); return; } const p = this.rwPending; this.rwPending = null; if (p && this.rw?.id) this.recRelaySeek(p.ts, p.rate, p.srate); };\n this.api.control(`api/relay-seek?session=${encodeURIComponent(s.id)}&start=${Math.round(ts)}&rate=${rate}&srate=${srate}`).then(ok => done(ok));\n }\n /** Scrub time-lapse rate, coalesced (120 ms floor, 15 % hysteresis). */\n private recRelayRate(r: number): void {\n const s = this.rw; if (!s?.active || !s.id || !this.rwScrub) return;\n if (this.rwRateBusy) { this.rwPendingRate = r; return; }\n if (this.rwSrate === r) return;\n if (this.rwSrate !== 1 && (r > 0) === (this.rwSrate > 0) && Math.abs(r - this.rwSrate) < 0.15 * Math.abs(this.rwSrate)) return;\n const wait = 120 - (Date.now() - this.rwLastRateAt);\n if (wait > 0) { this.rwRateBusy = true; this.rwPendingRate = r; window.setTimeout(() => { this.rwRateBusy = false; const p = this.rwPendingRate; this.rwPendingRate = null; if (p != null && this.rw?.id) this.recRelayRate(p); }, wait); return; }\n const c = this.currentTs(); this.rwSrate = r; this.rwRate = r; this.rwLastRateAt = Date.now(); this.cmdSeq++; if (c != null) { this.rwPosTs = c; this.rwPosAt = Date.now(); }\n this.wdGrace = Date.now() + 8000; this.cad.lastNew = Date.now();\n this.rwRateBusy = true;\n this.api.control(`api/relay-rate?session=${encodeURIComponent(s.id)}&rate=${r}`).then(ok => { if (!ok) this.relayRecover(); }).then(() => { this.rwRateBusy = false; const p = this.rwPendingRate; this.rwPendingRate = null; if (p != null && this.rw?.id && p !== this.rwSrate) this.recRelayRate(p); });\n }\n private recRelayScrub(on: boolean): void {\n const s = this.rw; if (!s?.active || !s.id || this.rwScrub === on) return;\n this.rwScrub = on;\n this.cmdSeq++;\n if (!on) { const c = this.currentTs(); this.rwSrate = 1; this.rwRate = this.rate; this.rwPendingRate = null; if (c != null) { this.rwPosTs = c; this.rwPosAt = Date.now(); } }\n this.wdLastCt = -1; this.wdLastAt = Date.now(); this.wdGrace = Date.now() + 5000; this.cad.lastNew = Date.now();\n this.api.control(`api/relay-scrub?session=${encodeURIComponent(s.id)}&on=${on ? 1 : 0}`).then(ok => { if (!ok) this.relayRecover(); });\n }\n private relayRecover(): void {\n if (!this.rw?.active) return;\n const t = this.rwPosTs ?? this.rwStartMs;\n this.recoveries++; rlog('relay-recover', { n: this.recoveries });\n if (this.recoveries > 2) { this.recFallbackMse(t); return; }\n this.recWebrtcStart(t);\n }\n private startRelayPoll(): void {\n if (this.relayPoll) return;\n this.cadStart(); this.wdLastCt = -1; this.wdLastAt = Date.now(); this.wdDead = 0; this.wdGrace = Date.now() + 8000;\n this.relayPoll = window.setInterval(() => {\n const s = this.rw; const v = this.v; if (!s?.active || !s.id) return;\n const q = this.presentedFrames();\n if (v.paused && !this.recPaused && !document.hidden) { if (!this.wdResumeLogged) { this.wdResumeLogged = true; rlog('auto-resume', { rs: v.readyState }); } this.safePlay(); } else if (!v.paused) this.wdResumeLogged = false;\n if (!v.paused && !document.hidden && this.rwBase != null) {\n if (q !== this.wdLastCt) { this.wdLastCt = q; this.wdLastAt = Date.now(); this.recoveries = 0; if (!this.posterUntilSeek) this.freezeHide(); if (this.label === 'loading') this.setLabel('playing'); }\n else if (this.rwScrub) this.wdLastAt = Date.now();\n else if (Date.now() - this.wdLastAt > 4000 && Date.now() > this.wdGrace) {\n this.wdLastAt = Date.now();\n const o: any = { ct: Math.round(v.currentTime * 10) / 10, paused: v.paused, muted: v.muted, rs: v.readyState, pf: q, w: v.videoWidth };\n try { s.pc?.getStats().then(st => { st.forEach((r: any) => { if (r.type === 'inbound-rtp' && (r.kind || r.mediaType) === 'video') { o.recv = r.framesReceived; o.dec = r.framesDecoded; o.drop = r.framesDropped; o.pli = r.pliCount; } }); rlog('stall-snap', o); }).catch(() => { /* ignore */ }); } catch { /* ignore */ }\n this.relayRecover(); return;\n }\n } else { this.wdLastCt = q; this.wdLastAt = Date.now(); }\n const seq = this.cmdSeq;\n fetch(this.api.url(`api/relay-pos?session=${encodeURIComponent(s.id)}`), { cache: 'no-store' }).then(r => r.json()).then((d: any) => {\n if (seq !== this.cmdSeq) return; // answered across a seek/rate change → stale\n if (d && d.t > 0 && Date.now() - this.seekAt < 2500 && Math.abs(d.t - this.seekTarget) > 5000) return; // pre-swap position\n if (d && d.t > 0) { this.wdDead = 0; this.rwPosTs = d.t; this.rwPosAt = Date.now(); if (this.posterUntilSeek && Math.abs(d.t - this.seekTarget) < 4000 && !this.rwSeekBusy && !this.rwPending) this.freezeHide(); this.emit(); }\n else if (d && d.t <= 0) { if (++this.wdDead >= 3) { this.wdDead = 0; this.relayRecover(); } }\n }).catch(() => { /* ignore */ });\n }, 600);\n }\n private stopRelayPoll(): void { this.cadStop(); if (this.relayPoll) { clearInterval(this.relayPoll); this.relayPoll = undefined; } }\n private cadStart(): void {\n this.cadStop(); const C = this.cad; C.last = -1; C.frames0 = -1; C.stalls = 0; C.maxStall = 0; C.gapMax = 0; C.t0 = Date.now();\n C.t = window.setInterval(() => {\n if (!this.rw?.active || document.hidden) return;\n const q = this.presentedFrames(), now = Date.now();\n if (this.rwScrub) { C.last = q; C.lastNew = now; return; }\n if (C.frames0 < 0) { C.frames0 = q; C.last = q; C.lastNew = now; return; }\n if (q === C.frames0 && C.last === C.frames0) { C.lastNew = now; return; } // connect phase: no frame yet, not a stall\n if (q > C.last) { const gap = now - C.lastNew; if (gap > C.gapMax) C.gapMax = gap; if (gap >= 400) { C.stalls++; if (gap > C.maxStall) C.maxStall = gap; } C.last = q; C.lastNew = now; }\n if (now - C.t0 >= 30000) {\n const rep: any = { sec: Math.round((now - C.t0) / 1000), frames: C.last - C.frames0, stalls: C.stalls, maxStall: C.maxStall, gapMax: C.gapMax, w: this.v.videoWidth };\n C.t0 = now; C.frames0 = C.last; C.stalls = 0; C.maxStall = 0; C.gapMax = 0;\n const pc = this.rw?.pc;\n if (pc) pc.getStats().then(st => { st.forEach((r: any) => { if (r.type === 'inbound-rtp' && (r.kind || r.mediaType) === 'video') { rep.lost = r.packetsLost; rep.jit = Math.round((r.jitter || 0) * 1000); rep.recv = r.framesReceived; rep.dec = r.framesDecoded; rep.drop = r.framesDropped; } }); rlog('cadence', rep); }).catch(() => rlog('cadence', rep));\n else rlog('cadence', rep);\n }\n }, 100);\n }\n private cadStop(): void { if (this.cad.t) { clearInterval(this.cad.t); this.cad.t = 0; } }\n\n // ---- playAt: relay first, MSE/native fallback ------------------------------------------------\n playAt(ts: number, opts: { scrub?: boolean; srate?: number; noChase?: boolean } = {}): void {\n const idx0 = this.clipIndexFor(ts);\n if (this.recWebrtcOk()) {\n this.chaseAbort();\n if (idx0 < 0) { this.setLabel('noRecording'); return; }\n this.recPaused = false;\n const t0 = Math.max(ts, this.clips[idx0]!.startTime);\n if (this.rw?.active && this.rw.id) this.recRelaySeek(t0, this.rate || 1, opts.srate || 1);\n else if (this.rw?.active && !this.live) this.rwPending = { ts: t0, rate: this.rate || 1, srate: opts.srate || 1 };\n else { if (this.live) { this.freezeShow(true); this.exitLiveState(); } this.recWebrtcStart(t0); }\n return;\n }\n // ---- MSE fallback / native\n const canChase = !opts.noChase && !this.live && this.M.active && !this.recPaused && this.currentTs() != null && idx0 >= 0;\n this.chaseAbort();\n if (canChase && !opts.scrub) { this.startChase(ts); return; }\n if (idx0 < 0) { this.setLabel('noRecording'); return; }\n if (this.live) { this.freezeShow(true); this.exitLiveState(); }\n this.recPaused = false;\n const clip = this.clips[idx0]!; if (ts < clip.startTime) ts = clip.startTime;\n this.playIndex = idx0;\n this.v.muted = opts.scrub ? true : !this.soundOn;\n if (this.mseSupported()) {\n const t = (ts - this.M.base) / 1000;\n if (this.M.active && t >= 0 && (this.bufferedContains(t) || (t <= this.M.end + 0.5 && this.M.end - t < 95))) { try { this.v.currentTime = t; } catch { /* ignore */ } if (this.v.paused) this.safePlay(); this.feed(); }\n else { if (opts.scrub && Date.now() - this.lastLoad < 200) { this.pendingTs = ts; return; } this.lastLoad = Date.now(); this.mseStart(idx0, (ts - clip.startTime) / 1000); }\n } else {\n const off = Math.min(Math.max((ts - clip.startTime) / 1000, 0), (clip.duration || 0) / 1000);\n if (clip.id === this.curClipId && this.v.src) { try { this.v.currentTime = off; } catch { /* ignore */ } if (this.v.paused) this.safePlay(); }\n else { if (opts.scrub && Date.now() - this.lastLoad < 120) { this.pendingTs = ts; return; } this.freezeShow(); this.lastLoad = Date.now(); this.curClipId = clip.id; this.transport = 'native'; rlog('native-fallback', { clip: clip.id }); this.v.src = this.api.url(`api/segment?id=${encodeURIComponent(clip.videoId || clip.id)}`); this.v.load(); this.v.onloadedmetadata = () => { this.v.playbackRate = this.rate; try { this.v.currentTime = off; } catch { /* ignore */ } this.safePlay(); }; }\n }\n this.setLabel(opts.scrub ? 'scrub' : 'playing');\n }\n\n // ---- MSE recorded ------------------------------------------------------------------------\n private mseSupported(): boolean { try { return !!(this.api.corsMedia && MSCls && this.codecs && MSCls.isTypeSupported(`video/mp4; codecs=\"${this.codecs}\"`)); } catch { return false; } }\n private mseTeardown(): void { const M = this.M; M.active = false; M.nextIdx = -1; M.feeding = false; M.end = 0; M.pendingSeek = null; M.q = []; M.segFirst = false; try { M.abort?.abort(); } catch { /* ignore */ } M.abort = null; if (M.sb && M.ms && M.ms.readyState === 'open') { try { M.sb.abort(); } catch { /* ignore */ } } M.sb = null; M.ms = null; }\n private bufferedContains(t: number): boolean { try { const b = this.v.buffered; for (let i = 0; i < b.length; i++) if (t >= b.start(i) - 0.3 && t <= b.end(i) + 0.3) return true; } catch { /* ignore */ } return false; }\n private mseStart(idx: number, offSec: number): void {\n this.freezeShow(); this.mseTeardown();\n const M = this.M; const ms = new MSCls!(); M.ms = ms; M.active = true; M.base = this.clips[idx]!.startTime; M.nextIdx = idx; M.end = 0; M.mmsGo = true; this.transport = 'mse';\n if ((window as any).ManagedMediaSource && ms instanceof (window as any).ManagedMediaSource) { try { (this.v as any).disableRemotePlayback = true; } catch { /* ignore */ } ms.addEventListener('startstreaming', () => { M.mmsGo = true; this.feed(); }); ms.addEventListener('endstreaming', () => { M.mmsGo = false; }); }\n M.pendingSeek = offSec;\n const u = URL.createObjectURL(ms);\n ms.addEventListener('sourceopen', () => {\n URL.revokeObjectURL(u); if (M.ms !== ms) return;\n let sb: SourceBuffer; try { sb = ms.addSourceBuffer(`video/mp4; codecs=\"${this.codecs}\"`); } catch { this.codecs = null; M.active = false; return; }\n sb.mode = 'segments';\n sb.addEventListener('updateend', () => { if (M.pendingSeek != null && this.v.readyState >= 1) { const t0 = M.pendingSeek; M.pendingSeek = null; try { this.v.currentTime = t0; } catch { /* ignore */ } } this.drain(); if (!M.feeding && !M.q.length) this.feed(); });\n sb.addEventListener('error', () => { M.active = false; });\n M.sb = sb; try { this.v.currentTime = offSec; } catch { /* ignore */ } this.feed();\n });\n try { this.v.srcObject = null; } catch { /* ignore */ }\n this.v.src = u; this.v.playbackRate = this.rate; this.safePlay();\n }\n private drain(): void {\n const M = this.M; if (!M.active || !M.sb || M.sb.updating || !M.q.length) return;\n if (M.segFirst) { M.segFirst = false; try { M.sb.timestampOffset = M.segOff; } catch { try { M.sb.abort(); M.sb.timestampOffset = M.segOff; } catch { M.active = false; return; } } }\n const buf = M.q.shift()!;\n try { M.sb.appendBuffer(buf as BufferSource); } catch { try { M.sb.abort(); M.sb.appendBuffer(buf as BufferSource); } catch { M.active = false; } }\n }\n private feed(): void {\n const M = this.M; if (!M.active || M.feeding) return; if (M.mmsGo === false) return; if (M.nextIdx < 0 || M.nextIdx >= this.clips.length) return;\n if (M.end - this.v.currentTime > 90) return;\n try { const b = this.v.buffered; if (b.length && this.v.currentTime - b.start(0) > 240 && M.sb && !M.sb.updating && !M.q.length) { M.sb.remove(0, this.v.currentTime - 120); return; } } catch { /* ignore */ }\n const clip = this.clips[M.nextIdx]!, ms = M.ms;\n M.feeding = true; M.segFirst = true; M.segOff = (clip.startTime - M.base) / 1000; M.abort = new AbortController();\n fetch(this.api.url(`api/segment?id=${encodeURIComponent(clip.videoId || clip.id)}`), { credentials: 'same-origin', signal: M.abort.signal })\n .then(r => { if (!r.ok || !r.body) throw new Error(String(r.status)); const rd = r.body.getReader(); const loop = () => { rd.read().then(x => { if (M.ms !== ms || !M.active) return; if (x.done) { M.feeding = false; M.nextIdx++; M.end = M.segOff + (clip.duration || 60000) / 1000; if (!M.q.length) this.feed(); return; } M.q.push(x.value); this.drain(); loop(); }).catch(() => { if (M.ms === ms) M.feeding = false; }); }; loop(); })\n .catch(() => { if (M.ms !== ms) return; M.feeding = false; M.nextIdx++; this.feed(); });\n }\n private handleStall(): void { if (this.live || !this.M.active || this.v.paused) return; const t = this.v.currentTime; try { const b = this.v.buffered; for (let i = 0; i < b.length; i++) if (b.start(i) > t && b.start(i) - t < 60) { this.v.currentTime = b.start(i) + 0.05; return; } } catch { /* ignore */ } if (this.M.nextIdx >= this.clips.length) this.opts.onClipsRefresh().then(c => { const cur = this.clips[this.M.nextIdx - 1]; this.clips = c; if (cur) { const i = c.findIndex(x => x.id === cur.id); if (i >= 0) this.M.nextIdx = i + 1; } this.feed(); }).catch(() => { /* ignore */ }); else this.feed(); }\n // trick-play chase inside the MSE buffer\n private chaseAbort(): void { if (!this.CH.active) return; this.CH.active = false; if (this.CH.timer) { clearInterval(this.CH.timer); this.CH.timer = 0; } this.v.playbackRate = this.rate; this.v.muted = !this.soundOn; }\n private endChase(): void { const tgt = this.CH.target; this.chaseAbort(); try { this.v.currentTime = (tgt - this.M.base) / 1000; } catch { /* ignore */ } this.setLabel('playing'); if (this.v.paused) this.safePlay(); }\n private startChase(target: number): void {\n this.chaseAbort(); this.freezeHide(); this.CH.active = true; this.CH.target = target; try { this.v.pause(); } catch { /* ignore */ } this.v.muted = true; this.setLabel('scrub');\n this.CH.timer = window.setInterval(() => {\n if (!this.CH.active) return; const c = this.currentTs(); if (c == null) { this.endChase(); return; }\n const rem = this.CH.target - c; if (Math.abs(rem) <= 250) { this.endChase(); return; }\n let step = rem * 0.2; if (Math.abs(step) < 180) step = rem > 0 ? 180 : -180;\n const nt = c + step, tt = (nt - this.M.base) / 1000;\n if (this.M.active && this.bufferedContains(tt)) { try { this.v.currentTime = tt; } catch { /* ignore */ } this.feed(); } else { this.endChase(); this.playAt(this.CH.target, { noChase: true }); }\n }, 50);\n }\n\n // ---- controls -----------------------------------------------------------------------------\n togglePlayPause(): void {\n if (this.live) return;\n if (this.CH.active) { this.chaseAbort(); try { this.v.pause(); } catch { /* ignore */ } this.emit(); return; }\n if (this.recPaused) { this.recPaused = false; const t = this.recPausedTs ?? (this.currentTs() ?? Date.now() - 1000); this.playAt(t, {}); return; }\n if (this.rw?.active) { this.recPausedTs = this.currentTs(); this.freezeShow(); if (this.freezeT) { clearTimeout(this.freezeT); this.freezeT = 0; } this.recWebrtcTeardown(); try { this.v.pause(); } catch { /* ignore */ } this.recPaused = true; this.transport = 'none'; this.setLabel('paused'); return; }\n if (this.v.paused) this.safePlay(); else this.v.pause();\n }\n skip(ms: number): void { const ts = this.live ? Date.now() + ms : ((this.currentTs() ?? Date.now()) + ms); if (this.live && ms > 0) return; this.playAt(ts, {}); }\n cycleSpeed(): number {\n if (this.live) return this.rate;\n const rates = [1, 2, 4, 8]; this.rate = rates[(rates.indexOf(this.rate) + 1) % rates.length] ?? 1;\n if (this.rw?.active && this.rw.id) { const c = this.currentTs(); this.recRelaySeek(c ?? this.rwStartMs, this.rate); this.v.muted = !this.soundOn || this.rate !== 1; }\n else this.v.playbackRate = this.rate;\n this.emit(); return this.rate;\n }\n setSound(on: boolean): void { this.soundOn = on; this.v.muted = !on || (!!this.rw?.active && this.rate !== 1); if (on && this.v.paused && !this.recPaused) this.safePlay(); this.emit(); }\n snapshot(): void {\n try {\n const src: any = this.live && !this.img.classList.contains('hidden') ? this.img : this.v;\n const w = src.videoWidth || src.naturalWidth || 1280, h = src.videoHeight || src.naturalHeight || 720;\n const cv = document.createElement('canvas'); cv.width = w; cv.height = h; cv.getContext('2d')!.drawImage(src, 0, 0, w, h);\n cv.toBlob(b => { if (!b) return; const a = document.createElement('a'); a.href = URL.createObjectURL(b); const ts = this.currentTs() ?? Date.now(); const d = new Date(ts); a.download = `${(this.camName || 'snapshot').replace(/[^\\w.-]+/g, '_')}_${String(d.getHours()).padStart(2, '0')}${String(d.getMinutes()).padStart(2, '0')}${String(d.getSeconds()).padStart(2, '0')}.jpg`; document.body.appendChild(a); a.click(); a.remove(); setTimeout(() => URL.revokeObjectURL(a.href), 4000); }, 'image/jpeg', 0.92);\n } catch { /* ignore */ }\n }\n private capLog(tag: string, extra?: object): void { try { const v: any = this.v, st: any = this.stage; rlog(tag, { fsReq: !!st.requestFullscreen, wkFs: !!st.webkitRequestFullscreen, vEnter: !!v.webkitEnterFullscreen, pipReq: !!v.requestPictureInPicture, wkPip: !!(v.webkitSupportsPresentationMode && v.webkitSupportsPresentationMode('picture-in-picture')), rs: v.readyState, vw: v.videoWidth, ...(extra || {}) }); } catch { /* ignore */ } }\n pip(): void {\n const v: any = this.v; this.capLog('pip-btn');\n try {\n if (document.pictureInPictureElement || v.webkitPresentationMode === 'picture-in-picture') { if (document.pictureInPictureElement) document.exitPictureInPicture().catch(() => { /* ignore */ }); else v.webkitSetPresentationMode('inline'); return; }\n if (this.v.classList.contains('hidden')) return;\n const wk = () => { try { if (v.webkitSupportsPresentationMode && v.webkitSupportsPresentationMode('picture-in-picture')) v.webkitSetPresentationMode('picture-in-picture'); else this.capLog('pip-unsupported'); } catch (e: any) { this.capLog('pip-fail', { e: String(e?.name || e) }); } };\n if (v.requestPictureInPicture) v.requestPictureInPicture().catch((e: any) => { this.capLog('pip-fail', { e: String(e?.name || e) }); wk(); }); else wk();\n } catch (e: any) { this.capLog('pip-fail', { e: String(e?.name || e) }); }\n }\n fullscreen(): void {\n const st: any = this.stage, v: any = this.v, d: any = document; this.capLog('fs-btn');\n try {\n if (d.fullscreenElement || d.webkitFullscreenElement) { (d.exitFullscreen || d.webkitExitFullscreen).call(d); return; }\n if (st.requestFullscreen) st.requestFullscreen().catch((e: any) => this.capLog('fs-fail', { e: String(e?.name || e) }));\n else if (st.webkitRequestFullscreen) st.webkitRequestFullscreen();\n else if (v.webkitEnterFullscreen && !this.v.classList.contains('hidden')) v.webkitEnterFullscreen();\n else this.capLog('fs-unsupported');\n } catch (e: any) { this.capLog('fs-fail', { e: String(e?.name || e) }); }\n }\n\n // ---- scrub (timeline gesture) ------------------------------------------------------------\n /** first gesture: scrub profile on (relay); MSE: freeze + pause */\n scrubBegin(): void { this.chaseAbort(); if (!this.rw?.active) { this.freezeShow(); if (!this.live) { try { this.v.pause(); } catch { /* ignore */ } } } this.recRelayScrub(true); }\n /** scroll position + velocity (timeline-ms per wall-s) while the gesture runs */\n scrubMove(_centerTs: number, vel: number, smoothTs: number): void {\n if (!this.rw?.active) { this.freezeHold(); return; }\n if (!this.rw.id) return;\n let r = vel / 1000;\n if (Math.abs(r) < 0.1) return;\n r = Math.min(3000, Math.max(-3000, r));\n r = Math.abs(r) >= 10 ? Math.round(r) : Math.round(r * 10) / 10;\n const tgt = this.clampRange(smoothTs), cur = this.currentTs();\n const drift = cur == null ? null : tgt - cur;\n if (drift == null || Math.abs(drift) > Math.max(4500, 1200 * Math.abs(r))) this.scrubSeek(tgt, r);\n else this.recRelayRate(r);\n }\n /** hold / release: land exactly on the centre at 1× (or go live near now) */\n scrubSeek(ts: number, srate = 1): void { if (this.nearNow(ts)) { this.goLive(); return; } this.playAt(this.clampRange(ts), { scrub: true, srate }); }\n /** gesture settled → normal profile, base rate */\n scrubIdle(): void { this.recRelayScrub(false); }\n\n // ---- visibility ---------------------------------------------------------------------------\n private hiddenTs: number | null = null;\n private onVisibility(): void {\n if (document.visibilityState === 'hidden') {\n // don't pin a camera stream in the background; live is simply restarted on return\n if (this.live) { this.hiddenTs = null; this.webrtcTeardown(); this.liveTeardown(); if (this.transport === 'mjpeg') this.img.removeAttribute('src'); }\n else if (this.rw?.active) { this.hiddenTs = this.currentTs(); this.freezeShow(true); this.recWebrtcTeardown(); }\n } else {\n if (this.live) this.goLive(); // also covers goLive() issued while hidden (background tab)\n else if (this.hiddenTs != null && !this.recPaused) { const t = this.hiddenTs; this.hiddenTs = null; this.playAt(t, {}); }\n }\n }\n}\n\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@sentinel-nvr/web",
3
+ "version": "0.1.0",
4
+ "description": "Shared browser code for the Sentinel NVR plugin for Scrypted: API model + client (/api), player (/player) and React UI (/ui, planned). Consumed by the plugin's own web UI and the HAPulse dashboard.",
5
+ "license": "MIT",
6
+ "author": "Muggedadscher",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/Muggedadscher/sentinel-nvr-web.git"
10
+ },
11
+ "type": "module",
12
+ "sideEffects": false,
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "exports": {
17
+ "./api": {
18
+ "types": "./dist/api/index.d.ts",
19
+ "import": "./dist/api/index.js",
20
+ "default": "./dist/api/index.js"
21
+ },
22
+ "./player": {
23
+ "types": "./dist/player/index.d.ts",
24
+ "import": "./dist/player/index.js",
25
+ "default": "./dist/player/index.js"
26
+ }
27
+ },
28
+ "engines": {
29
+ "node": ">=20"
30
+ },
31
+ "scripts": {
32
+ "build": "tsup",
33
+ "typecheck": "tsc --noEmit",
34
+ "test": "vitest run",
35
+ "release": "npm run build && changeset publish"
36
+ },
37
+ "devDependencies": {
38
+ "@changesets/cli": "^2.27.0",
39
+ "tsup": "^8.3.0",
40
+ "typescript": "^5.7.0",
41
+ "vitest": "^2.1.9"
42
+ }
43
+ }