prismcast 1.10.2 → 1.11.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 +6 -3
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +140 -86
- package/dist/app.js.map +1 -1
- package/dist/browser/blockedPage.d.ts +80 -0
- package/dist/browser/blockedPage.d.ts.map +1 -0
- package/dist/browser/blockedPage.js +209 -0
- package/dist/browser/blockedPage.js.map +1 -0
- package/dist/browser/browserSupervisor.d.ts +80 -0
- package/dist/browser/browserSupervisor.d.ts.map +1 -0
- package/dist/browser/browserSupervisor.js +186 -0
- package/dist/browser/browserSupervisor.js.map +1 -0
- package/dist/browser/cdp.d.ts +1 -0
- package/dist/browser/cdp.d.ts.map +1 -0
- package/dist/browser/cdp.js +6 -5
- package/dist/browser/cdp.js.map +1 -1
- package/dist/browser/channelSelection.d.ts +45 -14
- package/dist/browser/channelSelection.d.ts.map +1 -0
- package/dist/browser/channelSelection.js +81 -18
- package/dist/browser/channelSelection.js.map +1 -1
- package/dist/browser/consent.d.ts +152 -0
- package/dist/browser/consent.d.ts.map +1 -0
- package/dist/browser/consent.js +418 -0
- package/dist/browser/consent.js.map +1 -0
- package/dist/browser/display.d.ts +1 -0
- package/dist/browser/display.d.ts.map +1 -0
- package/dist/browser/hlsPlaylistObserver.d.ts +55 -0
- package/dist/browser/hlsPlaylistObserver.d.ts.map +1 -0
- package/dist/browser/hlsPlaylistObserver.js +132 -0
- package/dist/browser/hlsPlaylistObserver.js.map +1 -0
- package/dist/browser/index.d.ts +67 -40
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +508 -300
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/launchGovernor.d.ts +89 -0
- package/dist/browser/launchGovernor.d.ts.map +1 -0
- package/dist/browser/launchGovernor.js +96 -0
- package/dist/browser/launchGovernor.js.map +1 -0
- package/dist/browser/login.d.ts +10 -2
- package/dist/browser/login.d.ts.map +1 -0
- package/dist/browser/login.js +36 -5
- package/dist/browser/login.js.map +1 -1
- package/dist/browser/manifestInterceptor.d.ts +102 -49
- package/dist/browser/manifestInterceptor.d.ts.map +1 -0
- package/dist/browser/manifestInterceptor.js +219 -237
- package/dist/browser/manifestInterceptor.js.map +1 -1
- package/dist/browser/pageStaleness.d.ts +30 -0
- package/dist/browser/pageStaleness.d.ts.map +1 -0
- package/dist/browser/pageStaleness.js +76 -0
- package/dist/browser/pageStaleness.js.map +1 -0
- package/dist/browser/precaching.d.ts +95 -3
- package/dist/browser/precaching.d.ts.map +1 -0
- package/dist/browser/precaching.js +499 -65
- package/dist/browser/precaching.js.map +1 -1
- package/dist/browser/tabNetworkObserver.d.ts +49 -0
- package/dist/browser/tabNetworkObserver.d.ts.map +1 -0
- package/dist/browser/tabNetworkObserver.js +144 -0
- package/dist/browser/tabNetworkObserver.js.map +1 -0
- package/dist/browser/tuning/cache.d.ts +61 -0
- package/dist/browser/tuning/cache.d.ts.map +1 -0
- package/dist/browser/tuning/cache.js +62 -0
- package/dist/browser/tuning/cache.js.map +1 -0
- package/dist/browser/tuning/comcastPolymer.d.ts +3 -2
- package/dist/browser/tuning/comcastPolymer.d.ts.map +1 -0
- package/dist/browser/tuning/comcastPolymer.js +79 -102
- package/dist/browser/tuning/comcastPolymer.js.map +1 -1
- package/dist/browser/tuning/cox.d.ts +1 -0
- package/dist/browser/tuning/cox.d.ts.map +1 -0
- package/dist/browser/tuning/directv.d.ts +1 -0
- package/dist/browser/tuning/directv.d.ts.map +1 -0
- package/dist/browser/tuning/directv.js +52 -46
- package/dist/browser/tuning/directv.js.map +1 -1
- package/dist/browser/tuning/fox.d.ts +1 -0
- package/dist/browser/tuning/fox.d.ts.map +1 -0
- package/dist/browser/tuning/fox.js +13 -12
- package/dist/browser/tuning/fox.js.map +1 -1
- package/dist/browser/tuning/gridSearch.d.ts +68 -0
- package/dist/browser/tuning/gridSearch.d.ts.map +1 -0
- package/dist/browser/tuning/gridSearch.js +85 -0
- package/dist/browser/tuning/gridSearch.js.map +1 -0
- package/dist/browser/tuning/hbo.d.ts +1 -0
- package/dist/browser/tuning/hbo.d.ts.map +1 -0
- package/dist/browser/tuning/hbo.js +73 -45
- package/dist/browser/tuning/hbo.js.map +1 -1
- package/dist/browser/tuning/hulu.d.ts +1 -0
- package/dist/browser/tuning/hulu.d.ts.map +1 -0
- package/dist/browser/tuning/hulu.js +128 -173
- package/dist/browser/tuning/hulu.js.map +1 -1
- package/dist/browser/tuning/shared.d.ts +75 -5
- package/dist/browser/tuning/shared.d.ts.map +1 -0
- package/dist/browser/tuning/shared.js +216 -6
- package/dist/browser/tuning/shared.js.map +1 -1
- package/dist/browser/tuning/sling.d.ts +1 -0
- package/dist/browser/tuning/sling.d.ts.map +1 -0
- package/dist/browser/tuning/sling.js +105 -126
- package/dist/browser/tuning/sling.js.map +1 -1
- package/dist/browser/tuning/spectrum.d.ts +1 -0
- package/dist/browser/tuning/spectrum.d.ts.map +1 -0
- package/dist/browser/tuning/spectrum.js +80 -125
- package/dist/browser/tuning/spectrum.js.map +1 -1
- package/dist/browser/tuning/thumbnailRow.d.ts +1 -0
- package/dist/browser/tuning/thumbnailRow.d.ts.map +1 -0
- package/dist/browser/tuning/thumbnailRow.js +8 -2
- package/dist/browser/tuning/thumbnailRow.js.map +1 -1
- package/dist/browser/tuning/tileClick.d.ts +1 -0
- package/dist/browser/tuning/tileClick.d.ts.map +1 -0
- package/dist/browser/tuning/tileClick.js +3 -2
- package/dist/browser/tuning/tileClick.js.map +1 -1
- package/dist/browser/tuning/xfinity.d.ts +1 -0
- package/dist/browser/tuning/xfinity.d.ts.map +1 -0
- package/dist/browser/tuning/youtubeTv.d.ts +1 -0
- package/dist/browser/tuning/youtubeTv.d.ts.map +1 -0
- package/dist/browser/tuning/youtubeTv.js +74 -127
- package/dist/browser/tuning/youtubeTv.js.map +1 -1
- package/dist/browser/video.d.ts +54 -14
- package/dist/browser/video.d.ts.map +1 -0
- package/dist/browser/video.js +296 -138
- package/dist/browser/video.js.map +1 -1
- package/dist/channels/index.d.ts +1 -0
- package/dist/channels/index.d.ts.map +1 -0
- package/dist/channels/index.js +12 -9
- package/dist/channels/index.js.map +1 -1
- package/dist/config/channelForm.d.ts +15 -1
- package/dist/config/channelForm.d.ts.map +1 -0
- package/dist/config/channelForm.js +28 -12
- package/dist/config/channelForm.js.map +1 -1
- package/dist/config/consistencyProbe.d.ts +1 -0
- package/dist/config/consistencyProbe.d.ts.map +1 -0
- package/dist/config/consistencyProbe.js +27 -21
- package/dist/config/consistencyProbe.js.map +1 -1
- package/dist/config/health.d.ts +41 -8
- package/dist/config/health.d.ts.map +1 -0
- package/dist/config/health.js +189 -38
- package/dist/config/health.js.map +1 -1
- package/dist/config/index.d.ts +55 -3
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +320 -69
- package/dist/config/index.js.map +1 -1
- package/dist/config/paths.d.ts +10 -9
- package/dist/config/paths.d.ts.map +1 -0
- package/dist/config/paths.js +11 -11
- package/dist/config/paths.js.map +1 -1
- package/dist/config/persistence.context.d.ts +1 -0
- package/dist/config/persistence.context.d.ts.map +1 -0
- package/dist/config/persistence.d.ts +13 -10
- package/dist/config/persistence.d.ts.map +1 -0
- package/dist/config/persistence.js +40 -21
- package/dist/config/persistence.js.map +1 -1
- package/dist/config/presets.d.ts +1 -0
- package/dist/config/presets.d.ts.map +1 -0
- package/dist/config/profiles.d.ts +22 -15
- package/dist/config/profiles.d.ts.map +1 -0
- package/dist/config/profiles.js +81 -47
- package/dist/config/profiles.js.map +1 -1
- package/dist/config/providerLineups.d.ts +47 -0
- package/dist/config/providerLineups.d.ts.map +1 -0
- package/dist/config/providerLineups.js +137 -0
- package/dist/config/providerLineups.js.map +1 -0
- package/dist/config/reactivity.d.ts +84 -0
- package/dist/config/reactivity.d.ts.map +1 -0
- package/dist/config/reactivity.js +226 -0
- package/dist/config/reactivity.js.map +1 -0
- package/dist/config/servicePacks.d.ts +18 -2
- package/dist/config/servicePacks.d.ts.map +1 -0
- package/dist/config/servicePacks.js +53 -11
- package/dist/config/servicePacks.js.map +1 -1
- package/dist/config/services.d.ts +21 -15
- package/dist/config/services.d.ts.map +1 -0
- package/dist/config/services.js +35 -24
- package/dist/config/services.js.map +1 -1
- package/dist/config/sites.d.ts +6 -4
- package/dist/config/sites.d.ts.map +1 -0
- package/dist/config/sites.js +15 -11
- package/dist/config/sites.js.map +1 -1
- package/dist/config/userChannels.d.ts +129 -30
- package/dist/config/userChannels.d.ts.map +1 -0
- package/dist/config/userChannels.js +333 -68
- package/dist/config/userChannels.js.map +1 -1
- package/dist/config/userConfig.d.ts +14 -9
- package/dist/config/userConfig.d.ts.map +1 -0
- package/dist/config/userConfig.js +87 -25
- package/dist/config/userConfig.js.map +1 -1
- package/dist/config/userProfiles.d.ts +10 -6
- package/dist/config/userProfiles.d.ts.map +1 -0
- package/dist/config/userProfiles.js +64 -39
- package/dist/config/userProfiles.js.map +1 -1
- package/dist/hdhr/channelMap.d.ts +1 -0
- package/dist/hdhr/channelMap.d.ts.map +1 -0
- package/dist/hdhr/deviceId.d.ts +1 -0
- package/dist/hdhr/deviceId.d.ts.map +1 -0
- package/dist/hdhr/discover.d.ts +1 -0
- package/dist/hdhr/discover.d.ts.map +1 -0
- package/dist/hdhr/discover.js +48 -47
- package/dist/hdhr/discover.js.map +1 -1
- package/dist/hdhr/getHandlers.d.ts +29 -0
- package/dist/hdhr/getHandlers.d.ts.map +1 -0
- package/dist/hdhr/getHandlers.js +196 -0
- package/dist/hdhr/getHandlers.js.map +1 -0
- package/dist/hdhr/identity.d.ts +36 -0
- package/dist/hdhr/identity.d.ts.map +1 -0
- package/dist/hdhr/identity.js +51 -0
- package/dist/hdhr/identity.js.map +1 -0
- package/dist/hdhr/index.d.ts +22 -4
- package/dist/hdhr/index.d.ts.map +1 -0
- package/dist/hdhr/index.js +229 -54
- package/dist/hdhr/index.js.map +1 -1
- package/dist/hdhr/protocol.d.ts +75 -0
- package/dist/hdhr/protocol.d.ts.map +1 -0
- package/dist/hdhr/protocol.js +264 -0
- package/dist/hdhr/protocol.js.map +1 -0
- package/dist/hdhr/tunerState.d.ts +24 -0
- package/dist/hdhr/tunerState.d.ts.map +1 -0
- package/dist/hdhr/tunerState.js +67 -0
- package/dist/hdhr/tunerState.js.map +1 -0
- package/dist/hdhr/udp.d.ts +43 -0
- package/dist/hdhr/udp.d.ts.map +1 -0
- package/dist/hdhr/udp.js +277 -0
- package/dist/hdhr/udp.js.map +1 -0
- package/dist/identity.d.ts +1 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +13 -11
- package/dist/identity.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -12
- package/dist/index.js.map +1 -1
- package/dist/native/codecInference.d.ts +1 -0
- package/dist/native/codecInference.d.ts.map +1 -0
- package/dist/native/codecInference.js +50 -5
- package/dist/native/codecInference.js.map +1 -1
- package/dist/native/decrypt.d.ts +6 -2
- package/dist/native/decrypt.d.ts.map +1 -0
- package/dist/native/decrypt.js +15 -8
- package/dist/native/decrypt.js.map +1 -1
- package/dist/native/index.d.ts +40 -17
- package/dist/native/index.d.ts.map +1 -0
- package/dist/native/index.js +281 -120
- package/dist/native/index.js.map +1 -1
- package/dist/native/probe.d.ts +114 -18
- package/dist/native/probe.d.ts.map +1 -0
- package/dist/native/probe.js +452 -115
- package/dist/native/probe.js.map +1 -1
- package/dist/native/proxy.d.ts +57 -5
- package/dist/native/proxy.d.ts.map +1 -0
- package/dist/native/proxy.js +604 -170
- package/dist/native/proxy.js.map +1 -1
- package/dist/native/tokenExpiry.d.ts +1 -0
- package/dist/native/tokenExpiry.d.ts.map +1 -0
- package/dist/native/tokenExpiry.js +1 -1
- package/dist/routes/assets.d.ts +1 -0
- package/dist/routes/assets.d.ts.map +1 -0
- package/dist/routes/assets.js +4 -2
- package/dist/routes/assets.js.map +1 -1
- package/dist/routes/auth.d.ts +1 -0
- package/dist/routes/auth.d.ts.map +1 -0
- package/dist/routes/auth.js +0 -1
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/cdp.d.ts +5 -5
- package/dist/routes/cdp.d.ts.map +1 -0
- package/dist/routes/cdp.js +59 -20
- package/dist/routes/cdp.js.map +1 -1
- package/dist/routes/channels.d.ts +1 -0
- package/dist/routes/channels.d.ts.map +1 -0
- package/dist/routes/channels.js +2 -1
- package/dist/routes/channels.js.map +1 -1
- package/dist/routes/clientActions.d.ts +98 -0
- package/dist/routes/clientActions.d.ts.map +1 -0
- package/dist/routes/clientActions.js +113 -0
- package/dist/routes/clientActions.js.map +1 -0
- package/dist/routes/components.d.ts +5 -3
- package/dist/routes/components.d.ts.map +1 -0
- package/dist/routes/components.js +36 -39
- package/dist/routes/components.js.map +1 -1
- package/dist/routes/config/channels/endpoints/browse.d.ts +1 -0
- package/dist/routes/config/channels/endpoints/browse.d.ts.map +1 -0
- package/dist/routes/config/channels/endpoints/browse.js +23 -10
- package/dist/routes/config/channels/endpoints/browse.js.map +1 -1
- package/dist/routes/config/channels/endpoints/bulk.d.ts +1 -0
- package/dist/routes/config/channels/endpoints/bulk.d.ts.map +1 -0
- package/dist/routes/config/channels/endpoints/bulk.js +5 -3
- package/dist/routes/config/channels/endpoints/bulk.js.map +1 -1
- package/dist/routes/config/channels/endpoints/crud.d.ts +1 -0
- package/dist/routes/config/channels/endpoints/crud.d.ts.map +1 -0
- package/dist/routes/config/channels/endpoints/crud.js +85 -93
- package/dist/routes/config/channels/endpoints/crud.js.map +1 -1
- package/dist/routes/config/channels/endpoints/importExport.d.ts +1 -0
- package/dist/routes/config/channels/endpoints/importExport.d.ts.map +1 -0
- package/dist/routes/config/channels/endpoints/importExport.js +6 -3
- package/dist/routes/config/channels/endpoints/importExport.js.map +1 -1
- package/dist/routes/config/channels/endpoints/predefined.d.ts +1 -0
- package/dist/routes/config/channels/endpoints/predefined.d.ts.map +1 -0
- package/dist/routes/config/channels/endpoints/prefs.d.ts +1 -0
- package/dist/routes/config/channels/endpoints/prefs.d.ts.map +1 -0
- package/dist/routes/config/channels/endpoints/prefs.js +2 -1
- package/dist/routes/config/channels/endpoints/prefs.js.map +1 -1
- package/dist/routes/config/channels/endpoints/service.d.ts +2 -1
- package/dist/routes/config/channels/endpoints/service.d.ts.map +1 -0
- package/dist/routes/config/channels/endpoints/service.js +3 -1
- package/dist/routes/config/channels/endpoints/service.js.map +1 -1
- package/dist/routes/config/channels/endpoints/tags.d.ts +1 -0
- package/dist/routes/config/channels/endpoints/tags.d.ts.map +1 -0
- package/dist/routes/config/channels/endpoints/tags.js +13 -7
- package/dist/routes/config/channels/endpoints/tags.js.map +1 -1
- package/dist/routes/config/channels/healthBridge.d.ts +24 -0
- package/dist/routes/config/channels/healthBridge.d.ts.map +1 -0
- package/dist/routes/config/channels/healthBridge.js +71 -0
- package/dist/routes/config/channels/healthBridge.js.map +1 -0
- package/dist/routes/config/channels/http/handler.d.ts +1 -0
- package/dist/routes/config/channels/http/handler.d.ts.map +1 -0
- package/dist/routes/config/channels/http/playlistHint.d.ts +2 -1
- package/dist/routes/config/channels/http/playlistHint.d.ts.map +1 -0
- package/dist/routes/config/channels/http/playlistHint.js +16 -2
- package/dist/routes/config/channels/http/playlistHint.js.map +1 -1
- package/dist/routes/config/channels/http/serviceWarning.d.ts +4 -2
- package/dist/routes/config/channels/http/serviceWarning.d.ts.map +1 -0
- package/dist/routes/config/channels/http/serviceWarning.js +3 -2
- package/dist/routes/config/channels/http/serviceWarning.js.map +1 -1
- package/dist/routes/config/channels/index.d.ts +1 -0
- package/dist/routes/config/channels/index.d.ts.map +1 -0
- package/dist/routes/config/channels/setup.d.ts +1 -0
- package/dist/routes/config/channels/setup.d.ts.map +1 -0
- package/dist/routes/config/channels/table.d.ts +3 -3
- package/dist/routes/config/channels/table.d.ts.map +1 -0
- package/dist/routes/config/channels/table.js +148 -107
- package/dist/routes/config/channels/table.js.map +1 -1
- package/dist/routes/config/http/envelope.d.ts +1 -0
- package/dist/routes/config/http/envelope.d.ts.map +1 -0
- package/dist/routes/config/index.d.ts +35 -3
- package/dist/routes/config/index.d.ts.map +1 -0
- package/dist/routes/config/index.js +51 -2
- package/dist/routes/config/index.js.map +1 -1
- package/dist/routes/config/services.d.ts +5 -4
- package/dist/routes/config/services.d.ts.map +1 -0
- package/dist/routes/config/services.js +57 -43
- package/dist/routes/config/services.js.map +1 -1
- package/dist/routes/config/settings.d.ts +1 -0
- package/dist/routes/config/settings.d.ts.map +1 -0
- package/dist/routes/config/settings.js +98 -49
- package/dist/routes/config/settings.js.map +1 -1
- package/dist/routes/debug.d.ts +1 -0
- package/dist/routes/debug.d.ts.map +1 -0
- package/dist/routes/debug.js +277 -139
- package/dist/routes/debug.js.map +1 -1
- package/dist/routes/health.d.ts +39 -1
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +33 -27
- package/dist/routes/health.js.map +1 -1
- package/dist/routes/hls.d.ts +1 -0
- package/dist/routes/hls.d.ts.map +1 -0
- package/dist/routes/icons.d.ts +1 -0
- package/dist/routes/icons.d.ts.map +1 -0
- package/dist/routes/icons.js +1 -1
- package/dist/routes/index.d.ts +1 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/logs.d.ts +1 -0
- package/dist/routes/logs.d.ts.map +1 -0
- package/dist/routes/logs.js +14 -4
- package/dist/routes/logs.js.map +1 -1
- package/dist/routes/mpegts.d.ts +1 -0
- package/dist/routes/mpegts.d.ts.map +1 -0
- package/dist/routes/play.d.ts +1 -0
- package/dist/routes/play.d.ts.map +1 -0
- package/dist/routes/playlist.d.ts +1 -0
- package/dist/routes/playlist.d.ts.map +1 -0
- package/dist/routes/playlist.js +7 -2
- package/dist/routes/playlist.js.map +1 -1
- package/dist/routes/root/content.d.ts +8 -5
- package/dist/routes/root/content.d.ts.map +1 -0
- package/dist/routes/root/content.js +29 -26
- package/dist/routes/root/content.js.map +1 -1
- package/dist/routes/root/index.d.ts +2 -1
- package/dist/routes/root/index.d.ts.map +1 -0
- package/dist/routes/root/index.js +26 -21
- package/dist/routes/root/index.js.map +1 -1
- package/dist/routes/root/scripts/channels.d.ts +6 -0
- package/dist/routes/root/scripts/channels.d.ts.map +1 -0
- package/dist/routes/root/scripts/channels.js +197 -118
- package/dist/routes/root/scripts/channels.js.map +1 -1
- package/dist/routes/root/scripts/clientEscape.d.ts +22 -0
- package/dist/routes/root/scripts/clientEscape.d.ts.map +1 -0
- package/dist/routes/root/scripts/clientEscape.js +41 -0
- package/dist/routes/root/scripts/clientEscape.js.map +1 -0
- package/dist/routes/root/scripts/clientUrl.d.ts +23 -0
- package/dist/routes/root/scripts/clientUrl.d.ts.map +1 -0
- package/dist/routes/root/scripts/clientUrl.js +44 -0
- package/dist/routes/root/scripts/clientUrl.js.map +1 -0
- package/dist/routes/root/scripts/config.d.ts +6 -0
- package/dist/routes/root/scripts/config.d.ts.map +1 -0
- package/dist/routes/root/scripts/config.js +110 -24
- package/dist/routes/root/scripts/config.js.map +1 -1
- package/dist/routes/root/scripts/index.d.ts +1 -0
- package/dist/routes/root/scripts/index.d.ts.map +1 -0
- package/dist/routes/root/scripts/shared.d.ts +1 -0
- package/dist/routes/root/scripts/shared.d.ts.map +1 -0
- package/dist/routes/root/scripts/shared.js +112 -26
- package/dist/routes/root/scripts/shared.js.map +1 -1
- package/dist/routes/root/scripts/status.d.ts +1 -0
- package/dist/routes/root/scripts/status.d.ts.map +1 -0
- package/dist/routes/root/scripts/status.handlers.d.ts +23 -33
- package/dist/routes/root/scripts/status.handlers.d.ts.map +1 -0
- package/dist/routes/root/scripts/status.handlers.js +46 -92
- package/dist/routes/root/scripts/status.handlers.js.map +1 -1
- package/dist/routes/root/scripts/status.js +21 -8
- package/dist/routes/root/scripts/status.js.map +1 -1
- package/dist/routes/root/styles.d.ts +1 -0
- package/dist/routes/root/styles.d.ts.map +1 -0
- package/dist/routes/root/styles.js +7 -4
- package/dist/routes/root/styles.js.map +1 -1
- package/dist/routes/services.d.ts +13 -1
- package/dist/routes/services.d.ts.map +1 -0
- package/dist/routes/services.js +81 -68
- package/dist/routes/services.js.map +1 -1
- package/dist/routes/sse.d.ts +1 -0
- package/dist/routes/sse.d.ts.map +1 -0
- package/dist/routes/sse.js +1 -1
- package/dist/routes/sse.js.map +1 -1
- package/dist/routes/streams.d.ts +2 -1
- package/dist/routes/streams.d.ts.map +1 -0
- package/dist/routes/streams.js +6 -4
- package/dist/routes/streams.js.map +1 -1
- package/dist/routes/theme.d.ts +3 -2
- package/dist/routes/theme.d.ts.map +1 -0
- package/dist/routes/theme.js +6 -5
- package/dist/routes/theme.js.map +1 -1
- package/dist/routes/ui.d.ts +3 -1
- package/dist/routes/ui.d.ts.map +1 -0
- package/dist/routes/ui.js +16 -4
- package/dist/routes/ui.js.map +1 -1
- package/dist/routes/upgrade.d.ts +1 -0
- package/dist/routes/upgrade.d.ts.map +1 -0
- package/dist/routes/upgrade.js +6 -2
- package/dist/routes/upgrade.js.map +1 -1
- package/dist/service/commands.context.d.ts +1 -0
- package/dist/service/commands.context.d.ts.map +1 -0
- package/dist/service/commands.context.js +4 -3
- package/dist/service/commands.context.js.map +1 -1
- package/dist/service/commands.d.ts +1 -0
- package/dist/service/commands.d.ts.map +1 -0
- package/dist/service/commands.js +10 -13
- package/dist/service/commands.js.map +1 -1
- package/dist/service/generators.context.d.ts +1 -0
- package/dist/service/generators.context.d.ts.map +1 -0
- package/dist/service/generators.context.js +1 -1
- package/dist/service/generators.context.js.map +1 -1
- package/dist/service/generators.d.ts +4 -3
- package/dist/service/generators.d.ts.map +1 -0
- package/dist/service/generators.js +111 -31
- package/dist/service/generators.js.map +1 -1
- package/dist/service/index.d.ts +1 -0
- package/dist/service/index.d.ts.map +1 -0
- package/dist/streaming/captureLock.d.ts +44 -0
- package/dist/streaming/captureLock.d.ts.map +1 -0
- package/dist/streaming/captureLock.js +95 -0
- package/dist/streaming/captureLock.js.map +1 -0
- package/dist/streaming/captureSession.d.ts +31 -0
- package/dist/streaming/captureSession.d.ts.map +1 -0
- package/dist/streaming/captureSession.js +54 -0
- package/dist/streaming/captureSession.js.map +1 -0
- package/dist/streaming/clients.d.ts +1 -0
- package/dist/streaming/clients.d.ts.map +1 -0
- package/dist/streaming/codec.d.ts +1 -0
- package/dist/streaming/codec.d.ts.map +1 -0
- package/dist/streaming/fmp4Segmenter.d.ts +29 -2
- package/dist/streaming/fmp4Segmenter.d.ts.map +1 -0
- package/dist/streaming/fmp4Segmenter.js +79 -26
- package/dist/streaming/fmp4Segmenter.js.map +1 -1
- package/dist/streaming/hls.d.ts +18 -7
- package/dist/streaming/hls.d.ts.map +1 -0
- package/dist/streaming/hls.js +220 -120
- package/dist/streaming/hls.js.map +1 -1
- package/dist/streaming/hlsResume.d.ts +1 -0
- package/dist/streaming/hlsResume.d.ts.map +1 -0
- package/dist/streaming/hlsResume.js +1 -1
- package/dist/streaming/hlsResume.js.map +1 -1
- package/dist/streaming/hlsSegments.d.ts +59 -2
- package/dist/streaming/hlsSegments.d.ts.map +1 -0
- package/dist/streaming/hlsSegments.js +147 -17
- package/dist/streaming/hlsSegments.js.map +1 -1
- package/dist/streaming/lifecycle.d.ts +4 -1
- package/dist/streaming/lifecycle.d.ts.map +1 -0
- package/dist/streaming/lifecycle.js +65 -85
- package/dist/streaming/lifecycle.js.map +1 -1
- package/dist/streaming/monitor.d.ts +6 -4
- package/dist/streaming/monitor.d.ts.map +1 -0
- package/dist/streaming/monitor.js +343 -145
- package/dist/streaming/monitor.js.map +1 -1
- package/dist/streaming/mp4Parser.d.ts +5 -4
- package/dist/streaming/mp4Parser.d.ts.map +1 -0
- package/dist/streaming/mp4Parser.js +36 -13
- package/dist/streaming/mp4Parser.js.map +1 -1
- package/dist/streaming/mpegts.d.ts +16 -0
- package/dist/streaming/mpegts.d.ts.map +1 -0
- package/dist/streaming/mpegts.js +61 -17
- package/dist/streaming/mpegts.js.map +1 -1
- package/dist/streaming/playlistBuilder.d.ts +1 -0
- package/dist/streaming/playlistBuilder.d.ts.map +1 -0
- package/dist/streaming/preroll.d.ts +32 -5
- package/dist/streaming/preroll.d.ts.map +1 -0
- package/dist/streaming/preroll.js +70 -32
- package/dist/streaming/preroll.js.map +1 -1
- package/dist/streaming/pretune.d.ts +26 -1
- package/dist/streaming/pretune.d.ts.map +1 -0
- package/dist/streaming/pretune.js +22 -24
- package/dist/streaming/pretune.js.map +1 -1
- package/dist/streaming/pretuneTimers.d.ts +24 -0
- package/dist/streaming/pretuneTimers.d.ts.map +1 -0
- package/dist/streaming/pretuneTimers.js +56 -0
- package/dist/streaming/pretuneTimers.js.map +1 -0
- package/dist/streaming/recovery.d.ts +139 -5
- package/dist/streaming/recovery.d.ts.map +1 -0
- package/dist/streaming/recovery.js +160 -16
- package/dist/streaming/recovery.js.map +1 -1
- package/dist/streaming/registry.d.ts +27 -9
- package/dist/streaming/registry.d.ts.map +1 -0
- package/dist/streaming/registry.js +21 -3
- package/dist/streaming/registry.js.map +1 -1
- package/dist/streaming/setup.d.ts +157 -29
- package/dist/streaming/setup.d.ts.map +1 -0
- package/dist/streaming/setup.js +1034 -458
- package/dist/streaming/setup.js.map +1 -1
- package/dist/streaming/showInfo.d.ts +21 -1
- package/dist/streaming/showInfo.d.ts.map +1 -0
- package/dist/streaming/showInfo.js +31 -16
- package/dist/streaming/showInfo.js.map +1 -1
- package/dist/streaming/statusEmitter.d.ts +10 -10
- package/dist/streaming/statusEmitter.d.ts.map +1 -0
- package/dist/streaming/statusEmitter.js +5 -8
- package/dist/streaming/statusEmitter.js.map +1 -1
- package/dist/types/channels.d.ts +16 -4
- package/dist/types/channels.d.ts.map +1 -0
- package/dist/types/channels.js +4 -2
- package/dist/types/channels.js.map +1 -1
- package/dist/types/config.d.ts +16 -5
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/profiles.d.ts +6 -4
- package/dist/types/profiles.d.ts.map +1 -0
- package/dist/types/selection.d.ts +31 -3
- package/dist/types/selection.d.ts.map +1 -0
- package/dist/types/selection.js +4 -2
- package/dist/types/selection.js.map +1 -1
- package/dist/types/shared.d.ts +1 -0
- package/dist/types/shared.d.ts.map +1 -0
- package/dist/types/streaming.d.ts +8 -0
- package/dist/types/streaming.d.ts.map +1 -0
- package/dist/upgrade/commands.context.d.ts +1 -0
- package/dist/upgrade/commands.context.d.ts.map +1 -0
- package/dist/upgrade/commands.context.js +14 -10
- package/dist/upgrade/commands.context.js.map +1 -1
- package/dist/upgrade/commands.d.ts +8 -15
- package/dist/upgrade/commands.d.ts.map +1 -0
- package/dist/upgrade/commands.js +27 -28
- package/dist/upgrade/commands.js.map +1 -1
- package/dist/upgrade/detection.context.d.ts +1 -0
- package/dist/upgrade/detection.context.d.ts.map +1 -0
- package/dist/upgrade/detection.context.js +4 -1
- package/dist/upgrade/detection.context.js.map +1 -1
- package/dist/upgrade/detection.d.ts +9 -7
- package/dist/upgrade/detection.d.ts.map +1 -0
- package/dist/upgrade/detection.js +23 -54
- package/dist/upgrade/detection.js.map +1 -1
- package/dist/upgrade/index.d.ts +2 -0
- package/dist/upgrade/index.d.ts.map +1 -0
- package/dist/upgrade/index.js +1 -0
- package/dist/upgrade/index.js.map +1 -1
- package/dist/upgrade/lifecycle.context.d.ts +20 -0
- package/dist/upgrade/lifecycle.context.d.ts.map +1 -0
- package/dist/upgrade/lifecycle.context.js +47 -0
- package/dist/upgrade/lifecycle.context.js.map +1 -0
- package/dist/upgrade/lifecycle.d.ts +72 -0
- package/dist/upgrade/lifecycle.d.ts.map +1 -0
- package/dist/upgrade/lifecycle.js +175 -0
- package/dist/upgrade/lifecycle.js.map +1 -0
- package/dist/upgrade/pathHandle.d.ts +30 -0
- package/dist/upgrade/pathHandle.d.ts.map +1 -0
- package/dist/upgrade/pathHandle.js +102 -0
- package/dist/upgrade/pathHandle.js.map +1 -0
- package/dist/utils/bootSession.context.d.ts +16 -0
- package/dist/utils/bootSession.context.d.ts.map +1 -0
- package/dist/utils/bootSession.context.js +60 -0
- package/dist/utils/bootSession.context.js.map +1 -0
- package/dist/utils/bootSession.d.ts +17 -0
- package/dist/utils/bootSession.d.ts.map +1 -0
- package/dist/utils/bootSession.js +20 -0
- package/dist/utils/bootSession.js.map +1 -0
- package/dist/utils/chromeFetch.d.ts +1 -0
- package/dist/utils/chromeFetch.d.ts.map +1 -0
- package/dist/utils/cliOutput.d.ts +1 -0
- package/dist/utils/cliOutput.d.ts.map +1 -0
- package/dist/utils/clock.d.ts +5 -4
- package/dist/utils/clock.d.ts.map +1 -0
- package/dist/utils/clock.js +19 -16
- package/dist/utils/clock.js.map +1 -1
- package/dist/utils/debugFilter.d.ts +9 -1
- package/dist/utils/debugFilter.d.ts.map +1 -0
- package/dist/utils/debugFilter.js +60 -33
- package/dist/utils/debugFilter.js.map +1 -1
- package/dist/utils/delay.d.ts +48 -15
- package/dist/utils/delay.d.ts.map +1 -0
- package/dist/utils/delay.js +73 -20
- package/dist/utils/delay.js.map +1 -1
- package/dist/utils/errors.d.ts +32 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +45 -4
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/evaluate.d.ts +1 -0
- package/dist/utils/evaluate.d.ts.map +1 -0
- package/dist/utils/evaluate.js +29 -23
- package/dist/utils/evaluate.js.map +1 -1
- package/dist/utils/ffmpeg.context.d.ts +1 -0
- package/dist/utils/ffmpeg.context.d.ts.map +1 -0
- package/dist/utils/ffmpeg.context.js.map +1 -1
- package/dist/utils/ffmpeg.d.ts +29 -7
- package/dist/utils/ffmpeg.d.ts.map +1 -0
- package/dist/utils/ffmpeg.js +32 -14
- package/dist/utils/ffmpeg.js.map +1 -1
- package/dist/utils/fileLogger.d.ts +3 -1
- package/dist/utils/fileLogger.d.ts.map +1 -0
- package/dist/utils/fileLogger.js +64 -29
- package/dist/utils/fileLogger.js.map +1 -1
- package/dist/utils/format.d.ts +14 -1
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +19 -5
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/logEmitter.d.ts +1 -0
- package/dist/utils/logEmitter.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +1 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +10 -6
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/m3u.d.ts +3 -2
- package/dist/utils/m3u.d.ts.map +1 -0
- package/dist/utils/m3u.js +4 -3
- package/dist/utils/m3u.js.map +1 -1
- package/dist/utils/markup.d.ts +13 -1
- package/dist/utils/markup.d.ts.map +1 -0
- package/dist/utils/markup.js +28 -4
- package/dist/utils/markup.js.map +1 -1
- package/dist/utils/memo.d.ts +3 -2
- package/dist/utils/memo.d.ts.map +1 -0
- package/dist/utils/memo.js +3 -3
- package/dist/utils/morganStream.d.ts +1 -0
- package/dist/utils/morganStream.d.ts.map +1 -0
- package/dist/utils/network.d.ts +1 -0
- package/dist/utils/network.d.ts.map +1 -0
- package/dist/utils/network.js +2 -2
- package/dist/utils/pid.d.ts +3 -25
- package/dist/utils/pid.d.ts.map +1 -0
- package/dist/utils/pid.js +10 -49
- package/dist/utils/pid.js.map +1 -1
- package/dist/utils/platform.d.ts +3 -1
- package/dist/utils/platform.d.ts.map +1 -0
- package/dist/utils/platform.js +2 -1
- package/dist/utils/platform.js.map +1 -1
- package/dist/utils/processInspector.context.d.ts +8 -0
- package/dist/utils/processInspector.context.d.ts.map +1 -0
- package/dist/utils/processInspector.context.js +106 -0
- package/dist/utils/processInspector.context.js.map +1 -0
- package/dist/utils/processInspector.d.ts +55 -0
- package/dist/utils/processInspector.d.ts.map +1 -0
- package/dist/utils/processInspector.js +127 -0
- package/dist/utils/processInspector.js.map +1 -0
- package/dist/utils/retry.d.ts +25 -2
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +33 -6
- package/dist/utils/retry.js.map +1 -1
- package/dist/utils/runtimeIdentity.context.d.ts +7 -0
- package/dist/utils/runtimeIdentity.context.d.ts.map +1 -0
- package/dist/utils/runtimeIdentity.context.js +43 -0
- package/dist/utils/runtimeIdentity.context.js.map +1 -0
- package/dist/utils/runtimeIdentity.d.ts +98 -0
- package/dist/utils/runtimeIdentity.d.ts.map +1 -0
- package/dist/utils/runtimeIdentity.js +181 -0
- package/dist/utils/runtimeIdentity.js.map +1 -0
- package/dist/utils/sanitize.d.ts +1 -0
- package/dist/utils/sanitize.d.ts.map +1 -0
- package/dist/utils/streamContext.d.ts +2 -1
- package/dist/utils/streamContext.d.ts.map +1 -0
- package/dist/utils/streamContext.js +1 -1
- package/dist/utils/timing.d.ts +2 -1
- package/dist/utils/timing.d.ts.map +1 -0
- package/dist/utils/timing.js +0 -5
- package/dist/utils/timing.js.map +1 -1
- package/dist/utils/version.d.ts +1 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +47 -13
- package/dist/utils/version.js.map +1 -1
- package/package.json +26 -20
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
*
|
|
3
3
|
* channels.ts: Client-side JavaScript generator for the PrismCast channels subtab.
|
|
4
4
|
*/
|
|
5
|
+
import { ACTIONS } from "../../clientActions.js";
|
|
6
|
+
/**
|
|
7
|
+
* Generates the channels subtab script block containing the service profile wizard, the browse channels wizard, the tag manager, and the setup wizard, plus the
|
|
8
|
+
* data-click-action registrations that wire server-rendered buttons to these handlers.
|
|
9
|
+
* @returns HTML script block with channels subtab functions.
|
|
10
|
+
*/
|
|
5
11
|
export function generateChannelsSubtabScript() {
|
|
6
12
|
return [
|
|
7
13
|
"<script>",
|
|
@@ -57,17 +63,26 @@ export function generateChannelsSubtabScript() {
|
|
|
57
63
|
" else if(ef.type === 'boolean' && editCs[ef.id]) { strategyFields[ef.id] = true; }",
|
|
58
64
|
" }",
|
|
59
65
|
" }",
|
|
66
|
+
// Rehydrate the rendered profile fields from the registry: boolean flags into flags, text selectors into fieldValues. This is truthy-only capture, so an
|
|
67
|
+
// explicit-false or explicit-null value of a RENDERED field is not represented (a known, unchanged limitation); every field the wizard does not render survives
|
|
68
|
+
// via baseProfileFields below.
|
|
60
69
|
" const flags = {};",
|
|
61
|
-
" const
|
|
62
|
-
" for(const wf of
|
|
70
|
+
" const fieldValues = {};",
|
|
71
|
+
" for(const wf of window.__wizardFields) {",
|
|
72
|
+
" if(wf.type === 'boolean') { if(p[wf.id]) flags[wf.id] = true; }",
|
|
73
|
+
" else if(p[wf.id]) { fieldValues[wf.id] = p[wf.id]; }",
|
|
74
|
+
" }",
|
|
75
|
+
// Each domain row keeps its full raw config so unrendered domain-level fields (videoTimeout, loginUrl, maxContinuousPlayback, dismissSelector) ride through a
|
|
76
|
+
// resave; service and serviceTag drive the rendered inputs.
|
|
63
77
|
" const domains = (match.domains && match.domains.length > 0) ?",
|
|
64
|
-
" match.domains.map((d) => ({ domain: d.domain, service: d.service || '', serviceTag: d.serviceTag || '' })) :",
|
|
65
|
-
" [{ domain: '', service: '', serviceTag: '' }];",
|
|
78
|
+
" match.domains.map((d) => ({ config: d.config || {}, domain: d.domain, service: d.service || '', serviceTag: d.serviceTag || '' })) :",
|
|
79
|
+
" [{ config: {}, domain: '', service: '', serviceTag: '' }];",
|
|
80
|
+
// Keep the full fetched profile as baseProfileFields. saveProfile starts from a copy of it and deletes only the rendered vocabulary, so unrendered profile-level
|
|
81
|
+
// fields (channelSelector, clickSelector, fullscreenKey, fullscreenSelector, staticCapture) survive an edit-resave unchanged.
|
|
66
82
|
" profileWizard.state = {",
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
" hideSelector: p.hideSelector || '', domains: domains, description: p.description || ''",
|
|
83
|
+
" baseProfile: p.extends || '', baseProfileFields: p, description: p.description || '',",
|
|
84
|
+
" domains: domains, editKey: key, editMode: true, fieldValues: fieldValues, flags: flags,",
|
|
85
|
+
" profileName: key, strategy: strat, strategyFields: strategyFields",
|
|
71
86
|
" };",
|
|
72
87
|
" profileWizard.open({ highestStep: 5, title: 'Edit Service Profile' });",
|
|
73
88
|
" } catch(e) { console.error('Profile data failed to load.', e); showToast('Failed to load profile data.', 'error'); }",
|
|
@@ -91,7 +106,7 @@ export function generateChannelsSubtabScript() {
|
|
|
91
106
|
" const channelCount = data.channels ? Object.keys(data.channels).length : 0;",
|
|
92
107
|
" let html = '<table class=\"import-summary-table\">';",
|
|
93
108
|
" html += '<tr><td class=\"import-summary-label\">Pack name</td>';",
|
|
94
|
-
" html += '<td>' +
|
|
109
|
+
" html += '<td>' + escapeHtml(data.name || 'Unnamed') + '</td></tr>';",
|
|
95
110
|
" html += '<tr><td class=\"import-summary-label\">Profiles</td>';",
|
|
96
111
|
" html += '<td>' + plural(profileCount, 'profile') + '</td></tr>';",
|
|
97
112
|
" html += '<tr><td class=\"import-summary-label\">Domains</td>';",
|
|
@@ -166,13 +181,13 @@ export function generateChannelsSubtabScript() {
|
|
|
166
181
|
" if(dom.service) { serviceName = dom.service; break; }",
|
|
167
182
|
" }",
|
|
168
183
|
" const meta = [];",
|
|
169
|
-
" if(serviceName) meta.push(
|
|
184
|
+
" if(serviceName) meta.push(escapeHtml(serviceName));",
|
|
170
185
|
" meta.push(plural(domainCount, 'domain'));",
|
|
171
186
|
" meta.push(plural(channelCount, 'channel'));",
|
|
172
187
|
" html += '<label class=\"export-profile-item\">';",
|
|
173
|
-
" html += '<input type=\"checkbox\" class=\"export-profile-cb\" value=\"' +
|
|
188
|
+
" html += '<input type=\"checkbox\" class=\"export-profile-cb\" value=\"' + escapeHtml(p.key) + '\" checked>';",
|
|
174
189
|
" html += '<div class=\"export-profile-info\">';",
|
|
175
|
-
" html += '<div class=\"export-profile-name\">' +
|
|
190
|
+
" html += '<div class=\"export-profile-name\">' + escapeHtml(p.key) + '</div>';",
|
|
176
191
|
" html += '<div class=\"export-profile-meta\">' + meta.join(' · ') + '</div>';",
|
|
177
192
|
" html += '</div></label>';",
|
|
178
193
|
" }",
|
|
@@ -207,12 +222,8 @@ export function generateChannelsSubtabScript() {
|
|
|
207
222
|
" function autoServiceTag(name) {",
|
|
208
223
|
" return name.toLowerCase().replace(/[^a-z0-9]/g, '');",
|
|
209
224
|
" }",
|
|
210
|
-
//
|
|
211
|
-
|
|
212
|
-
" const d = document.createElement('div');",
|
|
213
|
-
" d.appendChild(document.createTextNode(str || ''));",
|
|
214
|
-
" return d.innerHTML;",
|
|
215
|
-
" }",
|
|
225
|
+
// The escapeHtml used throughout this script is the shared client-escape SSOT installed on window by the shared utilities script, which the page emits before
|
|
226
|
+
// this one; there is no local copy here.
|
|
216
227
|
// Pluralization helper for UI text: returns "1 domain", "2 domains", etc.
|
|
217
228
|
" function plural(n, word) {",
|
|
218
229
|
" return n + ' ' + word + (n === 1 ? '' : 's');",
|
|
@@ -244,8 +255,7 @@ export function generateChannelsSubtabScript() {
|
|
|
244
255
|
" html += '<div class=\"field-group\">';",
|
|
245
256
|
" html += '<label class=\"wizard-label\" for=\"wizard-profile-name\">Profile Name</label>';",
|
|
246
257
|
" const nameReadonly = s.editMode ? ' readonly style=\"opacity: 0.6; cursor: not-allowed;\"' : '';",
|
|
247
|
-
" html += '<input type=\"text\" id=\"wizard-profile-name\" value=\"' + s.profileName
|
|
248
|
-
" '\" placeholder=\"e.g., myService\"' + nameReadonly + '>';",
|
|
258
|
+
" html += '<input type=\"text\" id=\"wizard-profile-name\" value=\"' + escapeHtml(s.profileName) + '\" placeholder=\"e.g., myService\"' + nameReadonly + '>';",
|
|
249
259
|
" html += '<div class=\"field-hint\">' + (s.editMode ? 'Profile name cannot be changed.' :",
|
|
250
260
|
" 'Unique identifier. Letters, numbers, and hyphens only.') + '</div>';",
|
|
251
261
|
" html += '</div>';",
|
|
@@ -267,14 +277,14 @@ export function generateChannelsSubtabScript() {
|
|
|
267
277
|
" if(items.length === 0) continue;",
|
|
268
278
|
" html += '<div class=\"wizard-profile-category\">';",
|
|
269
279
|
" html += '<h4>' + cat.title + '</h4>';",
|
|
270
|
-
" if(cat.desc) html += '<div class=\"wizard-category-desc\">' +
|
|
280
|
+
" if(cat.desc) html += '<div class=\"wizard-category-desc\">' + escapeHtml(cat.desc) + '</div>';",
|
|
271
281
|
" for(const p of items) {",
|
|
272
282
|
" const checked = (s.baseProfile === p.name) ? ' checked' : '';",
|
|
273
283
|
" html += '<label class=\"wizard-profile-option\">';",
|
|
274
284
|
" html += '<input type=\"radio\" name=\"baseProfile\" value=\"' + p.name + '\"' + checked + '>';",
|
|
275
|
-
" const sumTag = p.summary ? ' <span class=\"profile-option-summary\">(' +
|
|
276
|
-
" html += '<div><div class=\"profile-option-name\">' +
|
|
277
|
-
" html += '<div class=\"profile-option-desc\">' +
|
|
285
|
+
" const sumTag = p.summary ? ' <span class=\"profile-option-summary\">(' + escapeHtml(p.summary) + ')</span>' : '';",
|
|
286
|
+
" html += '<div><div class=\"profile-option-name\">' + escapeHtml(p.name) + sumTag + '</div>';",
|
|
287
|
+
" html += '<div class=\"profile-option-desc\">' + escapeHtml(p.description) + '</div></div>';",
|
|
278
288
|
" html += '</label>';",
|
|
279
289
|
" }",
|
|
280
290
|
" html += '</div>';",
|
|
@@ -297,12 +307,12 @@ export function generateChannelsSubtabScript() {
|
|
|
297
307
|
" html += '<hr style=\"border: none; border-top: 1px solid var(--border-default); margin: 16px 0;\">';",
|
|
298
308
|
" for(const f of currentStrat.fields) {",
|
|
299
309
|
" if(f.type === 'text') {",
|
|
300
|
-
" const val = (s.strategyFields[f.id] || '')
|
|
310
|
+
" const val = escapeHtml(s.strategyFields[f.id] || '');",
|
|
301
311
|
" const optLabel = f.required ? '' : ' <span style=\"color: var(--text-muted);\">(optional)</span>';",
|
|
302
312
|
" html += '<div class=\"field-group\">';",
|
|
303
313
|
" html += '<label class=\"wizard-label\" for=\"wizard-sf-' + f.id + '\">' + f.label + optLabel + '</label>';",
|
|
304
314
|
" html += '<input type=\"text\" id=\"wizard-sf-' + f.id + '\" data-field=\"' + f.id + '\" value=\"' + val + '\"';",
|
|
305
|
-
" if(f.placeholder) html += ' placeholder=\"' + f.placeholder
|
|
315
|
+
" if(f.placeholder) html += ' placeholder=\"' + escapeHtml(f.placeholder) + '\"';",
|
|
306
316
|
" html += '>';",
|
|
307
317
|
" if(f.hint) html += '<div class=\"field-hint\">' + f.hint + '</div>';",
|
|
308
318
|
" html += '</div>';",
|
|
@@ -317,13 +327,15 @@ export function generateChannelsSubtabScript() {
|
|
|
317
327
|
" }",
|
|
318
328
|
" }",
|
|
319
329
|
" }",
|
|
320
|
-
// Step 3:
|
|
330
|
+
// Step 3: Profile Fields. Both the boolean flags and the text selectors are rendered from the server-side registry (window.__wizardFields), branching on type:
|
|
331
|
+
// booleans are checkboxes described by their description, text fields are inputs described by their hint.
|
|
321
332
|
" if(step === 3) {",
|
|
322
333
|
" html += '<label class=\"wizard-label\">Profile Flags</label>';",
|
|
323
334
|
" html += '<div class=\"field-hint\" style=\"margin-bottom: 12px;\">These override the base profile. ' +",
|
|
324
335
|
" 'Only change what differs from ' + s.baseProfile + '.</div>';",
|
|
325
|
-
" const
|
|
326
|
-
" for(const f of
|
|
336
|
+
" const wizFields = window.__wizardFields;",
|
|
337
|
+
" for(const f of wizFields) {",
|
|
338
|
+
" if(f.type !== 'boolean') continue;",
|
|
327
339
|
" const checked = s.flags[f.id] ? ' checked' : '';",
|
|
328
340
|
" html += '<label class=\"wizard-flag\">';",
|
|
329
341
|
" html += '<input type=\"checkbox\" name=\"flag-' + f.id + '\"' + checked + '>';",
|
|
@@ -331,12 +343,17 @@ export function generateChannelsSubtabScript() {
|
|
|
331
343
|
" html += '<div class=\"wizard-flag-desc\">' + f.description + '</div></div>';",
|
|
332
344
|
" html += '</label>';",
|
|
333
345
|
" }",
|
|
334
|
-
"
|
|
335
|
-
"
|
|
336
|
-
"
|
|
337
|
-
" '\"
|
|
338
|
-
"
|
|
339
|
-
"
|
|
346
|
+
" for(const f of wizFields) {",
|
|
347
|
+
" if(f.type !== 'text') continue;",
|
|
348
|
+
" const fieldVal = escapeHtml(s.fieldValues[f.id] || '');",
|
|
349
|
+
" html += '<div class=\"field-group\" style=\"margin-top: 12px;\">';",
|
|
350
|
+
" html += '<label class=\"wizard-label\" for=\"wizard-field-' + f.id + '\">' + f.label +",
|
|
351
|
+
" ' <span style=\"color: var(--text-muted);\">(optional)</span></label>';",
|
|
352
|
+
" html += '<input type=\"text\" class=\"wizard-field-input\" data-field-id=\"' + f.id + '\" id=\"wizard-field-' + f.id + '\" value=\"' + fieldVal +",
|
|
353
|
+
" '\" placeholder=\"' + escapeHtml(f.placeholder || '') + '\">';",
|
|
354
|
+
" html += '<div class=\"field-hint\">' + (f.hint || '') + '</div>';",
|
|
355
|
+
" html += '</div>';",
|
|
356
|
+
" }",
|
|
340
357
|
" }",
|
|
341
358
|
// Step 4: Domain Mapping.
|
|
342
359
|
" if(step === 4) {",
|
|
@@ -346,16 +363,15 @@ export function generateChannelsSubtabScript() {
|
|
|
346
363
|
" html += '<div class=\"wizard-domain-row\" data-domain-idx=\"' + di + '\">';",
|
|
347
364
|
" html += '<div class=\"field-group\">';",
|
|
348
365
|
" html += '<label class=\"wizard-label\">Domain</label>';",
|
|
349
|
-
" html += '<input type=\"text\" class=\"domain-input\" value=\"' + d.domain
|
|
366
|
+
" html += '<input type=\"text\" class=\"domain-input\" value=\"' + escapeHtml(d.domain) + '\" placeholder=\"e.g., watch.sling.com\">';",
|
|
350
367
|
" html += '</div>';",
|
|
351
368
|
" html += '<div class=\"field-group\">';",
|
|
352
369
|
" html += '<label class=\"wizard-label\">Service Name</label>';",
|
|
353
|
-
" html += '<input type=\"text\" class=\"provider-input\" value=\"' + d.service
|
|
370
|
+
" html += '<input type=\"text\" class=\"provider-input\" value=\"' + escapeHtml(d.service) + '\" placeholder=\"e.g., Sling TV\">';",
|
|
354
371
|
" html += '</div>';",
|
|
355
372
|
" html += '<div class=\"field-group\">';",
|
|
356
373
|
" html += '<label class=\"wizard-label\">Service Tag <span style=\"color: var(--text-muted);\">(auto-filled)</span></label>';",
|
|
357
|
-
" html += '<input type=\"text\" class=\"provider-tag-input\" value=\"' + d.serviceTag
|
|
358
|
-
" '\" placeholder=\"auto-generated\">';",
|
|
374
|
+
" html += '<input type=\"text\" class=\"provider-tag-input\" value=\"' + escapeHtml(d.serviceTag) + '\" placeholder=\"auto-generated\">';",
|
|
359
375
|
" html += '<div class=\"field-hint\">Identifier for the service filter. Auto-generated from service name.</div>';",
|
|
360
376
|
" html += '</div>';",
|
|
361
377
|
" html += '</div>';",
|
|
@@ -366,12 +382,12 @@ export function generateChannelsSubtabScript() {
|
|
|
366
382
|
" if(step === 5) {",
|
|
367
383
|
" html += '<label class=\"wizard-label\">Review</label>';",
|
|
368
384
|
" html += '<table class=\"wizard-review-table\">';",
|
|
369
|
-
" html += '<tr><td>Profile</td><td>' +
|
|
370
|
-
" html += '<tr><td>Extends</td><td>' +
|
|
371
|
-
" html += '<tr><td>Strategy</td><td>' +
|
|
372
|
-
" const domainList = s.domains.filter((d) => d.domain).map((d) =>
|
|
385
|
+
" html += '<tr><td>Profile</td><td>' + escapeHtml(s.profileName) + '</td></tr>';",
|
|
386
|
+
" html += '<tr><td>Extends</td><td>' + escapeHtml(s.baseProfile) + '</td></tr>';",
|
|
387
|
+
" html += '<tr><td>Strategy</td><td>' + escapeHtml(s.strategy) + '</td></tr>';",
|
|
388
|
+
" const domainList = s.domains.filter((d) => d.domain).map((d) => escapeHtml(d.domain)).join(', ');",
|
|
373
389
|
" html += '<tr><td>Domain(s)</td><td>' + (domainList || 'none') + '</td></tr>';",
|
|
374
|
-
" const serviceList = s.domains.filter((d) => d.service).map((d) =>
|
|
390
|
+
" const serviceList = s.domains.filter((d) => d.service).map((d) => escapeHtml(d.service)).join(', ');",
|
|
375
391
|
" html += '<tr><td>Service</td><td>' + (serviceList || 'none') + '</td></tr>';",
|
|
376
392
|
" if(s.strategy !== 'none') {",
|
|
377
393
|
" const reviewStrat = window.__wizardStrategies.find((st) => st.id === s.strategy);",
|
|
@@ -379,22 +395,26 @@ export function generateChannelsSubtabScript() {
|
|
|
379
395
|
" for(const rf of reviewStrat.fields) {",
|
|
380
396
|
" const rv = s.strategyFields[rf.id];",
|
|
381
397
|
" if(rf.type === 'text' && rv) {",
|
|
382
|
-
" html += '<tr><td>' +
|
|
398
|
+
" html += '<tr><td>' + escapeHtml(rf.label.replace(/ \\(CSS\\)/, '')) + '</td><td><code>' + escapeHtml(rv) + '</code></td></tr>';",
|
|
383
399
|
" } else if(rf.type === 'boolean' && rv) {",
|
|
384
|
-
" html += '<tr><td>' +
|
|
400
|
+
" html += '<tr><td>' + escapeHtml(rf.label) + '</td><td>Yes</td></tr>';",
|
|
385
401
|
" }",
|
|
386
402
|
" }",
|
|
387
403
|
" }",
|
|
388
404
|
" }",
|
|
389
405
|
" const flagNames = Object.keys(s.flags).filter((k) => s.flags[k]);",
|
|
390
406
|
" if(flagNames.length > 0) {",
|
|
391
|
-
" html += '<tr><td>Flags</td><td>' +
|
|
407
|
+
" html += '<tr><td>Flags</td><td>' + escapeHtml(flagNames.join(', ')) + '</td></tr>';",
|
|
408
|
+
" }",
|
|
409
|
+
" for(const rtf of window.__wizardFields) {",
|
|
410
|
+
" if(rtf.type !== 'text') continue;",
|
|
411
|
+
" const rtv = s.fieldValues[rtf.id];",
|
|
412
|
+
" if(rtv) html += '<tr><td>' + escapeHtml(rtf.label.replace(/ \\(CSS\\)/, '')) + '</td><td><code>' + escapeHtml(rtv) + '</code></td></tr>';",
|
|
392
413
|
" }",
|
|
393
|
-
" if(s.hideSelector) html += '<tr><td>Hide Selector</td><td><code>' + esc(s.hideSelector) + '</code></td></tr>';",
|
|
394
414
|
" html += '</table>';",
|
|
395
415
|
" html += '<div class=\"field-group\" style=\"margin-top: 16px;\">';",
|
|
396
416
|
" html += '<label class=\"wizard-label\" for=\"wizard-description\">Description <span style=\"color: var(--text-muted);\">(optional)</span></label>';",
|
|
397
|
-
" html += '<textarea id=\"wizard-description\" placeholder=\"Optional description for documentation.\">' +
|
|
417
|
+
" html += '<textarea id=\"wizard-description\" placeholder=\"Optional description for documentation.\">' + escapeHtml(s.description) + '</textarea>';",
|
|
398
418
|
" html += '</div>';",
|
|
399
419
|
" }",
|
|
400
420
|
" content.innerHTML = html;",
|
|
@@ -428,7 +448,7 @@ export function generateChannelsSubtabScript() {
|
|
|
428
448
|
" else { delete s.strategyFields[this.getAttribute('data-field')]; }",
|
|
429
449
|
" });",
|
|
430
450
|
" }",
|
|
431
|
-
// Step 3: flag checkboxes and
|
|
451
|
+
// Step 3: flag checkboxes and text selector inputs. Text fields bind by their data-field-id into fieldValues.
|
|
432
452
|
" const flagCbs = document.querySelectorAll('input[name^=\"flag-\"]');",
|
|
433
453
|
" for(const flagCb of flagCbs) {",
|
|
434
454
|
" flagCb.addEventListener('change', function() {",
|
|
@@ -436,9 +456,11 @@ export function generateChannelsSubtabScript() {
|
|
|
436
456
|
" if(this.checked) { s.flags[flagName] = true; } else { delete s.flags[flagName]; }",
|
|
437
457
|
" });",
|
|
438
458
|
" }",
|
|
439
|
-
" const
|
|
440
|
-
"
|
|
441
|
-
|
|
459
|
+
" const fieldInputs = document.querySelectorAll('.wizard-field-input[data-field-id]');",
|
|
460
|
+
" for(const fieldInput of fieldInputs) {",
|
|
461
|
+
" fieldInput.addEventListener('input', function() { s.fieldValues[this.getAttribute('data-field-id')] = this.value; });",
|
|
462
|
+
" }",
|
|
463
|
+
// Step 4: add-domain button and domain inputs with auto-fill for service tag. Per-iteration const bindings from for...of.entries() capture the correct index
|
|
442
464
|
// in each closure - no IIFE wrapper needed.
|
|
443
465
|
" const addDomainBtn = document.getElementById('wizard-add-domain-btn');",
|
|
444
466
|
" if(addDomainBtn) addDomainBtn.addEventListener('click', addWizardDomain);",
|
|
@@ -490,24 +512,38 @@ export function generateChannelsSubtabScript() {
|
|
|
490
512
|
// Open the profile builder wizard and reset state for a new profile.
|
|
491
513
|
" window.openWizard = () => {",
|
|
492
514
|
" profileWizard.state = {",
|
|
493
|
-
"
|
|
494
|
-
"
|
|
495
|
-
"
|
|
515
|
+
" baseProfile: '', baseProfileFields: {}, description: '',",
|
|
516
|
+
" domains: [{ config: {}, domain: '', service: '', serviceTag: '' }], editKey: null, editMode: false,",
|
|
517
|
+
" fieldValues: {}, flags: {}, profileName: '', strategy: 'none', strategyFields: {}",
|
|
496
518
|
" };",
|
|
497
519
|
" profileWizard.open({ title: 'New Service Profile' });",
|
|
498
520
|
" };",
|
|
499
521
|
// Add another domain row to step 4 and re-render.
|
|
500
522
|
" function addWizardDomain() {",
|
|
501
|
-
" profileWizard.state.domains.push({ domain: '', service: '', serviceTag: '' });",
|
|
523
|
+
" profileWizard.state.domains.push({ config: {}, domain: '', service: '', serviceTag: '' });",
|
|
502
524
|
" renderProfileStep(profileWizard.getStep());",
|
|
503
525
|
" }",
|
|
504
|
-
// Save the profile to the server.
|
|
526
|
+
// Save the profile to the server. Concurrent edits of the same profile resolve last-save-wins: the rebuild starts from the snapshot fetched when the wizard opened,
|
|
527
|
+
// matching the server's whole-replace semantics. The profile is a copy of the full fetched profile (empty for a new one) with only the wizard's rendered vocabulary
|
|
528
|
+
// deleted and
|
|
529
|
+
// re-applied, so every field the wizard does not render round-trips unchanged while a cleared rendered field is a real deletion. The server's whole-replace
|
|
530
|
+
// semantics are unchanged; a field outside the SiteProfile allowlist that rode through here surfaces as an explicit validation error, which is the honest outcome.
|
|
505
531
|
" window.saveProfile = async (andTest) => {",
|
|
506
532
|
" const s = profileWizard.state;",
|
|
507
|
-
|
|
533
|
+
// The wizard's rendered vocabulary: every field id it renders plus the structural keys it owns. Deleting these from the base copy is what makes a cleared field a
|
|
534
|
+
// deletion; everything else in the copy is preserved verbatim.
|
|
535
|
+
" const vocabulary = window.__wizardFields.map((f) => f.id).concat(['extends', 'description', 'channelSelection']);",
|
|
536
|
+
" const profile = Object.assign({}, s.baseProfileFields || {});",
|
|
537
|
+
" for(const vk of vocabulary) { delete profile[vk]; }",
|
|
538
|
+
" profile.extends = s.baseProfile;",
|
|
539
|
+
// Rebuild channelSelection rather than dropping it: preserve the base's unrendered sub-fields (listSelector, scrollSelector, scrollTarget) by starting from a copy
|
|
540
|
+
// and removing only the CHOSEN strategy's rendered field ids, so a strategy switch cannot leave stale rendered values behind. When the strategy is 'none' no
|
|
541
|
+
// channelSelection key is written at all - the sub-fields configure a strategy the user just removed.
|
|
508
542
|
" if(s.strategy !== 'none') {",
|
|
509
|
-
" const cs = { strategy: s.strategy };",
|
|
510
543
|
" const saveStrat = window.__wizardStrategies.find((st) => st.id === s.strategy);",
|
|
544
|
+
" const cs = Object.assign({}, (s.baseProfileFields && s.baseProfileFields.channelSelection) || {});",
|
|
545
|
+
" if(saveStrat) { for(const rf of saveStrat.fields) { delete cs[rf.id]; } }",
|
|
546
|
+
" cs.strategy = s.strategy;",
|
|
511
547
|
" if(saveStrat) {",
|
|
512
548
|
" for(const sf of saveStrat.fields) {",
|
|
513
549
|
" const sfVal = s.strategyFields[sf.id];",
|
|
@@ -517,16 +553,23 @@ export function generateChannelsSubtabScript() {
|
|
|
517
553
|
" }",
|
|
518
554
|
" profile.channelSelection = cs;",
|
|
519
555
|
" }",
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
"
|
|
556
|
+
// Re-apply the rendered profile fields: boolean flags that are set, text selectors that are non-empty. A cleared text field or an unchecked flag simply is not
|
|
557
|
+
// re-added, which - because the vocabulary was deleted above - deletes it from the round-tripped profile.
|
|
558
|
+
" for(const f of window.__wizardFields) {",
|
|
559
|
+
" if(f.type === 'boolean') { if(s.flags[f.id]) profile[f.id] = true; }",
|
|
560
|
+
" else { const tv = (s.fieldValues[f.id] || '').trim(); if(tv) profile[f.id] = tv; }",
|
|
561
|
+
" }",
|
|
523
562
|
" if(s.description) profile.description = s.description;",
|
|
563
|
+
// Each domain entry preserves its full raw config (unrendered fields ride through), then re-applies the profile key and the rendered service/serviceTag - deleting
|
|
564
|
+
// them when the inputs are cleared. A row whose domain string was edited carries its config to the new domain key (rename semantics).
|
|
524
565
|
" const domains = {};",
|
|
525
566
|
" for(const d of s.domains) {",
|
|
526
567
|
" if(d.domain.trim()) {",
|
|
527
|
-
"
|
|
528
|
-
"
|
|
529
|
-
" if(d.
|
|
568
|
+
" const entry = Object.assign({}, d.config || {});",
|
|
569
|
+
" entry.profile = s.profileName;",
|
|
570
|
+
" if(d.service.trim()) entry.service = d.service.trim(); else delete entry.service;",
|
|
571
|
+
" if(d.serviceTag.trim()) entry.serviceTag = d.serviceTag.trim(); else delete entry.serviceTag;",
|
|
572
|
+
" domains[d.domain.trim()] = entry;",
|
|
530
573
|
" }",
|
|
531
574
|
" }",
|
|
532
575
|
" const body = { domains: domains, key: s.profileName, profile: profile };",
|
|
@@ -559,7 +602,8 @@ export function generateChannelsSubtabScript() {
|
|
|
559
602
|
" testSelectors = {};",
|
|
560
603
|
" if(s.strategy !== 'none' && s.strategyFields.matchSelector) testSelectors.matchSelector = s.strategyFields.matchSelector;",
|
|
561
604
|
" if(s.strategyFields.playSelector) testSelectors.playSelector = s.strategyFields.playSelector;",
|
|
562
|
-
" if(s.hideSelector) testSelectors.hideSelector = s.hideSelector;",
|
|
605
|
+
" if(s.fieldValues.hideSelector) testSelectors.hideSelector = s.fieldValues.hideSelector;",
|
|
606
|
+
" if(s.fieldValues.dismissSelector) testSelectors.dismissSelector = s.fieldValues.dismissSelector;",
|
|
563
607
|
" const testUrl = url.includes('://') ? url : 'https://' + url;",
|
|
564
608
|
" try {",
|
|
565
609
|
" const res = await fetch('/config/profiles/test', {",
|
|
@@ -600,7 +644,7 @@ export function generateChannelsSubtabScript() {
|
|
|
600
644
|
" const r = data.results[name];",
|
|
601
645
|
" const color = r.valid && r.count > 0 ? 'var(--status-success-text)' : 'var(--status-error-text)';",
|
|
602
646
|
" const text = !r.valid ? 'Invalid selector' : r.count + ' element(s)';",
|
|
603
|
-
" html += '<tr><td style=\"padding: 4px 8px;\">' +
|
|
647
|
+
" html += '<tr><td style=\"padding: 4px 8px;\">' + escapeHtml(name) + '</td>';",
|
|
604
648
|
" html += '<td style=\"padding: 4px 8px; color: ' + color + ';\">' + text + '</td></tr>';",
|
|
605
649
|
" }",
|
|
606
650
|
" html += '</table>';",
|
|
@@ -634,7 +678,7 @@ export function generateChannelsSubtabScript() {
|
|
|
634
678
|
" const gEl = document.getElementById('browse-guide-urls-data');",
|
|
635
679
|
" if(gEl) browseGuideUrls = JSON.parse(gEl.textContent || '{}');",
|
|
636
680
|
" } catch(e) { console.warn('Embedded browse services data failed to parse.', e); }",
|
|
637
|
-
// Browse Channels wizard.
|
|
681
|
+
// Browse Channels wizard. Steps: Service (picker grid) and Channels (discovery + channel list). Uses the shared wizard controller for step navigation
|
|
638
682
|
// and indicator updates. The state object tracks the selected service slug and label, and the filtered service list for the current session.
|
|
639
683
|
" const browseWizard = createWizardController({",
|
|
640
684
|
" contentId: 'browse-content',",
|
|
@@ -692,8 +736,9 @@ export function generateChannelsSubtabScript() {
|
|
|
692
736
|
" let html = '<p class=\"wizard-hint\">Select a service to see its available channels.</p>';",
|
|
693
737
|
" html += '<div class=\"wizard-provider-grid\">';",
|
|
694
738
|
" for(const p of available) {",
|
|
695
|
-
" html += '<div class=\"wizard-provider-card\" data-slug=\"' +
|
|
696
|
-
|
|
739
|
+
" html += '<div class=\"wizard-provider-card\" data-slug=\"' + escapeHtml(p.slug) + '\" data-label=\"' + escapeHtml(p.label) + '\">';",
|
|
740
|
+
// serviceIconHtml escapes its name argument internally through the shared escapeHtml SSOT, so the label is passed raw here; escaping it again would double-encode.
|
|
741
|
+
" html += serviceIconHtml(p.domain, p.label, 'provider-icon', 'provider-icon-text', 'both', p.iconUrl || '');",
|
|
697
742
|
" html += '</div>';",
|
|
698
743
|
" }",
|
|
699
744
|
" html += '</div>';",
|
|
@@ -711,7 +756,7 @@ export function generateChannelsSubtabScript() {
|
|
|
711
756
|
" const slug = browseWizard.state.slug;",
|
|
712
757
|
" const label = browseWizard.state.label;",
|
|
713
758
|
// Show a spinner while fetching channels.
|
|
714
|
-
" content.innerHTML = '<div class=\"wizard-spinner\">Discovering channels from ' +
|
|
759
|
+
" content.innerHTML = '<div class=\"wizard-spinner\">Discovering channels from ' + escapeHtml(label) + '...</div>';",
|
|
715
760
|
// Fetch discovered channels from the service endpoint.
|
|
716
761
|
" (async () => {",
|
|
717
762
|
" try {",
|
|
@@ -723,18 +768,19 @@ export function generateChannelsSubtabScript() {
|
|
|
723
768
|
" } catch(err) {",
|
|
724
769
|
" if(browseWizard.state.slug !== slug) return;",
|
|
725
770
|
" content.innerHTML = '<div class=\"wizard-empty\"><div class=\"wizard-empty-title\">Could not discover channels.</div>' +",
|
|
726
|
-
"
|
|
771
|
+
" escapeHtml(err.message || 'Check that the browser is running and you are signed in to ' + label + '.') + '</div>';",
|
|
727
772
|
" }",
|
|
728
773
|
" })();",
|
|
729
774
|
" }",
|
|
730
775
|
// Render the channel list with three-state checkboxes. Each discovered channel carries an optional lineup field from the server's annotation layer.
|
|
731
|
-
// When lineup is present, the channel
|
|
732
|
-
//
|
|
776
|
+
// When lineup is present but the entry is disabled, the channel is "disabled" regardless of currentTag. Otherwise, when lineup.currentTag matches the
|
|
777
|
+
// browsed service slug, the channel is "current" (checked); when it differs, the channel is "switch" (indeterminate). When lineup is absent, the
|
|
778
|
+
// channel is "new" (empty).
|
|
733
779
|
" function renderBrowseChannelList(channels, slug, label) {",
|
|
734
780
|
" if(!channels || channels.length === 0) {",
|
|
735
781
|
" document.getElementById('browse-content').innerHTML =",
|
|
736
782
|
" '<div class=\"wizard-empty\"><div class=\"wizard-empty-title\">No channels found.</div>' +",
|
|
737
|
-
" 'Make sure you are signed in to ' +
|
|
783
|
+
" 'Make sure you are signed in to ' + escapeHtml(label) + ' in the browser.</div>';",
|
|
738
784
|
" return;",
|
|
739
785
|
" }",
|
|
740
786
|
// Build the channel list HTML with hint, legend, search filter, and three-state checkboxes.
|
|
@@ -755,8 +801,8 @@ export function generateChannelsSubtabScript() {
|
|
|
755
801
|
// Render each discovered channel. The lineup field from the server annotation determines the checkbox state.
|
|
756
802
|
" for(const ch of channels) {",
|
|
757
803
|
" const lu = ch.lineup;",
|
|
758
|
-
// Determine the channel's state from the server-provided lineup annotation
|
|
759
|
-
// switch (exists via a different service), current (already using this service).
|
|
804
|
+
// Determine the channel's state from the server-provided lineup annotation: new (no lineup data), disabled (predefined but disabled),
|
|
805
|
+
// switch (exists via a different service), or current (already using this service).
|
|
760
806
|
" let state = 'new';",
|
|
761
807
|
" let stateLabel = '';",
|
|
762
808
|
" if(lu) {",
|
|
@@ -773,33 +819,34 @@ export function generateChannelsSubtabScript() {
|
|
|
773
819
|
" }",
|
|
774
820
|
" const itemClass = 'browse-channel-item browse-state-' + state;",
|
|
775
821
|
" const searchName = ((lu && lu.displayName) ? lu.displayName : ch.name).toLowerCase();",
|
|
776
|
-
" html += '<label class=\"' + itemClass + '\" data-name=\"' +
|
|
822
|
+
" html += '<label class=\"' + itemClass + '\" data-name=\"' + escapeHtml(searchName) + '\">';",
|
|
777
823
|
// Checkbox with data attributes for state tracking and submission.
|
|
778
824
|
" html += '<input type=\"checkbox\" class=\"browse-channel-cb\"';",
|
|
779
|
-
" html += ' data-name=\"' +
|
|
780
|
-
" html += ' data-selector=\"' +
|
|
825
|
+
" html += ' data-name=\"' + escapeHtml(ch.name) + '\"';",
|
|
826
|
+
" html += ' data-selector=\"' + escapeHtml(ch.channelSelector) + '\"';",
|
|
781
827
|
" html += ' data-original=\"' + state + '\"';",
|
|
782
|
-
" if(lu) html += ' data-canonical=\"' +
|
|
783
|
-
" if(ch.stationId) html += ' data-station-id=\"' +
|
|
828
|
+
" if(lu) html += ' data-canonical=\"' + escapeHtml(lu.canonicalKey) + '\" data-has-alternatives=\"' + (lu.hasAlternatives ? 'true' : 'false') + '\"';",
|
|
829
|
+
" if(ch.stationId) html += ' data-station-id=\"' + escapeHtml(ch.stationId) + '\"';",
|
|
784
830
|
" if(state === 'current') html += ' checked';",
|
|
785
831
|
" html += '>';",
|
|
786
832
|
// Channel name with optional logo and affiliate. When the channel matches a lineup entry, use the predefined display name so the browse modal shows the
|
|
787
833
|
// same names as the channels table. For new channels (no lineup match), use the raw discovery name.
|
|
788
834
|
" const channelName = (lu && lu.displayName) ? lu.displayName : ch.name;",
|
|
789
835
|
" html += '<span class=\"browse-channel-name\">';",
|
|
790
|
-
|
|
791
|
-
"
|
|
836
|
+
// channelDisplayHtml escapes its name argument internally, so channelName is passed raw; escaping it here too would double-encode.
|
|
837
|
+
" html += channelDisplayHtml(lu ? lu.logoUrl || '' : '', channelName, 'browse-channel-logo', 'browse-channel-text', 'both');",
|
|
838
|
+
" if(ch.affiliate) html += ' <span class=\"browse-affiliate\">(' + escapeHtml(ch.affiliate) + ')</span>';",
|
|
792
839
|
" html += '</span>';",
|
|
793
840
|
// Right side: state label and tier badge.
|
|
794
841
|
" html += '<span class=\"browse-channel-meta\">';",
|
|
795
|
-
" if(stateLabel) html += '<span class=\"browse-state-label\">' +
|
|
842
|
+
" if(stateLabel) html += '<span class=\"browse-state-label\">' + escapeHtml(stateLabel) + '</span>';",
|
|
796
843
|
" if(ch.tier === 'free') html += '<span class=\"browse-tier-badge tier-free\">Free</span>';",
|
|
797
844
|
" html += '</span>';",
|
|
798
845
|
" html += '</label>';",
|
|
799
846
|
" }",
|
|
800
847
|
" html += '</div>';",
|
|
801
848
|
" document.getElementById('browse-content').innerHTML = html;",
|
|
802
|
-
" browseWizard.setTitle('Browse Channels <span class=\"browse-header-count\">(' +
|
|
849
|
+
" browseWizard.setTitle('Browse Channels <span class=\"browse-header-count\">(' + escapeHtml(label) + ' \\u2014 ' + channels.length + ' channels)</span>');",
|
|
803
850
|
// Set indeterminate state on checkboxes for channels that exist via a different service. The indeterminate property cannot be set via HTML attributes -
|
|
804
851
|
// it must be set via JavaScript after the elements are in the DOM.
|
|
805
852
|
" const switchCbs = document.querySelectorAll('.browse-channel-cb[data-original=\"switch\"]');",
|
|
@@ -896,8 +943,9 @@ export function generateChannelsSubtabScript() {
|
|
|
896
943
|
" const selectAll = document.getElementById('browse-select-all-cb');",
|
|
897
944
|
" if(selectAll) selectAll.checked = (visibleCount > 0) && allChecked;",
|
|
898
945
|
" }",
|
|
899
|
-
// Submit channel changes via the modify endpoint. Collects action
|
|
900
|
-
//
|
|
946
|
+
// Submit channel changes via the modify endpoint. Collects the applicable action for each visible checkbox by comparing its checked/indeterminate state
|
|
947
|
+
// to data-original: add (new channels checked), enable (disabled channels checked), switch (switched-to channels checked), or remove (current channels
|
|
948
|
+
// unchecked). Each entry includes an action field so the server can handle them appropriately.
|
|
901
949
|
" window.submitBrowseChannels = () => {",
|
|
902
950
|
" const cbs = document.querySelectorAll('.browse-channel-cb');",
|
|
903
951
|
" const guideUrl = browseGuideUrls[browseWizard.state.slug] || '';",
|
|
@@ -1055,24 +1103,18 @@ export function generateChannelsSubtabScript() {
|
|
|
1055
1103
|
" if(data.patch) { channelTable.applyPatch(data.patch); }",
|
|
1056
1104
|
" } catch(err) { console.error('Setup finish request failed.', err); setupWizard.close(); }",
|
|
1057
1105
|
" };",
|
|
1058
|
-
// Render the auth waiting state - shows a message while the user authenticates in Chrome.
|
|
1106
|
+
// Render the auth waiting state - shows a message while the user authenticates in Chrome. The Done and Skip buttons carry data-click-action attributes; the
|
|
1107
|
+
// project-wide dispatcher routes the clicks through the registerAction handlers installed below.
|
|
1059
1108
|
" function renderSetupAuthWaiting() {",
|
|
1060
1109
|
" const slug = setupWizard.state.selectedServices[setupWizard.state.authIndex];",
|
|
1061
1110
|
" const svc = setupServices.find((p) => p.tag === slug);",
|
|
1062
1111
|
" const label = svc ? svc.displayName : slug;",
|
|
1063
1112
|
" const content = document.getElementById('setup-content');",
|
|
1064
|
-
" content.innerHTML = '<div class=\"wizard-spinner\">Complete authentication for ' +
|
|
1113
|
+
" content.innerHTML = '<div class=\"wizard-spinner\">Complete authentication for ' + escapeHtml(label) +",
|
|
1065
1114
|
" ' in the Chrome browser window...</div>' +",
|
|
1066
1115
|
" '<div class=\"wizard-step-centered-compact\">' +",
|
|
1067
|
-
" '<button type=\"button\" class=\"btn btn-primary\" data-action=\"
|
|
1068
|
-
" '<button type=\"button\" class=\"btn btn-secondary\" data-action=\"
|
|
1069
|
-
// Attach handlers to the auth waiting buttons programmatically.
|
|
1070
|
-
" const waitActions = content.querySelectorAll('[data-action]');",
|
|
1071
|
-
" for(const btn of waitActions) {",
|
|
1072
|
-
" const action = btn.getAttribute('data-action');",
|
|
1073
|
-
" if(action === 'auth-done') { btn.onclick = () => { setupAuthDone(); }; }",
|
|
1074
|
-
" else if(action === 'auth-skip') { btn.onclick = () => { setupAuthSkip(); }; }",
|
|
1075
|
-
" }",
|
|
1116
|
+
" '<button type=\"button\" class=\"btn btn-primary\" data-click-action=\"" + ACTIONS.authDone + "\">Done</button> ' +",
|
|
1117
|
+
" '<button type=\"button\" class=\"btn btn-secondary\" data-click-action=\"" + ACTIONS.authSkip + "\">Skip</button></div>';",
|
|
1076
1118
|
" }",
|
|
1077
1119
|
// Render the current setup step content and update navigation buttons. The controller handles step indicator updates and error clearing.
|
|
1078
1120
|
" function renderSetupStep(step) {",
|
|
@@ -1092,7 +1134,8 @@ export function generateChannelsSubtabScript() {
|
|
|
1092
1134
|
" const checked = setupWizard.state.selectedServices.includes(p.tag) ? ' checked' : '';",
|
|
1093
1135
|
" html += '<label class=\"wizard-provider-card\">';",
|
|
1094
1136
|
" html += '<input type=\"checkbox\" class=\"setup-provider-cb\" value=\"' + p.tag + '\"' + checked + '>';",
|
|
1095
|
-
|
|
1137
|
+
// serviceIconHtml escapes its name argument internally, so displayName is passed raw; escaping it here too would double-encode.
|
|
1138
|
+
" html += serviceIconHtml(p.domain || '', p.displayName, 'provider-icon', 'provider-icon-text', 'both', p.iconUrl || '');",
|
|
1096
1139
|
" html += '</label>';",
|
|
1097
1140
|
" }",
|
|
1098
1141
|
" html += '</div>';",
|
|
@@ -1107,10 +1150,10 @@ export function generateChannelsSubtabScript() {
|
|
|
1107
1150
|
" html += '<p class=\"wizard-hint\">Sign in to each service in the Chrome browser window. " +
|
|
1108
1151
|
"PrismCast uses your login session to access live streams.</p>';",
|
|
1109
1152
|
" html += '<div class=\"wizard-step-centered\">';",
|
|
1110
|
-
" html += '<p class=\"wizard-step-provider-name\">' +
|
|
1153
|
+
" html += '<p class=\"wizard-step-provider-name\">' + escapeHtml(label) + '</p>';",
|
|
1111
1154
|
" html += '<p class=\"wizard-step-provider-count\">Service ' + current + ' of ' + total + '</p>';",
|
|
1112
|
-
" html += '<button type=\"button\" class=\"btn btn-primary\" data-action=\"
|
|
1113
|
-
" html += '<button type=\"button\" class=\"btn btn-secondary\" data-action=\"
|
|
1155
|
+
" html += '<button type=\"button\" class=\"btn btn-primary\" data-click-action=\"" + ACTIONS.authStart + "\">Sign In</button> ';",
|
|
1156
|
+
" html += '<button type=\"button\" class=\"btn btn-secondary\" data-click-action=\"" + ACTIONS.authSkip + "\">Skip</button>';",
|
|
1114
1157
|
" html += '</div>';",
|
|
1115
1158
|
" }",
|
|
1116
1159
|
// Step 3: Summary and finish.
|
|
@@ -1123,25 +1166,19 @@ export function generateChannelsSubtabScript() {
|
|
|
1123
1166
|
" html += '</div>';",
|
|
1124
1167
|
" }",
|
|
1125
1168
|
" content.innerHTML = html;",
|
|
1126
|
-
// Attach event handlers to dynamically-rendered buttons programmatically. Uses data-action attributes to identify buttons without inline onclick.
|
|
1127
|
-
" const actions = content.querySelectorAll('[data-action]');",
|
|
1128
|
-
" for(const btn of actions) {",
|
|
1129
|
-
" const action = btn.getAttribute('data-action');",
|
|
1130
|
-
" if(action === 'auth-start') { btn.onclick = () => { setupAuthService(); }; }",
|
|
1131
|
-
" else if(action === 'auth-skip') { btn.onclick = () => { setupAuthSkip(); }; }",
|
|
1132
|
-
" else if(action === 'auth-done') { btn.onclick = () => { setupAuthDone(); }; }",
|
|
1133
|
-
" }",
|
|
1134
1169
|
" }",
|
|
1135
1170
|
// Tag Management Modal.
|
|
1136
1171
|
// Single function for applying tag mutation responses. Updates the tag manager modal body, the column header filter dropdown, the channel table patch, and shows
|
|
1137
|
-
// a toast. Exposed on window so both channels.ts and config.ts (bulkToggleTag) can use the same code path. No page reload needed.
|
|
1172
|
+
// a toast. Exposed on window so both channels.ts and config.ts (bulkToggleTag) can use the same code path. No page reload needed. The server's message wins over
|
|
1173
|
+
// the caller's fallback so a mutation response can carry the playlist-reload hint; the fallback covers responses that carry no message.
|
|
1138
1174
|
" window.applyTagResponse = (data, toastMessage) => {",
|
|
1139
1175
|
" const contentDiv = document.getElementById('tag-manager-modal-content');",
|
|
1140
1176
|
" if(contentDiv && data.modalBody) { contentDiv.innerHTML = data.modalBody; }",
|
|
1141
1177
|
" const filterMenu = document.getElementById('tag-filter-menu');",
|
|
1142
1178
|
" if(filterMenu && data.filterContent) { filterMenu.innerHTML = data.filterContent; applyTagColumnFilter(); }",
|
|
1143
1179
|
" if(data.patch) { channelTable.applyPatch(data.patch); }",
|
|
1144
|
-
"
|
|
1180
|
+
" const toast = data.message || toastMessage;",
|
|
1181
|
+
" if(toast && window.showToast) { window.showToast(toast); }",
|
|
1145
1182
|
" };",
|
|
1146
1183
|
" window.openTagManager = () => {",
|
|
1147
1184
|
" const modal = document.getElementById('tag-manager-modal');",
|
|
@@ -1264,14 +1301,14 @@ export function generateChannelsSubtabScript() {
|
|
|
1264
1301
|
" const useExclude = unchecked.length < checked.length;",
|
|
1265
1302
|
" const tagParam = useExclude ? unchecked.map((t) => '-' + t).join(',') : checked.join(',');",
|
|
1266
1303
|
" const url = location.origin + '/playlist?tag=' + tagParam;",
|
|
1267
|
-
" const label = useExclude ? 'all channels except those tagged <strong>' + unchecked.join(', ') + '</strong>'",
|
|
1268
|
-
" : 'channels tagged <strong>' + checked.join(', ') + '</strong>';",
|
|
1304
|
+
" const label = useExclude ? 'all channels except those tagged <strong>' + unchecked.map((t) => escapeHtml(t)).join(', ') + '</strong>'",
|
|
1305
|
+
" : 'channels tagged <strong>' + checked.map((t) => escapeHtml(t)).join(', ') + '</strong>';",
|
|
1269
1306
|
" toggleDropdown(btn, { onOpen: (menu) => {",
|
|
1270
1307
|
" menu.innerHTML = '<div class=\"playlist-hint-content\">' +",
|
|
1271
1308
|
" '<p>Playlist URL for Channels DVR: ' + label + '.</p>' +",
|
|
1272
1309
|
" '<div class=\"playlist-hint-url\">' +",
|
|
1273
|
-
" '<code>' + url + '</code>' +",
|
|
1274
|
-
" '<button type=\"button\" class=\"btn btn-primary btn-sm\"
|
|
1310
|
+
" '<code>' + escapeHtml(url) + '</code>' +",
|
|
1311
|
+
" '<button type=\"button\" class=\"btn btn-primary btn-sm\" data-click-action=\"" + ACTIONS.copyPlaylistHintUrl + "\">Copy</button>' +",
|
|
1275
1312
|
" '</div></div>';",
|
|
1276
1313
|
" }});",
|
|
1277
1314
|
" };",
|
|
@@ -1340,6 +1377,48 @@ export function generateChannelsSubtabScript() {
|
|
|
1340
1377
|
" storageKey: 'prismcast-channels-subtab',",
|
|
1341
1378
|
" switchFn: switchChannelsSubtab",
|
|
1342
1379
|
" });",
|
|
1380
|
+
/* Action registrations. Each binds an ACTIONS name to a window-exposed handler defined above; the project-wide dispatcher in shared.ts looks up the handler
|
|
1381
|
+
* by name when a click / change / keydown / submit event lands on a matching [data-<event>-action] element. Handlers express only the action's intent -
|
|
1382
|
+
* event mechanics (preventDefault, stopPropagation, dropdown close) live declaratively on the trigger element via the event-type-scoped data-<event>-prevent
|
|
1383
|
+
* -default, data-<event>-stop-propagation, and data-<event>-close-dropdown attributes that the dispatcher processes before the handler runs.
|
|
1384
|
+
*/
|
|
1385
|
+
" window.registerAction('" + ACTIONS.applyTagColumnFilter + "', () => applyTagColumnFilter());",
|
|
1386
|
+
" window.registerAction('" + ACTIONS.authDone + "', () => setupAuthDone());",
|
|
1387
|
+
" window.registerAction('" + ACTIONS.authSkip + "', () => setupAuthSkip());",
|
|
1388
|
+
" window.registerAction('" + ACTIONS.authStart + "', () => setupAuthService());",
|
|
1389
|
+
" window.registerAction('" + ACTIONS.checkSelectors + "', () => checkSelectors());",
|
|
1390
|
+
" window.registerAction('" + ACTIONS.copyPlaylistHintUrl + "', () => copyPlaylistHintUrl());",
|
|
1391
|
+
" window.registerAction('" + ACTIONS.closeExportModal + "', () => closeExportModal());",
|
|
1392
|
+
" window.registerAction('" + ACTIONS.closeImportModal + "', () => closeImportModal());",
|
|
1393
|
+
" window.registerAction('" + ACTIONS.closeTagManager + "', () => closeTagManager());",
|
|
1394
|
+
" window.registerAction('" + ACTIONS.createTag + "', () => createTag());",
|
|
1395
|
+
/* Conditional preventDefault on a specific key. data-keydown-prevent-default would fire on every keystroke; only Enter should be canceled. The conditional
|
|
1396
|
+
* filtering logic lives in the handler since the dispatcher's modifier walk has no per-key scope.
|
|
1397
|
+
*/
|
|
1398
|
+
" window.registerAction('" + ACTIONS.createTagOnEnter + "', (target, event) => {",
|
|
1399
|
+
" if(event.key === 'Enter') { event.preventDefault(); createTag(); }",
|
|
1400
|
+
" });",
|
|
1401
|
+
" window.registerAction('" + ACTIONS.deleteTag + "', (target) => deleteTag(target.dataset.tagName));",
|
|
1402
|
+
" window.registerAction('" + ACTIONS.deleteUserProfile + "', (target) => deleteUserProfile(target.dataset.profileKey));",
|
|
1403
|
+
" window.registerAction('" + ACTIONS.editUserProfile + "', (target) => editUserProfile(target.dataset.profileKey));",
|
|
1404
|
+
" window.registerAction('" + ACTIONS.endProfileTest + "', () => endProfileTest());",
|
|
1405
|
+
" window.registerAction('" + ACTIONS.executeExport + "', () => executeExport());",
|
|
1406
|
+
" window.registerAction('" + ACTIONS.executeImport + "', () => executeImport());",
|
|
1407
|
+
" window.registerAction('" + ACTIONS.finishSetup + "', () => finishSetup());",
|
|
1408
|
+
" window.registerAction('" + ACTIONS.openBrowseModal + "', () => openBrowseModal());",
|
|
1409
|
+
" window.registerAction('" + ACTIONS.openSetupWizard + "', () => openSetupWizard());",
|
|
1410
|
+
" window.registerAction('" + ACTIONS.openTagManager + "', () => openTagManager());",
|
|
1411
|
+
" window.registerAction('" + ACTIONS.openWizard + "', () => openWizard());",
|
|
1412
|
+
" window.registerAction('" + ACTIONS.restoreTag + "', (target) => restoreTag(target.dataset.tagName));",
|
|
1413
|
+
" window.registerAction('" + ACTIONS.saveProfile + "', (target) => saveProfile(target.dataset.withTest === 'true'));",
|
|
1414
|
+
" window.registerAction('" + ACTIONS.showPlaylistHint + "', (target) => showPlaylistHint(target));",
|
|
1415
|
+
" window.registerAction('" + ACTIONS.skipSetup + "', () => skipSetup());",
|
|
1416
|
+
" window.registerAction('" + ACTIONS.startServiceExport + "', () => startServiceExport());",
|
|
1417
|
+
" window.registerAction('" + ACTIONS.startServiceImport + "', () => startServiceImport());",
|
|
1418
|
+
" window.registerAction('" + ACTIONS.startTagRename + "', (target) => startTagRename(target, target.dataset.tagName));",
|
|
1419
|
+
" window.registerAction('" + ACTIONS.submitBrowseChannels + "', () => submitBrowseChannels());",
|
|
1420
|
+
" window.registerAction('" + ACTIONS.toggleExportAll + "', (target) => toggleExportAll(target));",
|
|
1421
|
+
" window.registerAction('" + ACTIONS.toggleTagColumnFilter + "', () => toggleTagColumnFilter());",
|
|
1343
1422
|
"})();",
|
|
1344
1423
|
"</script>"
|
|
1345
1424
|
].join("\n");
|