prismcast 1.12.1 → 1.14.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.
- package/dist/app.d.ts +88 -7
- package/dist/app.js +295 -161
- package/dist/app.js.map +1 -1
- package/dist/browser/blockedPage.d.ts +0 -1
- package/dist/browser/browserSupervisor.d.ts +4 -4
- package/dist/browser/browserSupervisor.js.map +1 -1
- package/dist/browser/cdp.d.ts +8 -20
- package/dist/browser/cdp.js +11 -61
- package/dist/browser/cdp.js.map +1 -1
- package/dist/browser/channelSelection.d.ts +16 -4
- package/dist/browser/channelSelection.js +42 -31
- package/dist/browser/channelSelection.js.map +1 -1
- package/dist/browser/consent.d.ts +17 -4
- package/dist/browser/consent.js +25 -40
- package/dist/browser/consent.js.map +1 -1
- package/dist/browser/display.d.ts +0 -1
- package/dist/browser/hlsPlaylistObserver.d.ts +3 -2
- package/dist/browser/hlsPlaylistObserver.js +9 -4
- package/dist/browser/hlsPlaylistObserver.js.map +1 -1
- package/dist/browser/index.d.ts +179 -46
- package/dist/browser/index.js +473 -306
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/launchGovernor.d.ts +0 -1
- package/dist/browser/login.d.ts +8 -7
- package/dist/browser/login.js +25 -16
- package/dist/browser/login.js.map +1 -1
- package/dist/browser/manifestInterceptor.d.ts +14 -5
- package/dist/browser/manifestInterceptor.js +25 -12
- package/dist/browser/manifestInterceptor.js.map +1 -1
- package/dist/browser/navigation.d.ts +28 -0
- package/dist/browser/navigation.js +57 -0
- package/dist/browser/navigation.js.map +1 -0
- package/dist/browser/pageStaleness.d.ts +0 -1
- package/dist/browser/precaching.d.ts +27 -11
- package/dist/browser/precaching.js +262 -107
- package/dist/browser/precaching.js.map +1 -1
- package/dist/browser/tabCapture.d.ts +7 -10
- package/dist/browser/tabCapture.js +37 -50
- package/dist/browser/tabCapture.js.map +1 -1
- package/dist/browser/tabNetworkObserver.d.ts +0 -1
- package/dist/browser/tabSelection.d.ts +5 -5
- package/dist/browser/tabSelection.js +11 -10
- package/dist/browser/tabSelection.js.map +1 -1
- package/dist/browser/tuning/cache.d.ts +0 -1
- package/dist/browser/tuning/comcastPolymer.d.ts +0 -1
- package/dist/browser/tuning/comcastPolymer.js +29 -31
- package/dist/browser/tuning/comcastPolymer.js.map +1 -1
- package/dist/browser/tuning/cox.d.ts +0 -1
- package/dist/browser/tuning/directv.d.ts +0 -1
- package/dist/browser/tuning/directv.js +11 -12
- package/dist/browser/tuning/directv.js.map +1 -1
- package/dist/browser/tuning/fox.d.ts +0 -1
- package/dist/browser/tuning/fox.js +2 -2
- package/dist/browser/tuning/fox.js.map +1 -1
- package/dist/browser/tuning/gridSearch.d.ts +0 -1
- package/dist/browser/tuning/hbo.d.ts +0 -1
- package/dist/browser/tuning/hbo.js +34 -17
- package/dist/browser/tuning/hbo.js.map +1 -1
- package/dist/browser/tuning/hulu.d.ts +14 -2
- package/dist/browser/tuning/hulu.js +144 -21
- package/dist/browser/tuning/hulu.js.map +1 -1
- package/dist/browser/tuning/shared.d.ts +0 -1
- package/dist/browser/tuning/sling.d.ts +0 -1
- package/dist/browser/tuning/sling.js +17 -22
- package/dist/browser/tuning/sling.js.map +1 -1
- package/dist/browser/tuning/spectrum.d.ts +0 -1
- package/dist/browser/tuning/thumbnailRow.d.ts +0 -1
- package/dist/browser/tuning/tileClick.d.ts +0 -1
- package/dist/browser/tuning/xfinity.d.ts +0 -1
- package/dist/browser/tuning/youtubeTv.d.ts +0 -1
- package/dist/browser/video.d.ts +22 -20
- package/dist/browser/video.js +102 -119
- package/dist/browser/video.js.map +1 -1
- package/dist/browser/windowSync.d.ts +0 -1
- package/dist/channels/index.d.ts +0 -1
- package/dist/channels/index.js +5 -5
- package/dist/channels/index.js.map +1 -1
- package/dist/cliHelp.d.ts +11 -0
- package/dist/cliHelp.js +148 -0
- package/dist/cliHelp.js.map +1 -0
- package/dist/config/channelForm.d.ts +0 -1
- package/dist/config/channelForm.js +5 -4
- package/dist/config/channelForm.js.map +1 -1
- package/dist/config/channelIdentity.d.ts +27 -0
- package/dist/config/channelIdentity.js +72 -0
- package/dist/config/channelIdentity.js.map +1 -0
- package/dist/config/channelSort.d.ts +25 -0
- package/dist/config/channelSort.js +101 -0
- package/dist/config/channelSort.js.map +1 -0
- package/dist/config/consistencyProbe.d.ts +2 -5
- package/dist/config/consistencyProbe.js +8 -51
- package/dist/config/consistencyProbe.js.map +1 -1
- package/dist/config/health.d.ts +3 -2
- package/dist/config/health.js +41 -28
- package/dist/config/health.js.map +1 -1
- package/dist/config/index.d.ts +107 -56
- package/dist/config/index.js +499 -267
- package/dist/config/index.js.map +1 -1
- package/dist/config/paths.d.ts +13 -9
- package/dist/config/paths.js +21 -25
- package/dist/config/paths.js.map +1 -1
- package/dist/config/persistence.context.d.ts +0 -1
- package/dist/config/persistence.d.ts +57 -12
- package/dist/config/persistence.js +127 -44
- package/dist/config/persistence.js.map +1 -1
- package/dist/config/presets.d.ts +0 -1
- package/dist/config/profiles.d.ts +9 -4
- package/dist/config/profiles.js +37 -3
- package/dist/config/profiles.js.map +1 -1
- package/dist/config/providerLineups.d.ts +0 -1
- package/dist/config/reactivity.d.ts +60 -37
- package/dist/config/reactivity.js +89 -116
- package/dist/config/reactivity.js.map +1 -1
- package/dist/config/servicePacks.d.ts +0 -1
- package/dist/config/services.d.ts +62 -73
- package/dist/config/services.js +140 -202
- package/dist/config/services.js.map +1 -1
- package/dist/config/sites.d.ts +0 -9
- package/dist/config/sites.js +5 -40
- package/dist/config/sites.js.map +1 -1
- package/dist/config/streamSettings.d.ts +24 -0
- package/dist/config/streamSettings.js +17 -0
- package/dist/config/streamSettings.js.map +1 -0
- package/dist/config/userChannels.d.ts +82 -80
- package/dist/config/userChannels.js +184 -248
- package/dist/config/userChannels.js.map +1 -1
- package/dist/config/userConfig.d.ts +225 -59
- package/dist/config/userConfig.js +352 -131
- package/dist/config/userConfig.js.map +1 -1
- package/dist/config/userProfiles.d.ts +2 -3
- package/dist/config/userProfiles.js +6 -2
- package/dist/config/userProfiles.js.map +1 -1
- package/dist/hdhr/channelMap.d.ts +0 -1
- package/dist/hdhr/discover.d.ts +7 -2
- package/dist/hdhr/discover.js +12 -6
- package/dist/hdhr/discover.js.map +1 -1
- package/dist/hdhr/getHandlers.d.ts +0 -1
- package/dist/hdhr/identity.d.ts +0 -1
- package/dist/hdhr/index.d.ts +51 -11
- package/dist/hdhr/index.js +108 -112
- package/dist/hdhr/index.js.map +1 -1
- package/dist/hdhr/protocol.d.ts +0 -1
- package/dist/hdhr/tunerState.d.ts +0 -1
- package/dist/hdhr/udp.d.ts +11 -5
- package/dist/hdhr/udp.js +25 -20
- package/dist/hdhr/udp.js.map +1 -1
- package/dist/identity.d.ts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +16 -143
- package/dist/index.js.map +1 -1
- package/dist/native/codecInference.d.ts +5 -4
- package/dist/native/codecInference.js +12 -7
- package/dist/native/codecInference.js.map +1 -1
- package/dist/native/decrypt.d.ts +10 -3
- package/dist/native/decrypt.js +9 -5
- package/dist/native/decrypt.js.map +1 -1
- package/dist/native/index.d.ts +25 -23
- package/dist/native/index.js +27 -20
- package/dist/native/index.js.map +1 -1
- package/dist/native/probe.d.ts +7 -10
- package/dist/native/probe.js +40 -36
- package/dist/native/probe.js.map +1 -1
- package/dist/native/proxy.d.ts +3 -4
- package/dist/native/proxy.js +122 -92
- package/dist/native/proxy.js.map +1 -1
- package/dist/native/tokenExpiry.d.ts +0 -1
- package/dist/routes/assets.d.ts +0 -1
- package/dist/routes/auth.d.ts +0 -1
- package/dist/routes/auth.js +1 -1
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/cdp.d.ts +18 -11
- package/dist/routes/cdp.js +99 -70
- package/dist/routes/cdp.js.map +1 -1
- package/dist/routes/channels.d.ts +0 -1
- package/dist/routes/clientActions.d.ts +0 -1
- package/dist/routes/components.d.ts +23 -6
- package/dist/routes/components.js +21 -4
- package/dist/routes/components.js.map +1 -1
- package/dist/routes/config/channels/endpoints/browse.d.ts +0 -1
- package/dist/routes/config/channels/endpoints/browse.js +39 -29
- package/dist/routes/config/channels/endpoints/browse.js.map +1 -1
- package/dist/routes/config/channels/endpoints/bulk.d.ts +0 -1
- package/dist/routes/config/channels/endpoints/bulk.js +3 -7
- package/dist/routes/config/channels/endpoints/bulk.js.map +1 -1
- package/dist/routes/config/channels/endpoints/crud.d.ts +0 -1
- package/dist/routes/config/channels/endpoints/crud.js +3 -2
- package/dist/routes/config/channels/endpoints/crud.js.map +1 -1
- package/dist/routes/config/channels/endpoints/importExport.d.ts +0 -1
- package/dist/routes/config/channels/endpoints/importExport.js +7 -3
- package/dist/routes/config/channels/endpoints/importExport.js.map +1 -1
- package/dist/routes/config/channels/endpoints/predefined.d.ts +0 -1
- package/dist/routes/config/channels/endpoints/predefined.js +5 -15
- package/dist/routes/config/channels/endpoints/predefined.js.map +1 -1
- package/dist/routes/config/channels/endpoints/prefs.d.ts +0 -1
- package/dist/routes/config/channels/endpoints/prefs.js +8 -7
- package/dist/routes/config/channels/endpoints/prefs.js.map +1 -1
- package/dist/routes/config/channels/endpoints/service.d.ts +0 -1
- package/dist/routes/config/channels/endpoints/service.js +13 -9
- package/dist/routes/config/channels/endpoints/service.js.map +1 -1
- package/dist/routes/config/channels/endpoints/tags.d.ts +0 -1
- package/dist/routes/config/channels/endpoints/tags.js +4 -16
- package/dist/routes/config/channels/endpoints/tags.js.map +1 -1
- package/dist/routes/config/channels/healthBridge.d.ts +0 -1
- package/dist/routes/config/channels/http/handler.d.ts +0 -1
- package/dist/routes/config/channels/http/playlistHint.d.ts +0 -1
- package/dist/routes/config/channels/http/serviceWarning.d.ts +0 -1
- package/dist/routes/config/channels/http/serviceWarning.js +1 -1
- package/dist/routes/config/channels/http/serviceWarning.js.map +1 -1
- package/dist/routes/config/channels/index.d.ts +0 -1
- package/dist/routes/config/channels/setup.d.ts +0 -1
- package/dist/routes/config/channels/table.d.ts +2 -2
- package/dist/routes/config/channels/table.js +13 -14
- package/dist/routes/config/channels/table.js.map +1 -1
- package/dist/routes/config/http/envelope.d.ts +6 -4
- package/dist/routes/config/http/envelope.js +18 -5
- package/dist/routes/config/http/envelope.js.map +1 -1
- package/dist/routes/config/index.d.ts +21 -14
- package/dist/routes/config/index.js +49 -35
- package/dist/routes/config/index.js.map +1 -1
- package/dist/routes/config/services.d.ts +0 -1
- package/dist/routes/config/services.js +4 -3
- package/dist/routes/config/services.js.map +1 -1
- package/dist/routes/config/settings.d.ts +43 -7
- package/dist/routes/config/settings.js +227 -126
- package/dist/routes/config/settings.js.map +1 -1
- package/dist/routes/config/vocabulary.d.ts +24 -0
- package/dist/routes/config/vocabulary.js +33 -0
- package/dist/routes/config/vocabulary.js.map +1 -0
- package/dist/routes/debug.d.ts +0 -1
- package/dist/routes/debug.js +28 -13
- package/dist/routes/debug.js.map +1 -1
- package/dist/routes/health.d.ts +1 -2
- package/dist/routes/health.js +5 -2
- package/dist/routes/health.js.map +1 -1
- package/dist/routes/hls.d.ts +0 -1
- package/dist/routes/icons.d.ts +0 -1
- package/dist/routes/index.d.ts +0 -1
- package/dist/routes/logs.d.ts +3 -2
- package/dist/routes/logs.js +4 -2
- package/dist/routes/logs.js.map +1 -1
- package/dist/routes/mpegts.d.ts +0 -1
- package/dist/routes/play.d.ts +0 -1
- package/dist/routes/playlist.d.ts +0 -1
- package/dist/routes/playlist.js +2 -1
- package/dist/routes/playlist.js.map +1 -1
- package/dist/routes/root/content.d.ts +0 -1
- package/dist/routes/root/content.js +33 -26
- package/dist/routes/root/content.js.map +1 -1
- package/dist/routes/root/index.d.ts +0 -1
- package/dist/routes/root/scripts/channels.d.ts +0 -1
- package/dist/routes/root/scripts/channels.js +25 -13
- package/dist/routes/root/scripts/channels.js.map +1 -1
- package/dist/routes/root/scripts/clientEscape.d.ts +0 -1
- package/dist/routes/root/scripts/clientUrl.d.ts +0 -1
- package/dist/routes/root/scripts/config.d.ts +1 -2
- package/dist/routes/root/scripts/config.js +132 -105
- package/dist/routes/root/scripts/config.js.map +1 -1
- package/dist/routes/root/scripts/index.d.ts +0 -1
- package/dist/routes/root/scripts/shared.d.ts +0 -1
- package/dist/routes/root/scripts/shared.js +34 -23
- package/dist/routes/root/scripts/shared.js.map +1 -1
- package/dist/routes/root/scripts/status.d.ts +0 -1
- package/dist/routes/root/scripts/status.handlers.d.ts +8 -14
- package/dist/routes/root/scripts/status.handlers.js +38 -23
- package/dist/routes/root/scripts/status.handlers.js.map +1 -1
- package/dist/routes/root/styles.d.ts +0 -1
- package/dist/routes/root/styles.js +13 -16
- package/dist/routes/root/styles.js.map +1 -1
- package/dist/routes/services.d.ts +0 -1
- package/dist/routes/services.js +13 -17
- package/dist/routes/services.js.map +1 -1
- package/dist/routes/sse.d.ts +3 -2
- package/dist/routes/sse.js +7 -3
- package/dist/routes/sse.js.map +1 -1
- package/dist/routes/streams.d.ts +4 -2
- package/dist/routes/streams.js +8 -5
- package/dist/routes/streams.js.map +1 -1
- package/dist/routes/theme.d.ts +0 -1
- package/dist/routes/theme.js +12 -12
- package/dist/routes/theme.js.map +1 -1
- package/dist/routes/ui.d.ts +4 -4
- package/dist/routes/ui.js +17 -13
- package/dist/routes/ui.js.map +1 -1
- package/dist/routes/upgrade.d.ts +0 -1
- package/dist/routes/upgrade.js +2 -1
- package/dist/routes/upgrade.js.map +1 -1
- package/dist/service/commands.context.d.ts +0 -1
- package/dist/service/commands.context.js +7 -1
- package/dist/service/commands.context.js.map +1 -1
- package/dist/service/commands.d.ts +0 -1
- package/dist/service/generators.context.d.ts +0 -1
- package/dist/service/generators.d.ts +0 -1
- package/dist/service/generators.js +12 -9
- package/dist/service/generators.js.map +1 -1
- package/dist/service/index.d.ts +0 -1
- package/dist/streaming/captureLock.d.ts +1 -2
- package/dist/streaming/captureLock.js +6 -5
- package/dist/streaming/captureLock.js.map +1 -1
- package/dist/streaming/captureSession.d.ts +4 -5
- package/dist/streaming/captureSession.js +6 -7
- package/dist/streaming/captureSession.js.map +1 -1
- package/dist/streaming/clients.d.ts +4 -3
- package/dist/streaming/clients.js +5 -4
- package/dist/streaming/clients.js.map +1 -1
- package/dist/streaming/codec.d.ts +12 -3
- package/dist/streaming/codec.js +40 -28
- package/dist/streaming/codec.js.map +1 -1
- package/dist/streaming/fmp4Segmenter.d.ts +16 -5
- package/dist/streaming/fmp4Segmenter.js +110 -89
- package/dist/streaming/fmp4Segmenter.js.map +1 -1
- package/dist/streaming/hls.d.ts +55 -15
- package/dist/streaming/hls.js +255 -162
- package/dist/streaming/hls.js.map +1 -1
- package/dist/streaming/hlsResume.d.ts +42 -16
- package/dist/streaming/hlsResume.js +75 -42
- package/dist/streaming/hlsResume.js.map +1 -1
- package/dist/streaming/hlsSegments.d.ts +9 -7
- package/dist/streaming/hlsSegments.js +19 -14
- package/dist/streaming/hlsSegments.js.map +1 -1
- package/dist/streaming/lifecycle.d.ts +5 -4
- package/dist/streaming/lifecycle.js +25 -13
- package/dist/streaming/lifecycle.js.map +1 -1
- package/dist/streaming/monitor.d.ts +8 -5
- package/dist/streaming/monitor.js +109 -93
- package/dist/streaming/monitor.js.map +1 -1
- package/dist/streaming/mp4Parser.d.ts +29 -5
- package/dist/streaming/mp4Parser.js +49 -7
- package/dist/streaming/mp4Parser.js.map +1 -1
- package/dist/streaming/mpegts.d.ts +0 -1
- package/dist/streaming/mpegts.js +23 -7
- package/dist/streaming/mpegts.js.map +1 -1
- package/dist/streaming/playlistBuilder.d.ts +1 -3
- package/dist/streaming/playlistBuilder.js +2 -3
- package/dist/streaming/playlistBuilder.js.map +1 -1
- package/dist/streaming/preroll.d.ts +76 -30
- package/dist/streaming/preroll.js +141 -89
- package/dist/streaming/preroll.js.map +1 -1
- package/dist/streaming/pretune.d.ts +3 -4
- package/dist/streaming/pretune.js +50 -46
- package/dist/streaming/pretune.js.map +1 -1
- package/dist/streaming/pretuneTimers.d.ts +16 -12
- package/dist/streaming/pretuneTimers.js +27 -37
- package/dist/streaming/pretuneTimers.js.map +1 -1
- package/dist/streaming/recovery.d.ts +36 -7
- package/dist/streaming/recovery.js +53 -11
- package/dist/streaming/recovery.js.map +1 -1
- package/dist/streaming/registry.d.ts +35 -14
- package/dist/streaming/registry.js +23 -8
- package/dist/streaming/registry.js.map +1 -1
- package/dist/streaming/setup.d.ts +66 -25
- package/dist/streaming/setup.js +305 -229
- package/dist/streaming/setup.js.map +1 -1
- package/dist/streaming/showInfo.d.ts +29 -13
- package/dist/streaming/showInfo.js +156 -140
- package/dist/streaming/showInfo.js.map +1 -1
- package/dist/streaming/statusEmitter.d.ts +16 -12
- package/dist/streaming/statusEmitter.js +25 -21
- package/dist/streaming/statusEmitter.js.map +1 -1
- package/dist/types/channels.d.ts +0 -1
- package/dist/types/config.d.ts +24 -14
- package/dist/types/config.js +5 -1
- package/dist/types/config.js.map +1 -1
- package/dist/types/index.d.ts +4 -4
- package/dist/types/index.js +2 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/profiles.d.ts +3 -3
- package/dist/types/selection.d.ts +19 -8
- package/dist/types/shared.d.ts +0 -1
- package/dist/types/streaming.d.ts +12 -6
- package/dist/types/streaming.js +12 -5
- package/dist/types/streaming.js.map +1 -1
- package/dist/upgrade/commands.context.d.ts +0 -1
- package/dist/upgrade/commands.d.ts +0 -1
- package/dist/upgrade/detection.context.d.ts +0 -1
- package/dist/upgrade/detection.d.ts +0 -1
- package/dist/upgrade/index.d.ts +0 -1
- package/dist/upgrade/lifecycle.context.d.ts +2 -1
- package/dist/upgrade/lifecycle.context.js +9 -4
- package/dist/upgrade/lifecycle.context.js.map +1 -1
- package/dist/upgrade/lifecycle.d.ts +0 -1
- package/dist/upgrade/pathHandle.d.ts +0 -1
- package/dist/utils/bootSession.context.d.ts +0 -1
- package/dist/utils/bootSession.context.js +2 -1
- package/dist/utils/bootSession.context.js.map +1 -1
- package/dist/utils/bootSession.d.ts +0 -1
- package/dist/utils/chromeFetch.d.ts +0 -1
- package/dist/utils/cliOutput.d.ts +0 -1
- package/dist/utils/debugFilter.d.ts +3 -3
- package/dist/utils/debugFilter.js +7 -5
- package/dist/utils/debugFilter.js.map +1 -1
- package/dist/utils/delay.d.ts +47 -25
- package/dist/utils/delay.js +74 -37
- package/dist/utils/delay.js.map +1 -1
- package/dist/{hdhr → utils}/deviceId.d.ts +1 -2
- package/dist/{hdhr → utils}/deviceId.js +11 -29
- package/dist/utils/deviceId.js.map +1 -0
- package/dist/utils/errors.d.ts +7 -1
- package/dist/utils/errors.js +12 -3
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/evaluate.d.ts +11 -3
- package/dist/utils/evaluate.js +4 -3
- package/dist/utils/evaluate.js.map +1 -1
- package/dist/utils/ffmpeg.context.d.ts +0 -1
- package/dist/utils/ffmpeg.d.ts +0 -1
- package/dist/utils/fileLogger.d.ts +26 -14
- package/dist/utils/fileLogger.js +89 -49
- package/dist/utils/fileLogger.js.map +1 -1
- package/dist/utils/format.d.ts +12 -3
- package/dist/utils/format.js +29 -11
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/httpErrors.d.ts +13 -0
- package/dist/utils/httpErrors.js +22 -0
- package/dist/utils/httpErrors.js.map +1 -0
- package/dist/utils/index.d.ts +3 -2
- package/dist/utils/index.js +3 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/logEmitter.d.ts +0 -1
- package/dist/utils/logger.d.ts +9 -9
- package/dist/utils/logger.js +64 -20
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/m3u.d.ts +0 -1
- package/dist/utils/markup.d.ts +0 -1
- package/dist/utils/markup.js +8 -3
- package/dist/utils/markup.js.map +1 -1
- package/dist/utils/memo.d.ts +0 -1
- package/dist/utils/morganStream.d.ts +0 -1
- package/dist/utils/network.d.ts +0 -1
- package/dist/utils/never.d.ts +0 -1
- package/dist/utils/pid.d.ts +0 -1
- package/dist/utils/plainObject.d.ts +6 -0
- package/dist/utils/plainObject.js +18 -0
- package/dist/utils/plainObject.js.map +1 -0
- package/dist/utils/platform.d.ts +0 -1
- package/dist/utils/processInspector.context.d.ts +32 -2
- package/dist/utils/processInspector.context.js +117 -1
- package/dist/utils/processInspector.context.js.map +1 -1
- package/dist/utils/processInspector.d.ts +0 -32
- package/dist/utils/processInspector.js +10 -117
- package/dist/utils/processInspector.js.map +1 -1
- package/dist/utils/retry.d.ts +5 -4
- package/dist/utils/retry.js +43 -33
- package/dist/utils/retry.js.map +1 -1
- package/dist/utils/runtimeIdentity.context.d.ts +0 -1
- package/dist/utils/runtimeIdentity.context.js +4 -30
- package/dist/utils/runtimeIdentity.context.js.map +1 -1
- package/dist/utils/runtimeIdentity.d.ts +18 -7
- package/dist/utils/runtimeIdentity.js +51 -18
- package/dist/utils/runtimeIdentity.js.map +1 -1
- package/dist/utils/sanitize.d.ts +0 -1
- package/dist/utils/streamContext.d.ts +0 -1
- package/dist/utils/timing.d.ts +3 -4
- package/dist/utils/timing.js +4 -4
- package/dist/utils/timing.js.map +1 -1
- package/dist/utils/version.d.ts +5 -4
- package/dist/utils/version.js +35 -24
- package/dist/utils/version.js.map +1 -1
- package/package.json +9 -9
- package/dist/app.d.ts.map +0 -1
- package/dist/browser/blockedPage.d.ts.map +0 -1
- package/dist/browser/browserSupervisor.d.ts.map +0 -1
- package/dist/browser/cdp.d.ts.map +0 -1
- package/dist/browser/channelSelection.d.ts.map +0 -1
- package/dist/browser/consent.d.ts.map +0 -1
- package/dist/browser/display.d.ts.map +0 -1
- package/dist/browser/hlsPlaylistObserver.d.ts.map +0 -1
- package/dist/browser/index.d.ts.map +0 -1
- package/dist/browser/launchGovernor.d.ts.map +0 -1
- package/dist/browser/login.d.ts.map +0 -1
- package/dist/browser/manifestInterceptor.d.ts.map +0 -1
- package/dist/browser/pageStaleness.d.ts.map +0 -1
- package/dist/browser/precaching.d.ts.map +0 -1
- package/dist/browser/tabCapture.d.ts.map +0 -1
- package/dist/browser/tabNetworkObserver.d.ts.map +0 -1
- package/dist/browser/tabSelection.d.ts.map +0 -1
- package/dist/browser/tuning/cache.d.ts.map +0 -1
- package/dist/browser/tuning/comcastPolymer.d.ts.map +0 -1
- package/dist/browser/tuning/cox.d.ts.map +0 -1
- package/dist/browser/tuning/directv.d.ts.map +0 -1
- package/dist/browser/tuning/fox.d.ts.map +0 -1
- package/dist/browser/tuning/gridSearch.d.ts.map +0 -1
- package/dist/browser/tuning/hbo.d.ts.map +0 -1
- package/dist/browser/tuning/hulu.d.ts.map +0 -1
- package/dist/browser/tuning/shared.d.ts.map +0 -1
- package/dist/browser/tuning/sling.d.ts.map +0 -1
- package/dist/browser/tuning/spectrum.d.ts.map +0 -1
- package/dist/browser/tuning/thumbnailRow.d.ts.map +0 -1
- package/dist/browser/tuning/tileClick.d.ts.map +0 -1
- package/dist/browser/tuning/xfinity.d.ts.map +0 -1
- package/dist/browser/tuning/youtubeTv.d.ts.map +0 -1
- package/dist/browser/video.d.ts.map +0 -1
- package/dist/browser/windowSync.d.ts.map +0 -1
- package/dist/channels/index.d.ts.map +0 -1
- package/dist/config/channelForm.d.ts.map +0 -1
- package/dist/config/consistencyProbe.d.ts.map +0 -1
- package/dist/config/health.d.ts.map +0 -1
- package/dist/config/index.d.ts.map +0 -1
- package/dist/config/paths.d.ts.map +0 -1
- package/dist/config/persistence.context.d.ts.map +0 -1
- package/dist/config/persistence.d.ts.map +0 -1
- package/dist/config/presets.d.ts.map +0 -1
- package/dist/config/profiles.d.ts.map +0 -1
- package/dist/config/providerLineups.d.ts.map +0 -1
- package/dist/config/reactivity.d.ts.map +0 -1
- package/dist/config/servicePacks.d.ts.map +0 -1
- package/dist/config/services.d.ts.map +0 -1
- package/dist/config/sites.d.ts.map +0 -1
- package/dist/config/userChannels.d.ts.map +0 -1
- package/dist/config/userConfig.d.ts.map +0 -1
- package/dist/config/userProfiles.d.ts.map +0 -1
- package/dist/hdhr/channelMap.d.ts.map +0 -1
- package/dist/hdhr/deviceId.d.ts.map +0 -1
- package/dist/hdhr/deviceId.js.map +0 -1
- package/dist/hdhr/discover.d.ts.map +0 -1
- package/dist/hdhr/getHandlers.d.ts.map +0 -1
- package/dist/hdhr/identity.d.ts.map +0 -1
- package/dist/hdhr/index.d.ts.map +0 -1
- package/dist/hdhr/protocol.d.ts.map +0 -1
- package/dist/hdhr/tunerState.d.ts.map +0 -1
- package/dist/hdhr/udp.d.ts.map +0 -1
- package/dist/identity.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/native/codecInference.d.ts.map +0 -1
- package/dist/native/decrypt.d.ts.map +0 -1
- package/dist/native/index.d.ts.map +0 -1
- package/dist/native/probe.d.ts.map +0 -1
- package/dist/native/proxy.d.ts.map +0 -1
- package/dist/native/tokenExpiry.d.ts.map +0 -1
- package/dist/routes/assets.d.ts.map +0 -1
- package/dist/routes/auth.d.ts.map +0 -1
- package/dist/routes/cdp.d.ts.map +0 -1
- package/dist/routes/channels.d.ts.map +0 -1
- package/dist/routes/clientActions.d.ts.map +0 -1
- package/dist/routes/components.d.ts.map +0 -1
- package/dist/routes/config/channels/endpoints/browse.d.ts.map +0 -1
- package/dist/routes/config/channels/endpoints/bulk.d.ts.map +0 -1
- package/dist/routes/config/channels/endpoints/crud.d.ts.map +0 -1
- package/dist/routes/config/channels/endpoints/importExport.d.ts.map +0 -1
- package/dist/routes/config/channels/endpoints/predefined.d.ts.map +0 -1
- package/dist/routes/config/channels/endpoints/prefs.d.ts.map +0 -1
- package/dist/routes/config/channels/endpoints/service.d.ts.map +0 -1
- package/dist/routes/config/channels/endpoints/tags.d.ts.map +0 -1
- package/dist/routes/config/channels/healthBridge.d.ts.map +0 -1
- package/dist/routes/config/channels/http/handler.d.ts.map +0 -1
- package/dist/routes/config/channels/http/playlistHint.d.ts.map +0 -1
- package/dist/routes/config/channels/http/serviceWarning.d.ts.map +0 -1
- package/dist/routes/config/channels/index.d.ts.map +0 -1
- package/dist/routes/config/channels/setup.d.ts.map +0 -1
- package/dist/routes/config/channels/table.d.ts.map +0 -1
- package/dist/routes/config/http/envelope.d.ts.map +0 -1
- package/dist/routes/config/index.d.ts.map +0 -1
- package/dist/routes/config/services.d.ts.map +0 -1
- package/dist/routes/config/settings.d.ts.map +0 -1
- package/dist/routes/debug.d.ts.map +0 -1
- package/dist/routes/health.d.ts.map +0 -1
- package/dist/routes/hls.d.ts.map +0 -1
- package/dist/routes/icons.d.ts.map +0 -1
- package/dist/routes/index.d.ts.map +0 -1
- package/dist/routes/logs.d.ts.map +0 -1
- package/dist/routes/mpegts.d.ts.map +0 -1
- package/dist/routes/play.d.ts.map +0 -1
- package/dist/routes/playlist.d.ts.map +0 -1
- package/dist/routes/root/content.d.ts.map +0 -1
- package/dist/routes/root/index.d.ts.map +0 -1
- package/dist/routes/root/scripts/channels.d.ts.map +0 -1
- package/dist/routes/root/scripts/clientEscape.d.ts.map +0 -1
- package/dist/routes/root/scripts/clientUrl.d.ts.map +0 -1
- package/dist/routes/root/scripts/config.d.ts.map +0 -1
- package/dist/routes/root/scripts/index.d.ts.map +0 -1
- package/dist/routes/root/scripts/shared.d.ts.map +0 -1
- package/dist/routes/root/scripts/status.d.ts.map +0 -1
- package/dist/routes/root/scripts/status.handlers.d.ts.map +0 -1
- package/dist/routes/root/styles.d.ts.map +0 -1
- package/dist/routes/services.d.ts.map +0 -1
- package/dist/routes/sse.d.ts.map +0 -1
- package/dist/routes/streams.d.ts.map +0 -1
- package/dist/routes/theme.d.ts.map +0 -1
- package/dist/routes/ui.d.ts.map +0 -1
- package/dist/routes/upgrade.d.ts.map +0 -1
- package/dist/service/commands.context.d.ts.map +0 -1
- package/dist/service/commands.d.ts.map +0 -1
- package/dist/service/generators.context.d.ts.map +0 -1
- package/dist/service/generators.d.ts.map +0 -1
- package/dist/service/index.d.ts.map +0 -1
- package/dist/streaming/captureLock.d.ts.map +0 -1
- package/dist/streaming/captureSession.d.ts.map +0 -1
- package/dist/streaming/clients.d.ts.map +0 -1
- package/dist/streaming/codec.d.ts.map +0 -1
- package/dist/streaming/fmp4Segmenter.d.ts.map +0 -1
- package/dist/streaming/hls.d.ts.map +0 -1
- package/dist/streaming/hlsResume.d.ts.map +0 -1
- package/dist/streaming/hlsSegments.d.ts.map +0 -1
- package/dist/streaming/lifecycle.d.ts.map +0 -1
- package/dist/streaming/monitor.d.ts.map +0 -1
- package/dist/streaming/mp4Parser.d.ts.map +0 -1
- package/dist/streaming/mpegts.d.ts.map +0 -1
- package/dist/streaming/playlistBuilder.d.ts.map +0 -1
- package/dist/streaming/preroll.d.ts.map +0 -1
- package/dist/streaming/pretune.d.ts.map +0 -1
- package/dist/streaming/pretuneTimers.d.ts.map +0 -1
- package/dist/streaming/recovery.d.ts.map +0 -1
- package/dist/streaming/registry.d.ts.map +0 -1
- package/dist/streaming/setup.d.ts.map +0 -1
- package/dist/streaming/showInfo.d.ts.map +0 -1
- package/dist/streaming/statusEmitter.d.ts.map +0 -1
- package/dist/types/channels.d.ts.map +0 -1
- package/dist/types/config.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/profiles.d.ts.map +0 -1
- package/dist/types/selection.d.ts.map +0 -1
- package/dist/types/shared.d.ts.map +0 -1
- package/dist/types/streaming.d.ts.map +0 -1
- package/dist/upgrade/commands.context.d.ts.map +0 -1
- package/dist/upgrade/commands.d.ts.map +0 -1
- package/dist/upgrade/detection.context.d.ts.map +0 -1
- package/dist/upgrade/detection.d.ts.map +0 -1
- package/dist/upgrade/index.d.ts.map +0 -1
- package/dist/upgrade/lifecycle.context.d.ts.map +0 -1
- package/dist/upgrade/lifecycle.d.ts.map +0 -1
- package/dist/upgrade/pathHandle.d.ts.map +0 -1
- package/dist/utils/bootSession.context.d.ts.map +0 -1
- package/dist/utils/bootSession.d.ts.map +0 -1
- package/dist/utils/chromeFetch.d.ts.map +0 -1
- package/dist/utils/cliOutput.d.ts.map +0 -1
- package/dist/utils/clock.d.ts +0 -15
- package/dist/utils/clock.d.ts.map +0 -1
- package/dist/utils/clock.js +0 -31
- package/dist/utils/clock.js.map +0 -1
- package/dist/utils/debugFilter.d.ts.map +0 -1
- package/dist/utils/delay.d.ts.map +0 -1
- package/dist/utils/errors.d.ts.map +0 -1
- package/dist/utils/evaluate.d.ts.map +0 -1
- package/dist/utils/ffmpeg.context.d.ts.map +0 -1
- package/dist/utils/ffmpeg.d.ts.map +0 -1
- package/dist/utils/fileLogger.d.ts.map +0 -1
- package/dist/utils/format.d.ts.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/logEmitter.d.ts.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/m3u.d.ts.map +0 -1
- package/dist/utils/markup.d.ts.map +0 -1
- package/dist/utils/memo.d.ts.map +0 -1
- package/dist/utils/morganStream.d.ts.map +0 -1
- package/dist/utils/network.d.ts.map +0 -1
- package/dist/utils/never.d.ts.map +0 -1
- package/dist/utils/pid.d.ts.map +0 -1
- package/dist/utils/platform.d.ts.map +0 -1
- package/dist/utils/processInspector.context.d.ts.map +0 -1
- package/dist/utils/processInspector.d.ts.map +0 -1
- package/dist/utils/retry.d.ts.map +0 -1
- package/dist/utils/runtimeIdentity.context.d.ts.map +0 -1
- package/dist/utils/runtimeIdentity.d.ts.map +0 -1
- package/dist/utils/sanitize.d.ts.map +0 -1
- package/dist/utils/streamContext.d.ts.map +0 -1
- package/dist/utils/timing.d.ts.map +0 -1
- package/dist/utils/version.d.ts.map +0 -1
package/dist/native/proxy.js
CHANGED
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
*
|
|
3
3
|
* proxy.ts: Native HLS proxy - manifest polling, segment fetching, and playlist generation.
|
|
4
4
|
*/
|
|
5
|
-
import { LOG, chromeFetch,
|
|
6
|
-
import { buildPrerollEntries, computePrerollWindow } from "../streaming/preroll.js";
|
|
5
|
+
import { LOG, chromeFetch, resolveUrl, startTimer, timeoutSignal } from "../utils/index.js";
|
|
6
|
+
import { buildPrerollEntries, buildPrerollInitUri, computePrerollWindow } from "../streaming/preroll.js";
|
|
7
7
|
import { decryptSegment, deriveIvFromSequence, fetchDecryptionKey, parseExplicitIv } from "./decrypt.js";
|
|
8
8
|
import { findNamedInitSegment, pruneNamedInitSegments, storeAudioSegment, storeNamedInitSegment, storeSegment, updateAudioPlaylist, updatePlaylist, updateVideoPlaylist } from "../streaming/hlsSegments.js";
|
|
9
|
+
import { CAPTURE_BASELINE_CODEC } from "../types/index.js";
|
|
9
10
|
import { CONFIG } from "../config/index.js";
|
|
10
11
|
import { buildPlaylist } from "../streaming/playlistBuilder.js";
|
|
11
12
|
import { getStream } from "../streaming/registry.js";
|
|
12
|
-
import {
|
|
13
|
+
import { systemClock } from "homebridge-plugin-utils";
|
|
13
14
|
/* This module implements the native HLS proxy that replaces Chrome screen capture for viable streams. It polls the service's variant manifest at regular intervals,
|
|
14
15
|
* detects new segments by tracking #EXT-X-MEDIA-SEQUENCE, fetches each segment (optionally decrypting AES-128), stores them in the existing HLS segment system, and
|
|
15
16
|
* generates an HLS playlist that faithfully propagates upstream metadata - discontinuity markers, program timestamps, and SCTE-35 ad signaling (cue-out, cue-in,
|
|
@@ -33,10 +34,10 @@ const MAX_MANIFEST_FAILURES = 3;
|
|
|
33
34
|
// dropped connection on one segment) are more common here; this higher tolerance than MAX_MANIFEST_FAILURES avoids escalating on blips that would otherwise
|
|
34
35
|
// self-resolve on the next fetch.
|
|
35
36
|
const MAX_SEGMENT_FAILURES = 5;
|
|
36
|
-
// Number of segment byte-fetches one track keeps in flight while its commit walk consumes the results in broadcast order.
|
|
37
|
-
// track's download throughput to roughly
|
|
38
|
-
// production rate rather than accumulating a backlog that delays the next manifest poll. The bound is what keeps the gain cheap: at most
|
|
39
|
-
// track are resident at once -
|
|
37
|
+
// Number of segment byte-fetches one track keeps in flight while its commit walk consumes the results in broadcast order. Running that many connections at once
|
|
38
|
+
// lifts a track's download throughput to roughly that many times the per-connection pacing a CDN edge grants, which is what keeps a high-bitrate channel ahead
|
|
39
|
+
// of its own production rate rather than accumulating a backlog that delays the next manifest poll. The bound is what keeps the gain cheap: at most
|
|
40
|
+
// PARALLEL_SEGMENT_FETCHES segments per track are resident at once - twice that when audio is a separate rendition, since each track runs its own window.
|
|
40
41
|
const PARALLEL_SEGMENT_FETCHES = 3;
|
|
41
42
|
// Manifest poll backoff base delay and cap. On success, the poll interval returns to the base delay (a fixed 3000ms, ~half a typical 6s segment). On failure, the delay
|
|
42
43
|
// doubles on each consecutive failure up to the cap. Jitter of +/-20% prevents multiple streams from retrying in lockstep after a shared CDN outage.
|
|
@@ -427,7 +428,7 @@ async function resolveTrackInit(options) {
|
|
|
427
428
|
servedName = ((track === "video") ? "init-v" : "init-a") + String(tracking.initCounter) + ".mp4";
|
|
428
429
|
tracking.initCounter++;
|
|
429
430
|
}
|
|
430
|
-
storeNamedInitSegment(ctx.streamId, track, servedName, data);
|
|
431
|
+
storeNamedInitSegment(ctx.streamId, track, servedName, data, ctx.clock.now());
|
|
431
432
|
tracking.lastUpstreamMapUri = mapUri;
|
|
432
433
|
LOG.debug("native:proxy", "Initialization segment %s for %s (%s track, %s bytes, %s).", (existingName === undefined) ? "stored as " + servedName :
|
|
433
434
|
"reused as " + servedName, ctx.channelName, track, data.length, mapUri.slice(0, 80));
|
|
@@ -659,21 +660,30 @@ async function pollAudioStream(ctx, audio, pipeline) {
|
|
|
659
660
|
return false;
|
|
660
661
|
}
|
|
661
662
|
try {
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
663
|
+
const bound = timeoutSignal(SEGMENT_FETCH_TIMEOUT, { clock: ctx.clock });
|
|
664
|
+
let body;
|
|
665
|
+
try {
|
|
666
|
+
const response = await chromeFetch(audio.variantUrl, { signal: bound.signal });
|
|
667
|
+
if (!response.ok) {
|
|
668
|
+
audio.consecutiveManifestFailures++;
|
|
669
|
+
ctx.stats.totalFetchErrors++;
|
|
670
|
+
// Classify the failure via the shared threshold helper so the audio path escalates identically to the video path: 4xx uses the base threshold, 5xx and
|
|
671
|
+
// network conditions get double the attempts.
|
|
672
|
+
const effectiveThreshold = manifestFailureThreshold(response.status);
|
|
673
|
+
LOG.debug("native:proxy", "Audio manifest poll failed for %s: HTTP %s (%s/%s).", ctx.channelName, response.status, audio.consecutiveManifestFailures, effectiveThreshold);
|
|
674
|
+
if (audio.consecutiveManifestFailures >= effectiveThreshold) {
|
|
675
|
+
escalateProxyFailure({ ctx, message: "audio manifest poll failed " + String(audio.consecutiveManifestFailures) + " times" });
|
|
676
|
+
}
|
|
677
|
+
return false;
|
|
672
678
|
}
|
|
673
|
-
|
|
679
|
+
audio.consecutiveManifestFailures = 0;
|
|
680
|
+
body = await response.text();
|
|
681
|
+
}
|
|
682
|
+
finally {
|
|
683
|
+
// The bound covers this poll's own network wait and nothing past it: a bound is armed for exactly the wait it bounds and disposed the moment that wait
|
|
684
|
+
// settles, so the audio processing below runs with no timer of this poll's left pending on the proxy's clock.
|
|
685
|
+
bound.cancel();
|
|
674
686
|
}
|
|
675
|
-
audio.consecutiveManifestFailures = 0;
|
|
676
|
-
const body = await response.text();
|
|
677
687
|
return await processAudioStream(ctx, audio, body, audio.variantUrl, pipeline);
|
|
678
688
|
}
|
|
679
689
|
catch (error) {
|
|
@@ -741,10 +751,10 @@ async function processAudioStream(ctx, audio, body, baseUrl, pipeline) {
|
|
|
741
751
|
// Composite Playlist Builder.
|
|
742
752
|
/**
|
|
743
753
|
* Builds a composite playlist with fMP4 preroll entries and the relayed source's real entries. Uses the same compositor and builder as the capture path's
|
|
744
|
-
* generatePlaylist(), ensuring identical windowing behavior (
|
|
745
|
-
* signals the transition between two independently-initialized runs of content, which is spec-compliant per RFC 8216
|
|
746
|
-
* source is itself fMP4, that boundary is also where its own initialization reference is re-emitted. VERSION:7 is used
|
|
747
|
-
* backward-compatible with MPEG-TS entries once preroll falls off the window.
|
|
754
|
+
* generatePlaylist(), ensuring identical windowing behavior (the MAX_PREROLL_IN_WINDOW cap in streaming/preroll.ts, progressive falloff). The DISCONTINUITY
|
|
755
|
+
* tag at the preroll-to-real boundary signals the transition between two independently-initialized runs of content, which is spec-compliant per RFC 8216
|
|
756
|
+
* Section 4.3.3.3 - and when the relayed source is itself fMP4, that boundary is also where its own initialization reference is re-emitted. VERSION:7 is used
|
|
757
|
+
* throughout to support EXT-X-MAP, and stays backward-compatible with MPEG-TS entries once preroll falls off the window.
|
|
748
758
|
*
|
|
749
759
|
* @param options - Composite playlist configuration with segment data, preroll settings, and composite tracking state.
|
|
750
760
|
* @returns The formatted composite m3u8 playlist string.
|
|
@@ -752,20 +762,22 @@ async function processAudioStream(ctx, audio, body, baseUrl, pipeline) {
|
|
|
752
762
|
function buildCompositePlaylist(options) {
|
|
753
763
|
const { composite, prerollBaseUrl, prerollCodec, prerollSegmentCount, segmentEntries, segmentIndex, targetDuration, videoMetadata } = options;
|
|
754
764
|
// Compute the sliding window start index via the compositor. The three-way max prevents negative indices, enforces the sliding window rule, and caps preroll
|
|
755
|
-
// entries at
|
|
765
|
+
// entries at the preroll-in-window cap to force clients past preroll toward the live edge.
|
|
756
766
|
const realSegmentCount = segmentEntries.length;
|
|
757
767
|
const startIndex = computePrerollWindow({
|
|
758
768
|
currentSegmentIndex: segmentIndex,
|
|
759
769
|
maxSegments: CONFIG.hls.maxSegments,
|
|
760
770
|
prerollSegmentCount,
|
|
771
|
+
// The relay numbers its composite from index 0, so its preroll starts there.
|
|
772
|
+
prerollStartIndex: 0,
|
|
761
773
|
realSegmentCount
|
|
762
774
|
});
|
|
763
|
-
// Build fMP4 preroll entries for preroll indices still in the window. These reference the global /preroll/ routes with absolute URLs
|
|
775
|
+
// Build fMP4 preroll entries for preroll indices still in the window. These reference the global /preroll/ routes with absolute URLs.
|
|
764
776
|
let prerollEntries = [];
|
|
765
777
|
if (startIndex < prerollSegmentCount) {
|
|
766
|
-
prerollEntries = buildPrerollEntries({ baseUrl: prerollBaseUrl, codec: prerollCodec,
|
|
778
|
+
prerollEntries = buildPrerollEntries({ baseUrl: prerollBaseUrl, codec: prerollCodec, prerollSegmentCount, startIndex });
|
|
767
779
|
}
|
|
768
|
-
// Build real MPEG-TS
|
|
780
|
+
// Build the relayed source's real entries (MPEG-TS or fMP4) from the video metadata maps via the shared helper.
|
|
769
781
|
const realEntries = segmentEntries.map((filename) => buildEntryFromMetadata(filename, videoMetadata, targetDuration));
|
|
770
782
|
// Mark the preroll-to-real boundary on the first real entry when preroll entries are present in the window. This is a playlist-level concern (the stitching of
|
|
771
783
|
// preroll before real content), not a segment-level property - so it's applied here in the composite builder rather than injected into videoMetadata at segment
|
|
@@ -807,7 +819,7 @@ function buildCompositePlaylist(options) {
|
|
|
807
819
|
* has fallen out of the window, the real content's own initialization becomes the window-level reference directly.
|
|
808
820
|
*/
|
|
809
821
|
const realInitialMapUri = annotateMapTransitions(realEntries, videoMetadata);
|
|
810
|
-
let initialMapUri = (prerollEntries.length > 0) ? (prerollBaseUrl
|
|
822
|
+
let initialMapUri = (prerollEntries.length > 0) ? buildPrerollInitUri(prerollBaseUrl, prerollCodec) : undefined;
|
|
811
823
|
if (realInitialMapUri !== null) {
|
|
812
824
|
if ((prerollEntries.length > 0) && firstRealEntry) {
|
|
813
825
|
firstRealEntry.mapUri = realInitialMapUri;
|
|
@@ -831,12 +843,14 @@ function buildCompositePlaylist(options) {
|
|
|
831
843
|
* @returns The native proxy interface.
|
|
832
844
|
*/
|
|
833
845
|
export function createNativeProxy(options) {
|
|
834
|
-
const { channelName, clock =
|
|
846
|
+
const { channelName, clock = systemClock, container, encryption, keyUrl, onError, streamId } = options;
|
|
835
847
|
const hasAudio = options.audioVariantUrl !== null;
|
|
848
|
+
// The preroll codec is read only while a preroll is active, and every caller that activates one passes its codec, so the baseline stands in only for a proxy that
|
|
849
|
+
// never reads it.
|
|
850
|
+
const prerollCodec = options.prerollCodec ?? CAPTURE_BASELINE_CODEC;
|
|
836
851
|
// Preroll segment index offset. When preroll is ready (prerollSegmentCount > 0), real segments start numbering after the preroll range (e.g., segmentN.ts where
|
|
837
852
|
// N = prerollSegmentCount). This offset is unconditional - it reserves the index space for preroll regardless of whether the deferred preroll timer fires.
|
|
838
853
|
// The composite playlist behavior (including preroll entries) is determined dynamically by checking stream.hls.prerollStartTime at playlist generation time.
|
|
839
|
-
const prerollCodec = options.prerollCodec ?? "h264";
|
|
840
854
|
const prerollSegmentCount = options.prerollSegmentCount ?? 0;
|
|
841
855
|
/* Proxy state. These track segment storage, manifest polling, error thresholds, and playlist generation across the proxy's lifetime. Mutable variables are organized
|
|
842
856
|
* into typed state objects by subsystem (lifecycle, video tracking, audio tracking, composite playlist, statistics) to clarify ownership and interaction boundaries.
|
|
@@ -904,7 +918,7 @@ export function createNativeProxy(options) {
|
|
|
904
918
|
totalTokenRefreshes: 0
|
|
905
919
|
};
|
|
906
920
|
// Shared context for extracted module-level functions. Bundles immutable references with shared mutable state objects.
|
|
907
|
-
const ctx = { channelName, lifecycle, onError, stats, streamId };
|
|
921
|
+
const ctx = { channelName, clock, lifecycle, onError, stats, streamId };
|
|
908
922
|
/* The two tracks' pipeline bindings. Construction happens here, at the proxy's composition root, so the pipeline that serves both loops carries no branch on
|
|
909
923
|
* which track it is running: everything that differs between them - where segments are stored, how many are stored, how they are named, which initialization
|
|
910
924
|
* slot they read, and the extra bookkeeping video alone keeps - is data on these two objects.
|
|
@@ -912,7 +926,7 @@ export function createNativeProxy(options) {
|
|
|
912
926
|
const videoPipeline = {
|
|
913
927
|
afterCommit: ({ byteLength, storedBefore }) => {
|
|
914
928
|
video.lastSegmentSize = byteLength;
|
|
915
|
-
video.lastSegmentTime =
|
|
929
|
+
video.lastSegmentTime = ctx.clock.now();
|
|
916
930
|
// Log the first segment fetch latency for timing diagnostics.
|
|
917
931
|
if (stats.totalSegmentsFetched === 1) {
|
|
918
932
|
LOG.debug("timing:native", "First segment fetched for %s (%s bytes).", channelName, byteLength);
|
|
@@ -969,34 +983,44 @@ export function createNativeProxy(options) {
|
|
|
969
983
|
return Math.round(lifecycle.manifestBackoffMs * jitter);
|
|
970
984
|
}
|
|
971
985
|
/**
|
|
972
|
-
* Orchestrates the poll cycle: fetches video
|
|
986
|
+
* Orchestrates the poll cycle: fetches the video manifest first, then runs video segment processing in parallel with the audio poll (the audio manifest fetch
|
|
987
|
+
* and its segments), and generates playlists after both stores are updated.
|
|
973
988
|
*/
|
|
974
989
|
async function pollManifest() {
|
|
975
990
|
if (lifecycle.stopped) {
|
|
976
991
|
return;
|
|
977
992
|
}
|
|
978
|
-
const pollElapsed = startTimer();
|
|
993
|
+
const pollElapsed = startTimer(clock);
|
|
979
994
|
try {
|
|
980
|
-
const
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
995
|
+
const bound = timeoutSignal(SEGMENT_FETCH_TIMEOUT, { clock });
|
|
996
|
+
let body;
|
|
997
|
+
try {
|
|
998
|
+
const response = await chromeFetch(video.variantUrl, { signal: bound.signal });
|
|
999
|
+
if (!response.ok) {
|
|
1000
|
+
video.consecutiveManifestFailures++;
|
|
1001
|
+
stats.totalFetchErrors++;
|
|
1002
|
+
// Classify the error via the shared threshold helper. Client errors (4xx) use the base threshold; server errors (5xx) and network conditions get double
|
|
1003
|
+
// the attempts. This is the same logic the audio poll path uses, so video and audio escalate identically.
|
|
1004
|
+
const isClientError = (response.status >= 400) && (response.status < 500);
|
|
1005
|
+
const effectiveThreshold = manifestFailureThreshold(response.status);
|
|
1006
|
+
LOG.debug("native:proxy", "Manifest poll failed for %s: HTTP %s (%s, %s/%s).", channelName, response.status, isClientError ? "client" : "server", video.consecutiveManifestFailures, effectiveThreshold);
|
|
1007
|
+
if (video.consecutiveManifestFailures >= effectiveThreshold) {
|
|
1008
|
+
escalateProxyFailure({ ctx, message: "manifest poll failed " + String(video.consecutiveManifestFailures) + " times (HTTP " +
|
|
1009
|
+
String(response.status) + ")" });
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
schedulePoll(nextBackoffDelay());
|
|
992
1013
|
return;
|
|
993
1014
|
}
|
|
994
|
-
|
|
995
|
-
|
|
1015
|
+
video.consecutiveManifestFailures = 0;
|
|
1016
|
+
lifecycle.manifestBackoffMs = MANIFEST_BACKOFF_BASE;
|
|
1017
|
+
body = await response.text();
|
|
1018
|
+
}
|
|
1019
|
+
finally {
|
|
1020
|
+
// The bound covers this poll's own network wait and nothing past it: a bound is armed for exactly the wait it bounds and disposed the moment that wait
|
|
1021
|
+
// settles, so the segment work below runs with no timer of this poll's left pending on the proxy's clock.
|
|
1022
|
+
bound.cancel();
|
|
996
1023
|
}
|
|
997
|
-
video.consecutiveManifestFailures = 0;
|
|
998
|
-
lifecycle.manifestBackoffMs = MANIFEST_BACKOFF_BASE;
|
|
999
|
-
const body = await response.text();
|
|
1000
1024
|
LOG.debug("native:proxy", "Manifest poll for %s completed in %sms.", channelName, pollElapsed());
|
|
1001
1025
|
LOG.debug("native:manifest", "Variant manifest for %s:\n%s", channelName, body);
|
|
1002
1026
|
// Fetch and store video and audio segments in parallel so neither delays the other, and generate playlists after both stores are updated. This ensures video
|
|
@@ -1046,7 +1070,7 @@ export function createNativeProxy(options) {
|
|
|
1046
1070
|
schedulePoll(nextBackoffDelay());
|
|
1047
1071
|
return;
|
|
1048
1072
|
}
|
|
1049
|
-
// Schedule the next poll at MANIFEST_BACKOFF_BASE
|
|
1073
|
+
// Schedule the next poll at MANIFEST_BACKOFF_BASE for timely detection of new segments.
|
|
1050
1074
|
lifecycle.manifestBackoffMs = MANIFEST_BACKOFF_BASE;
|
|
1051
1075
|
schedulePoll(MANIFEST_BACKOFF_BASE);
|
|
1052
1076
|
}
|
|
@@ -1114,7 +1138,7 @@ export function createNativeProxy(options) {
|
|
|
1114
1138
|
* Fetches and optionally decrypts a segment. This is the shared core used by both video and audio fetch paths, for media segments and for the initialization
|
|
1115
1139
|
* segments an fMP4 source references. It handles the HTTP fetch, AES-128 decryption with key caching, and IV derivation. A caller with no key URL gets a plain
|
|
1116
1140
|
* fetch, since the decryption block below gates on the key and the sequence argument only feeds keyed-IV derivation. Error tracking is the caller's
|
|
1117
|
-
* responsibility since video and audio
|
|
1141
|
+
* responsibility since video and audio keep separate consecutive-failure counts against the shared MAX_SEGMENT_FAILURES threshold.
|
|
1118
1142
|
*
|
|
1119
1143
|
* @param url - The segment URL.
|
|
1120
1144
|
* @param sequence - The media sequence number (for IV derivation).
|
|
@@ -1124,15 +1148,23 @@ export function createNativeProxy(options) {
|
|
|
1124
1148
|
* @returns The segment data (decrypted if necessary), or null on failure.
|
|
1125
1149
|
*/
|
|
1126
1150
|
async function fetchAndDecryptSegment(url, sequence, ivHex, segKeyUrl, abortSignal) {
|
|
1127
|
-
// The caller's cancellation and this fetch's own
|
|
1128
|
-
//
|
|
1129
|
-
const
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1151
|
+
// The caller's cancellation and this fetch's own bound are composed, so the segment ends on whichever arrives first and a caller with nothing to cancel gets
|
|
1152
|
+
// the bound alone.
|
|
1153
|
+
const bound = timeoutSignal(SEGMENT_FETCH_TIMEOUT, { clock });
|
|
1154
|
+
let data;
|
|
1155
|
+
try {
|
|
1156
|
+
const response = await chromeFetch(url, { signal: abortSignal ? AbortSignal.any([abortSignal, bound.signal]) : bound.signal });
|
|
1157
|
+
if (!response.ok) {
|
|
1158
|
+
LOG.debug("native:proxy", "Segment fetch failed for %s: HTTP %s.", channelName, response.status);
|
|
1159
|
+
return null;
|
|
1160
|
+
}
|
|
1161
|
+
data = Buffer.from(await response.arrayBuffer());
|
|
1162
|
+
}
|
|
1163
|
+
finally {
|
|
1164
|
+
// The bound covers the segment's own fetch and body read. The key lookup below carries its own bound, and the decryption is pure work, so neither belongs
|
|
1165
|
+
// inside this one.
|
|
1166
|
+
bound.cancel();
|
|
1134
1167
|
}
|
|
1135
|
-
let data = Buffer.from(await response.arrayBuffer());
|
|
1136
1168
|
// Decrypt if this segment has a key URL. The manifest's #EXT-X-KEY tag is authoritative - DAI streams can switch between clear and AES-128 mid-stream (e.g., ad
|
|
1137
1169
|
// pods encrypted while main content is clear), so the initial probe classification cannot be relied upon. Segments before the first #EXT-X-KEY tag have
|
|
1138
1170
|
// segKeyUrl === null (clear).
|
|
@@ -1142,7 +1174,7 @@ export function createNativeProxy(options) {
|
|
|
1142
1174
|
if (!key) {
|
|
1143
1175
|
// The key fetch receives the raw cancellation signal rather than the composed one above, so it gets its own full timeout budget instead of inheriting
|
|
1144
1176
|
// whatever this segment's fetch has already spent.
|
|
1145
|
-
key = await fetchDecryptionKey(segKeyUrl, abortSignal) ?? undefined;
|
|
1177
|
+
key = await fetchDecryptionKey(segKeyUrl, { clock, signal: abortSignal }) ?? undefined;
|
|
1146
1178
|
if (!key) {
|
|
1147
1179
|
LOG.debug("native:proxy", "Decryption key unavailable for %s (key URL: %s).", channelName, segKeyUrl.slice(0, 80));
|
|
1148
1180
|
return null;
|
|
@@ -1193,10 +1225,10 @@ export function createNativeProxy(options) {
|
|
|
1193
1225
|
}
|
|
1194
1226
|
/**
|
|
1195
1227
|
* Generates playlists from the stored segments. For streams without separate audio, generates a single variant playlist. When preroll is active (muxed audio only),
|
|
1196
|
-
* produces a composite playlist with fMP4 preroll entries and MPEG-TS
|
|
1197
|
-
* served during the standalone preroll phase, ensuring smooth MEDIA-SEQUENCE progression. For streams with separate audio,
|
|
1198
|
-
* and the master playlist referencing video.m3u8 and audio.m3u8 (no preroll - preroll is muxed and can't be split into
|
|
1199
|
-
* playlist is produced separately by generateAudioPlaylist(), which the poll loop calls alongside this function.
|
|
1228
|
+
* produces a composite playlist with fMP4 preroll entries and the relayed source's real entries (MPEG-TS or fMP4) bridged by a DISCONTINUITY tag. The preroll
|
|
1229
|
+
* entries use the same fMP4 segments served during the standalone preroll phase, ensuring smooth MEDIA-SEQUENCE progression. For streams with separate audio,
|
|
1230
|
+
* generates the video variant playlist and the master playlist referencing video.m3u8 and audio.m3u8 (no preroll - preroll is muxed and can't be split into
|
|
1231
|
+
* separate renditions); the audio variant playlist is produced separately by generateAudioPlaylist(), which the poll loop calls alongside this function.
|
|
1200
1232
|
*
|
|
1201
1233
|
* @param targetDuration - The #EXT-X-TARGETDURATION value from the service's manifest.
|
|
1202
1234
|
*/
|
|
@@ -1207,10 +1239,11 @@ export function createNativeProxy(options) {
|
|
|
1207
1239
|
}
|
|
1208
1240
|
const segmentEntries = Array.from(stream.hls.segments.keys());
|
|
1209
1241
|
if (!hasAudio) {
|
|
1210
|
-
if ((prerollSegmentCount > 0) && stream.hls.prerollStartTime && stream.hls.prerollBaseUrl) {
|
|
1211
|
-
// Composite playlist with fMP4 preroll entries
|
|
1212
|
-
// timer has fired and the client is actually watching preroll. Without this check, fast native streams (where
|
|
1213
|
-
// would include unnecessary preroll entries. The compositor handles the sliding window with the
|
|
1242
|
+
if ((prerollSegmentCount > 0) && (stream.hls.prerollStartTime !== null) && stream.hls.prerollBaseUrl) {
|
|
1243
|
+
// Composite playlist with fMP4 preroll entries and the relayed source's real entries (MPEG-TS or fMP4). The prerollStartTime check ensures we only
|
|
1244
|
+
// include preroll entries when the deferred timer has fired and the client is actually watching preroll. Without this check, fast native streams (where
|
|
1245
|
+
// real content arrives before the preroll delay) would include unnecessary preroll entries. The compositor handles the sliding window with the
|
|
1246
|
+
// preroll-in-window cap.
|
|
1214
1247
|
updatePlaylist(streamId, buildCompositePlaylist({
|
|
1215
1248
|
composite,
|
|
1216
1249
|
prerollBaseUrl: stream.hls.prerollBaseUrl,
|
|
@@ -1220,19 +1253,19 @@ export function createNativeProxy(options) {
|
|
|
1220
1253
|
segmentIndex: video.segmentIndex,
|
|
1221
1254
|
targetDuration,
|
|
1222
1255
|
videoMetadata: video.metadata
|
|
1223
|
-
}));
|
|
1256
|
+
}), clock.now());
|
|
1224
1257
|
}
|
|
1225
1258
|
else {
|
|
1226
1259
|
// No preroll active - standard variant playlist. The segment index may still be offset (starting at prerollSegmentCount) to reserve the index space, but no
|
|
1227
1260
|
// preroll entries are included.
|
|
1228
|
-
updatePlaylist(streamId, buildVariantPlaylist(segmentEntries, video.metadata, "segment", targetDuration));
|
|
1261
|
+
updatePlaylist(streamId, buildVariantPlaylist(segmentEntries, video.metadata, "segment", targetDuration), clock.now());
|
|
1229
1262
|
}
|
|
1230
1263
|
}
|
|
1231
1264
|
else {
|
|
1232
1265
|
// Separate audio - generate video variant playlist and master playlist. Preroll is not supported for separate audio streams (preroll is muxed).
|
|
1233
1266
|
updateVideoPlaylist(streamId, buildVariantPlaylist(segmentEntries, video.metadata, "segment", targetDuration));
|
|
1234
1267
|
// Estimate bandwidth from stored segment sizes and durations. Sum total bytes and total duration across video segments, then convert to bits per second.
|
|
1235
|
-
// Falls back to 5 Mbps when no duration
|
|
1268
|
+
// Falls back to 5 Mbps when the video window holds no segment with a usable duration yet, such as an audio advance arriving before the first video segment.
|
|
1236
1269
|
let bandwidth = 5000000;
|
|
1237
1270
|
let totalBytes = 0;
|
|
1238
1271
|
let totalDuration = 0;
|
|
@@ -1252,7 +1285,7 @@ export function createNativeProxy(options) {
|
|
|
1252
1285
|
"#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"audio\",NAME=\"English\",DEFAULT=YES,AUTOSELECT=YES,URI=\"audio.m3u8\"\n" +
|
|
1253
1286
|
"#EXT-X-STREAM-INF:BANDWIDTH=" + String(bandwidth) + ",AUDIO=\"audio\"\n" +
|
|
1254
1287
|
"video.m3u8\n";
|
|
1255
|
-
updatePlaylist(streamId, masterPlaylist);
|
|
1288
|
+
updatePlaylist(streamId, masterPlaylist, clock.now());
|
|
1256
1289
|
}
|
|
1257
1290
|
// Release initialization segments the freshly-generated window no longer references. This runs after generation so the retain set reflects exactly the
|
|
1258
1291
|
// segments the playlist just published.
|
|
@@ -1276,11 +1309,11 @@ export function createNativeProxy(options) {
|
|
|
1276
1309
|
pruneTrackInits(streamId, "audio", audio.metadata, audioEntries);
|
|
1277
1310
|
}
|
|
1278
1311
|
/**
|
|
1279
|
-
* Schedules the next manifest poll after a delay. The sleep is awaited through the injected Clock port (defaulting to
|
|
1280
|
-
* polling cadence
|
|
1281
|
-
* issuing the next poll. The in-flight sleep itself is not cancelled - in production a stopped proxy lingers for at most the currently
|
|
1282
|
-
* which can be as long as MANIFEST_BACKOFF_CAP once jittered, before the awaiter wakes and exits cleanly. This is the same shape
|
|
1283
|
-
* utils/retry.ts
|
|
1312
|
+
* Schedules the next manifest poll after a delay. The sleep is awaited through the injected Clock port (defaulting to the system clock) so tests drive the
|
|
1313
|
+
* polling cadence on a virtual timeline rather than against real timers. Cancellation semantics: stop() flips lifecycle.stopped, and the post-sleep guard
|
|
1314
|
+
* catches that flip before issuing the next poll. The in-flight sleep itself is not cancelled - in production a stopped proxy lingers for at most the currently
|
|
1315
|
+
* scheduled poll delay, which can be as long as MANIFEST_BACKOFF_CAP once jittered, before the awaiter wakes and exits cleanly. This is the same shape
|
|
1316
|
+
* retryOperation in utils/retry.ts takes, for the same reason.
|
|
1284
1317
|
*
|
|
1285
1318
|
* @param delayMs - Delay in milliseconds before the next poll.
|
|
1286
1319
|
*/
|
|
@@ -1289,28 +1322,27 @@ export function createNativeProxy(options) {
|
|
|
1289
1322
|
return;
|
|
1290
1323
|
}
|
|
1291
1324
|
void (async () => {
|
|
1292
|
-
await clock.
|
|
1325
|
+
await clock.delay(delayMs);
|
|
1293
1326
|
if (lifecycle.stopped) {
|
|
1294
1327
|
return;
|
|
1295
1328
|
}
|
|
1296
1329
|
void pollManifest();
|
|
1297
1330
|
})();
|
|
1298
1331
|
}
|
|
1299
|
-
// The proxy's teardown: flip the lifecycle flag the polling awaiter checks, and cancel the pending token-refresh timer.
|
|
1300
|
-
// both as stop() (the established domain verb) and as [Symbol.dispose] (the TC39 protocol), making the proxy a
|
|
1332
|
+
// The proxy's teardown: flip the lifecycle flag the polling awaiter checks, cancel the proxy's open fetches, and cancel the pending token-refresh timer.
|
|
1333
|
+
// Defined as a const so it can be exposed both as stop() (the established domain verb) and as [Symbol.dispose] (the TC39 protocol), making the proxy a
|
|
1334
|
+
// self-disposing node without duplicating the body.
|
|
1301
1335
|
const stop = () => {
|
|
1302
1336
|
lifecycle.stopped = true;
|
|
1303
1337
|
// Cancel every fetch the proxy still has open - segments, initialization segments, and decryption keys - so teardown does not wait on a CDN and no
|
|
1304
1338
|
// straggler write can land after the stream's state has been cleared.
|
|
1305
1339
|
lifecycle.abortController.abort();
|
|
1306
|
-
// The polling cadence sleep is owned by schedulePoll's awaiter and is not cancelled here - the awaiter checks lifecycle.stopped after clock.
|
|
1340
|
+
// The polling cadence sleep is owned by schedulePoll's awaiter and is not cancelled here - the awaiter checks lifecycle.stopped after clock.delay resolves
|
|
1307
1341
|
// and exits before issuing the next poll. See schedulePoll's docblock for the cancellation contract.
|
|
1308
1342
|
// Cancel the pending token refresh timer to prevent fire-after-termination. Without this, the timer fires on a stopped proxy and attempts to navigate a
|
|
1309
1343
|
// potentially closed or reused page.
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
lifecycle.tokenRefreshTimer = null;
|
|
1313
|
-
}
|
|
1344
|
+
lifecycle.tokenRefreshTimer?.[Symbol.dispose]();
|
|
1345
|
+
lifecycle.tokenRefreshTimer = null;
|
|
1314
1346
|
LOG.debug("native:proxy", "Stopped native proxy for %s.", channelName);
|
|
1315
1347
|
};
|
|
1316
1348
|
return {
|
|
@@ -1345,9 +1377,7 @@ export function createNativeProxy(options) {
|
|
|
1345
1377
|
* handle is live when the stream ends.
|
|
1346
1378
|
*/
|
|
1347
1379
|
setTokenRefreshTimer: (timer) => {
|
|
1348
|
-
|
|
1349
|
-
clearTimeout(lifecycle.tokenRefreshTimer);
|
|
1350
|
-
}
|
|
1380
|
+
lifecycle.tokenRefreshTimer?.[Symbol.dispose]();
|
|
1351
1381
|
lifecycle.tokenRefreshTimer = timer;
|
|
1352
1382
|
},
|
|
1353
1383
|
start: () => {
|