prismcast 1.5.2 → 1.7.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.
Files changed (239) hide show
  1. package/README.md +44 -28
  2. package/dist/app.d.ts +5 -0
  3. package/dist/app.js +63 -5
  4. package/dist/app.js.map +1 -1
  5. package/dist/browser/cdp.js +1 -1
  6. package/dist/browser/cdp.js.map +1 -1
  7. package/dist/browser/channelSelection.d.ts +10 -34
  8. package/dist/browser/channelSelection.js +31 -96
  9. package/dist/browser/channelSelection.js.map +1 -1
  10. package/dist/browser/display.d.ts +19 -0
  11. package/dist/browser/display.js +16 -11
  12. package/dist/browser/display.js.map +1 -1
  13. package/dist/browser/index.d.ts +31 -54
  14. package/dist/browser/index.js +334 -272
  15. package/dist/browser/index.js.map +1 -1
  16. package/dist/browser/login.d.ts +65 -0
  17. package/dist/browser/login.js +193 -0
  18. package/dist/browser/login.js.map +1 -0
  19. package/dist/browser/precaching.js +15 -3
  20. package/dist/browser/precaching.js.map +1 -1
  21. package/dist/browser/tuning/comcastPolymer.d.ts +23 -0
  22. package/dist/browser/tuning/comcastPolymer.js +655 -0
  23. package/dist/browser/tuning/comcastPolymer.js.map +1 -0
  24. package/dist/browser/tuning/cox.d.ts +2 -0
  25. package/dist/browser/tuning/cox.js +14 -0
  26. package/dist/browser/tuning/cox.js.map +1 -0
  27. package/dist/browser/tuning/directv.js +14 -1
  28. package/dist/browser/tuning/directv.js.map +1 -1
  29. package/dist/browser/tuning/fox.js +14 -2
  30. package/dist/browser/tuning/fox.js.map +1 -1
  31. package/dist/browser/tuning/hbo.js +12 -1
  32. package/dist/browser/tuning/hbo.js.map +1 -1
  33. package/dist/browser/tuning/hulu.js +24 -1
  34. package/dist/browser/tuning/hulu.js.map +1 -1
  35. package/dist/browser/tuning/shared.d.ts +46 -0
  36. package/dist/browser/tuning/shared.js +100 -0
  37. package/dist/browser/tuning/shared.js.map +1 -0
  38. package/dist/browser/tuning/sling.js +35 -5
  39. package/dist/browser/tuning/sling.js.map +1 -1
  40. package/dist/browser/tuning/spectrum.js +13 -1
  41. package/dist/browser/tuning/spectrum.js.map +1 -1
  42. package/dist/browser/tuning/thumbnailRow.js +1 -1
  43. package/dist/browser/tuning/thumbnailRow.js.map +1 -1
  44. package/dist/browser/tuning/tileClick.js +1 -1
  45. package/dist/browser/tuning/tileClick.js.map +1 -1
  46. package/dist/browser/tuning/xfinity.d.ts +2 -0
  47. package/dist/browser/tuning/xfinity.js +14 -0
  48. package/dist/browser/tuning/xfinity.js.map +1 -0
  49. package/dist/browser/tuning/youtubeTv.js +15 -1
  50. package/dist/browser/tuning/youtubeTv.js.map +1 -1
  51. package/dist/browser/video.d.ts +20 -0
  52. package/dist/browser/video.js +168 -124
  53. package/dist/browser/video.js.map +1 -1
  54. package/dist/channels/index.d.ts +2 -2
  55. package/dist/channels/index.js +2075 -683
  56. package/dist/channels/index.js.map +1 -1
  57. package/dist/config/health.d.ts +28 -28
  58. package/dist/config/health.js +72 -54
  59. package/dist/config/health.js.map +1 -1
  60. package/dist/config/index.js +29 -64
  61. package/dist/config/index.js.map +1 -1
  62. package/dist/config/paths.d.ts +12 -0
  63. package/dist/config/paths.js +16 -0
  64. package/dist/config/paths.js.map +1 -1
  65. package/dist/config/profiles.d.ts +3 -2
  66. package/dist/config/profiles.js +45 -34
  67. package/dist/config/profiles.js.map +1 -1
  68. package/dist/config/providerPacks.js +4 -1
  69. package/dist/config/providerPacks.js.map +1 -1
  70. package/dist/config/providers.d.ts +19 -5
  71. package/dist/config/providers.js +123 -93
  72. package/dist/config/providers.js.map +1 -1
  73. package/dist/config/sites.d.ts +28 -0
  74. package/dist/config/sites.js +104 -127
  75. package/dist/config/sites.js.map +1 -1
  76. package/dist/config/userChannels.d.ts +53 -2
  77. package/dist/config/userChannels.js +222 -13
  78. package/dist/config/userChannels.js.map +1 -1
  79. package/dist/config/userConfig.d.ts +2 -1
  80. package/dist/config/userConfig.js +6 -15
  81. package/dist/config/userConfig.js.map +1 -1
  82. package/dist/config/userProfiles.d.ts +0 -1
  83. package/dist/config/userProfiles.js +18 -10
  84. package/dist/config/userProfiles.js.map +1 -1
  85. package/dist/hdhr/channelMap.d.ts +1 -1
  86. package/dist/hdhr/channelMap.js +4 -4
  87. package/dist/hdhr/channelMap.js.map +1 -1
  88. package/dist/index.js +25 -22
  89. package/dist/index.js.map +1 -1
  90. package/dist/native/decrypt.d.ts +32 -0
  91. package/dist/native/decrypt.js +85 -0
  92. package/dist/native/decrypt.js.map +1 -0
  93. package/dist/native/index.d.ts +61 -0
  94. package/dist/native/index.js +342 -0
  95. package/dist/native/index.js.map +1 -0
  96. package/dist/native/intercept.d.ts +35 -0
  97. package/dist/native/intercept.js +184 -0
  98. package/dist/native/intercept.js.map +1 -0
  99. package/dist/native/probe.d.ts +49 -0
  100. package/dist/native/probe.js +294 -0
  101. package/dist/native/probe.js.map +1 -0
  102. package/dist/native/proxy.d.ts +54 -0
  103. package/dist/native/proxy.js +947 -0
  104. package/dist/native/proxy.js.map +1 -0
  105. package/dist/routes/components.d.ts +43 -0
  106. package/dist/routes/components.js +122 -0
  107. package/dist/routes/components.js.map +1 -1
  108. package/dist/routes/config/channels/index.d.ts +2 -2
  109. package/dist/routes/config/channels/index.js +1 -1
  110. package/dist/routes/config/channels/index.js.map +1 -1
  111. package/dist/routes/config/channels/routes.js +443 -65
  112. package/dist/routes/config/channels/routes.js.map +1 -1
  113. package/dist/routes/config/channels/table.d.ts +76 -0
  114. package/dist/routes/config/channels/table.js +369 -89
  115. package/dist/routes/config/channels/table.js.map +1 -1
  116. package/dist/routes/config/index.d.ts +1 -1
  117. package/dist/routes/config/index.js +1 -1
  118. package/dist/routes/config/index.js.map +1 -1
  119. package/dist/routes/config/providers.d.ts +6 -6
  120. package/dist/routes/config/providers.js +73 -99
  121. package/dist/routes/config/providers.js.map +1 -1
  122. package/dist/routes/debug.js +5 -5
  123. package/dist/routes/debug.js.map +1 -1
  124. package/dist/routes/hls.js +12 -2
  125. package/dist/routes/hls.js.map +1 -1
  126. package/dist/routes/index.d.ts +0 -15
  127. package/dist/routes/index.js +2 -16
  128. package/dist/routes/index.js.map +1 -1
  129. package/dist/routes/providers.js +106 -3
  130. package/dist/routes/providers.js.map +1 -1
  131. package/dist/routes/root/content.js +124 -47
  132. package/dist/routes/root/content.js.map +1 -1
  133. package/dist/routes/root/index.js +2 -1
  134. package/dist/routes/root/index.js.map +1 -1
  135. package/dist/routes/root/scripts/channels.js +772 -312
  136. package/dist/routes/root/scripts/channels.js.map +1 -1
  137. package/dist/routes/root/scripts/config.js +596 -544
  138. package/dist/routes/root/scripts/config.js.map +1 -1
  139. package/dist/routes/root/scripts/index.d.ts +1 -0
  140. package/dist/routes/root/scripts/index.js +1 -0
  141. package/dist/routes/root/scripts/index.js.map +1 -1
  142. package/dist/routes/root/scripts/shared.d.ts +6 -0
  143. package/dist/routes/root/scripts/shared.js +391 -0
  144. package/dist/routes/root/scripts/shared.js.map +1 -0
  145. package/dist/routes/root/scripts/status.js +49 -33
  146. package/dist/routes/root/scripts/status.js.map +1 -1
  147. package/dist/routes/root/styles.js +117 -10
  148. package/dist/routes/root/styles.js.map +1 -1
  149. package/dist/service/commands.js +2 -1
  150. package/dist/service/commands.js.map +1 -1
  151. package/dist/streaming/fmp4Segmenter.d.ts +5 -0
  152. package/dist/streaming/fmp4Segmenter.js +146 -42
  153. package/dist/streaming/fmp4Segmenter.js.map +1 -1
  154. package/dist/streaming/hls.d.ts +24 -19
  155. package/dist/streaming/hls.js +603 -297
  156. package/dist/streaming/hls.js.map +1 -1
  157. package/dist/streaming/hlsResume.d.ts +16 -3
  158. package/dist/streaming/hlsResume.js +35 -8
  159. package/dist/streaming/hlsResume.js.map +1 -1
  160. package/dist/streaming/hlsSegments.d.ts +41 -2
  161. package/dist/streaming/hlsSegments.js +131 -28
  162. package/dist/streaming/hlsSegments.js.map +1 -1
  163. package/dist/streaming/lifecycle.js +27 -13
  164. package/dist/streaming/lifecycle.js.map +1 -1
  165. package/dist/streaming/monitor.d.ts +1 -0
  166. package/dist/streaming/monitor.js +862 -474
  167. package/dist/streaming/monitor.js.map +1 -1
  168. package/dist/streaming/mp4Parser.d.ts +52 -6
  169. package/dist/streaming/mp4Parser.js +156 -30
  170. package/dist/streaming/mp4Parser.js.map +1 -1
  171. package/dist/streaming/mpegts.d.ts +2 -2
  172. package/dist/streaming/mpegts.js +156 -109
  173. package/dist/streaming/mpegts.js.map +1 -1
  174. package/dist/streaming/playlistBuilder.d.ts +38 -0
  175. package/dist/streaming/playlistBuilder.js +66 -0
  176. package/dist/streaming/playlistBuilder.js.map +1 -0
  177. package/dist/streaming/preroll.d.ts +126 -0
  178. package/dist/streaming/preroll.js +434 -0
  179. package/dist/streaming/preroll.js.map +1 -0
  180. package/dist/streaming/pretune.d.ts +8 -0
  181. package/dist/streaming/pretune.js +226 -0
  182. package/dist/streaming/pretune.js.map +1 -0
  183. package/dist/streaming/recovery.d.ts +0 -6
  184. package/dist/streaming/recovery.js +0 -8
  185. package/dist/streaming/recovery.js.map +1 -1
  186. package/dist/streaming/registry.d.ts +57 -9
  187. package/dist/streaming/registry.js +26 -7
  188. package/dist/streaming/registry.js.map +1 -1
  189. package/dist/streaming/setup.d.ts +8 -1
  190. package/dist/streaming/setup.js +71 -27
  191. package/dist/streaming/setup.js.map +1 -1
  192. package/dist/streaming/showInfo.d.ts +29 -4
  193. package/dist/streaming/showInfo.js +210 -38
  194. package/dist/streaming/showInfo.js.map +1 -1
  195. package/dist/streaming/statusEmitter.d.ts +20 -6
  196. package/dist/streaming/statusEmitter.js +31 -7
  197. package/dist/streaming/statusEmitter.js.map +1 -1
  198. package/dist/types/channels.d.ts +32 -0
  199. package/dist/types/config.d.ts +2 -2
  200. package/dist/types/index.d.ts +2 -2
  201. package/dist/types/index.js.map +1 -1
  202. package/dist/types/profiles.d.ts +13 -1
  203. package/dist/types/selection.d.ts +5 -1
  204. package/dist/types/shared.d.ts +1 -1
  205. package/dist/types/streaming.d.ts +7 -0
  206. package/dist/utils/chromeFetch.d.ts +20 -0
  207. package/dist/utils/chromeFetch.js +43 -0
  208. package/dist/utils/chromeFetch.js.map +1 -0
  209. package/dist/utils/debugFilter.d.ts +0 -5
  210. package/dist/utils/debugFilter.js +20 -11
  211. package/dist/utils/debugFilter.js.map +1 -1
  212. package/dist/utils/delay.d.ts +28 -0
  213. package/dist/utils/delay.js +35 -1
  214. package/dist/utils/delay.js.map +1 -1
  215. package/dist/utils/evaluate.js +6 -11
  216. package/dist/utils/evaluate.js.map +1 -1
  217. package/dist/utils/ffmpeg.d.ts +14 -12
  218. package/dist/utils/ffmpeg.js +114 -134
  219. package/dist/utils/ffmpeg.js.map +1 -1
  220. package/dist/utils/format.d.ts +6 -0
  221. package/dist/utils/format.js +8 -0
  222. package/dist/utils/format.js.map +1 -1
  223. package/dist/utils/index.d.ts +3 -0
  224. package/dist/utils/index.js +3 -0
  225. package/dist/utils/index.js.map +1 -1
  226. package/dist/utils/logEmitter.js +1 -1
  227. package/dist/utils/logEmitter.js.map +1 -1
  228. package/dist/utils/pid.d.ts +40 -0
  229. package/dist/utils/pid.js +83 -0
  230. package/dist/utils/pid.js.map +1 -0
  231. package/dist/utils/retry.d.ts +15 -9
  232. package/dist/utils/retry.js +7 -23
  233. package/dist/utils/retry.js.map +1 -1
  234. package/dist/utils/timing.d.ts +5 -0
  235. package/dist/utils/timing.js +13 -0
  236. package/dist/utils/timing.js.map +1 -0
  237. package/dist/utils/version.js +2 -2
  238. package/dist/utils/version.js.map +1 -1
  239. package/package.json +7 -7
@@ -4,11 +4,14 @@ import { getUserDomains } from "./userProfiles.js";
4
4
  * and many have unique quirks like auto-muting or requiring specific fullscreen methods. Rather than scattering site-specific conditionals throughout the streaming
5
5
  * code, we define "site profiles" that describe each site's behavior in a declarative way.
6
6
  *
7
- * The profile system has three components:
7
+ * The profile system has four components:
8
8
  *
9
- * 1. SITE_PROFILES: Named behavior configurations describing how to handle different player implementations. Profiles can inherit from other profiles using the
10
- * "extends" property, allowing us to define base profiles for common patterns (like "keyboardFullscreen" for sites using the f key) and then extend them with
11
- * site-specific variations.
9
+ * 1. SITE_PROFILES: General-purpose behavior configurations that users can select for custom channels. These describe common player implementation patterns and
10
+ * are shown in UI dropdowns and the provider wizard. Profiles can inherit from other profiles using the "extends" property.
11
+ *
12
+ * 1b. PROVIDER_PROFILES: Internal profiles tied to specific provider modules (Hulu, YouTube TV, Sling, etc.). These have channel selection strategies and
13
+ * selectors tightly coupled to a streaming service's DOM structure. They are never shown in user-facing profile lists — users targeting these services should
14
+ * use the predefined channels directly. Provider profiles can extend general profiles (e.g., fullscreenApi) and profile resolution checks both tables.
12
15
  *
13
16
  * 2. DOMAIN_CONFIG: A mapping from domain patterns to site profiles and provider display names. When streaming a URL, we check if it matches any known domain and
14
17
  * use the corresponding profile. Provider display names give friendly labels (e.g., "Hulu" instead of "hulu.com") for the UI source column and provider
@@ -36,7 +39,7 @@ import { getUserDomains } from "./userProfiles.js";
36
39
  * - fullscreenApi: Sites requiring the JavaScript requestFullscreen() API
37
40
  * - staticPage: Non-video pages captured as static visual content
38
41
  *
39
- * Derived profiles (extends a base):
42
+ * General derived profiles (extends a base, user-selectable):
40
43
  * - keyboardDynamic: Keyboard fullscreen + network idle wait (extends keyboardFullscreen)
41
44
  * - keyboardMultiVideo: Keyboard fullscreen + multi-video selection (extends keyboardFullscreen)
42
45
  * - keyboardIframe: Keyboard fullscreen + iframe handling (extends keyboardFullscreen)
@@ -44,16 +47,13 @@ import { getUserDomains } from "./userProfiles.js";
44
47
  * - clickToPlayKeyboard: Click to start playback + keyboard fullscreen (extends keyboardFullscreen)
45
48
  * - brightcove: Brightcove players using API fullscreen + network idle wait (extends fullscreenApi)
46
49
  * - clickToPlayApi: Click to start playback + API fullscreen (extends fullscreenApi)
47
- * - disneyNow: DisneyNOW player with play button overlay + multi-video (extends clickToPlayApi)
48
50
  * - embeddedPlayer: Iframe-based players using fullscreen API (extends fullscreenApi)
49
51
  * - apiMultiVideo: API fullscreen + multi-video + auto-play tile channel selection via matchSelector (extends fullscreenApi)
50
- * - disneyPlus: API fullscreen + multi-video + tile selection via matchSelector with play button modal (extends fullscreenApi)
51
- * - huluLive: Hulu Live TV with guide grid channel selection + fullscreen button (extends fullscreenApi)
52
52
  * - embeddedDynamicMultiVideo: Embedded + network idle + multi-video selection (extends embeddedPlayer)
53
53
  * - embeddedVolumeLock: Embedded + volume property locking (extends embeddedPlayer)
54
- * - foxLive: Fox.com live guide grid with station code channel selection (extends fullscreenApi)
55
- * - slingLive: Sling TV with virtualized A-Z guide grid channel selection (extends fullscreenApi)
56
- * - youtubeTV: YouTube TV with non-virtualized EPG grid channel selection (extends fullscreenApi)
54
+ *
55
+ * Provider profiles (internal, not user-selectable — in PROVIDER_PROFILES table or registered by provider modules):
56
+ * - coxStream, directvStream, disneyNow, disneyPlus, foxLive, hboMax, huluLive, slingLive, spectrum, xfinityStream, youtubeTV
57
57
  *
58
58
  * Each profile includes a description field documenting its purpose. This is metadata only - it's stripped during profile resolution and exists purely for
59
59
  * documentation.
@@ -72,11 +72,13 @@ export const SITE_PROFILES = {
72
72
  },
73
73
  // Profile for sites using the Brightcove player platform. Brightcove players require waiting for network activity to settle before the video player is fully
74
74
  // initialized. The player dynamically loads its configuration and stream manifest, so waitForNetworkIdle ensures we don't try to interact with the player before
75
- // it's ready. Uses the JavaScript fullscreen API rather than keyboard shortcuts because Brightcove intercepts keyboard events.
75
+ // it's ready. Uses the JavaScript fullscreen API rather than keyboard shortcuts because Brightcove intercepts keyboard events. Uses selectReadyVideo because
76
+ // pages may have multiple video elements (preroll ads alongside the main player), and the ad video reaches readyState >= 3 before the main player.
76
77
  brightcove: {
77
78
  category: "api",
78
79
  description: "Brightcove player sites requiring network idle wait and API fullscreen.",
79
80
  extends: "fullscreenApi",
81
+ selectReadyVideo: true,
80
82
  summary: "Brightcove players (network wait)",
81
83
  waitForNetworkIdle: true
82
84
  },
@@ -98,44 +100,6 @@ export const SITE_PROFILES = {
98
100
  extends: "keyboardFullscreen",
99
101
  summary: "Click-to-play ('f' key fullscreen)"
100
102
  },
101
- // Profile for DirecTV Stream (stream.directv.com) live guide. The guide page is a React Native for Web SPA where all ~152 channel logos are always in the DOM
102
- // (not virtualized). The primary tuning mechanism bypasses DOM interaction entirely by injecting into webpack internals — capturing __webpack_require__ via the
103
- // chunk push array, extracting the Redux store from the React fiber tree, and dispatching the playConsumable action to switch channels. The fallback uses logo
104
- // aria-label matching with DOM click (coordinate clicks are blocked by an invisible overlay). Uses selectReadyVideo because the page has multiple video elements.
105
- directvStream: {
106
- category: "multiChannel",
107
- channelSelection: { strategy: "directvGrid" },
108
- description: "DirecTV Stream with direct tune via webpack injection. Set Channel Selector to the channel name as shown in the guide (e.g., CNN, ESPN, NBC).",
109
- extends: "fullscreenApi",
110
- selectReadyVideo: true,
111
- summary: "DirecTV Stream (guide grid, needs selector)"
112
- },
113
- // Profile for DisneyNOW (disneynow.com) which has a play button overlay that must be clicked to start playback and multiple video elements on the page.
114
- disneyNow: {
115
- category: "api",
116
- clickSelector: ".overlay__button button",
117
- description: "DisneyNOW player with play button overlay and multiple video elements.",
118
- extends: "clickToPlayApi",
119
- selectReadyVideo: true,
120
- summary: "DisneyNOW player"
121
- },
122
- // Profile for Disney+ live channels. The live channel shelf displays tiles with network logos. Clicking a tile opens an entity modal with a "WATCH LIVE" button
123
- // (playSelector) that must be clicked to start the stream. Extends fullscreenApi for requestFullscreen() behavior. The player uses Web Components with Shadow DOM
124
- // for its controls — the native <toggle-fullscreen> button cannot be clicked by Puppeteer (Shadow DOM boundary), so fullscreen is handled entirely by the inherited
125
- // requestFullscreen() API. The controls toolbar is hidden via hideSelector to prevent it from appearing in the captured stream. Uses selectReadyVideo because the
126
- // page has multiple video elements (previews, ads, main content).
127
- disneyPlus: {
128
- category: "multiChannel",
129
- channelSelection: {
130
- matchSelector: "img[src*=\"{channel}\" i]", playSelector: "[data-testid=\"live-modal-watch-live-action-button\"]",
131
- scrollToBottom: true, strategy: "tileClick"
132
- },
133
- description: "Disney+ live channels with tile selection and play button modal. Channel Selector is interpolated into matchSelector to find the element.",
134
- extends: "fullscreenApi",
135
- hideSelector: ".controls__footer__wrapper",
136
- selectReadyVideo: true,
137
- summary: "Disney+ (tile + play button, needs selector)"
138
- },
139
103
  // Profile for iframe-embedded players that also have multiple video elements (ads, placeholders, main content) and need network activity to settle. The
140
104
  // selectReadyVideo flag ensures we find the video with actual content rather than an ad placeholder. Combines iframe handling with API-based fullscreen.
141
105
  embeddedDynamicMultiVideo: {
@@ -165,17 +129,6 @@ export const SITE_PROFILES = {
165
129
  lockVolumeProperties: true,
166
130
  summary: "Embedded players that auto-mute"
167
131
  },
168
- // Profile for Fox.com live channel guide grid. The guide page presents all channels in a non-virtualized grid with station codes in the channel logo button
169
- // titles (e.g., FOXD2C, FNC, FS1). The channelSelector property matches against these station codes. Clicking the channel logo button is an SPA state
170
- // transition — the player at the top of the page switches channels without navigation. The grid renders dynamically after page load, so the strategy waits
171
- // for GuideChannelContainer elements before scanning.
172
- foxLive: {
173
- category: "multiChannel",
174
- channelSelection: { strategy: "foxGrid" },
175
- description: "Fox.com live channel guide. Set Channel Selector to the station code (e.g., BTN, FOXD2C, FS1).",
176
- extends: "fullscreenApi",
177
- summary: "Fox Live (guide grid, needs selector)"
178
- },
179
132
  // Base profile for sites that require the JavaScript fullscreen API (element.requestFullscreen()) instead of keyboard shortcuts. Many modern players intercept
180
133
  // keyboard events for their own controls, making the f key unreliable. Calling requestFullscreen() directly on the video element bypasses the player's keyboard
181
134
  // handling and reliably enters fullscreen mode.
@@ -185,31 +138,6 @@ export const SITE_PROFILES = {
185
138
  summary: "Sites needing JavaScript fullscreen",
186
139
  useRequestFullscreen: true
187
140
  },
188
- // Profile for HBO Max live channels (play.hbomax.com). The HBO brand page contains a "Distribution Channels" rail showing all 5 live linear channels (HBO, HBO
189
- // Hits, HBO Drama, HBO Comedy, HBO Movies) as tiles. The hboGrid strategy discovers the HBO tab URL from the homepage menu bar, navigates to it, then scrapes the
190
- // channel rail for the watch URL matching the channelSelector name. Extends fullscreenApi for requestFullscreen() behavior inherited by the watch page.
191
- hboMax: {
192
- category: "multiChannel",
193
- channelSelection: { strategy: "hboGrid" },
194
- description: "HBO Max with live channel rail selection. Set Channel Selector to the channel name (e.g., HBO, HBO Hits).",
195
- extends: "fullscreenApi",
196
- summary: "HBO Max (live channels, needs selector)"
197
- },
198
- // Profile for Hulu Live TV which presents a guide grid of live channels. The channel list is revealed by clicking a tab (listSelector), then the desired channel
199
- // is found by matching img.alt text. Uses the fullscreen API (inherited from fullscreenApi) plus a dedicated fullscreen button selector for the player's native
200
- // maximize control. Requires selectReadyVideo because the page may have multiple video elements (ads, previews, main content). Uses waitForNetworkIdle because
201
- // Hulu's SPA has heavy async initialization that often prevents the load event from firing within the retryOperation timeout; the graceful networkidle2 fallback
202
- // in navigateToPage() allows execution to continue to channel selection even when background requests are still pending.
203
- huluLive: {
204
- category: "multiChannel",
205
- channelSelection: { listSelector: "#CHANNELS", playSelector: "[data-testid=\"generic-tile-thumbnail\"]", strategy: "guideGrid" },
206
- description: "Hulu Live TV with guide grid channel selection. Set Channel Selector to the channel's internal guide name (may differ from logo).",
207
- extends: "fullscreenApi",
208
- fullscreenSelector: "[aria-label=\"Maximize\"]",
209
- selectReadyVideo: true,
210
- summary: "Hulu Live TV (guide grid, needs selector)",
211
- waitForNetworkIdle: true
212
- },
213
141
  // Profile for sites that use keyboard fullscreen and also need time for network activity to settle before the player is fully initialized. These sites dynamically
214
142
  // load their player and content. The waitForNetworkIdle flag ensures we don't try to interact with the player until all initial network requests have completed.
215
143
  keyboardDynamic: {
@@ -256,29 +184,6 @@ export const SITE_PROFILES = {
256
184
  selectReadyVideo: true,
257
185
  summary: "Multi-video sites ('f' key fullscreen)"
258
186
  },
259
- // Profile for Sling TV (watch.sling.com) live guide grid. The A-Z guide at /dashboard/grid_guide/grid_guide_a_z renders a virtualized grid of ~638 rows
260
- // (120px each) with channel identification via data-testid="channel-{NAME}" attributes. The slingGrid strategy performs binary search on .guide-cell scrollTop
261
- // to locate the target channel, then clicks the on-now program cell which navigates to a player page where a single <video> element auto-plays. Extends
262
- // fullscreenApi for requestFullscreen() behavior. Does not use waitForNetworkIdle — the strategy's own waitForSelector on channel entries is the readiness
263
- // signal, and the SPA's persistent connections would delay network idle unnecessarily.
264
- slingLive: {
265
- category: "multiChannel",
266
- channelSelection: { strategy: "slingGrid" },
267
- description: "Sling TV with guide grid channel selection. Set Channel Selector to the channel's internal guide name (may differ from logo).",
268
- extends: "fullscreenApi",
269
- summary: "Sling TV (guide grid, needs selector)"
270
- },
271
- // Profile for Spectrum TV (watch.spectrum.net) live guide grid. The guide page at /guide presents all ~442 streamable channels in a non-virtualized AngularJS
272
- // DOM. Channel headers provide callsigns, channel numbers, and Gracenote station IDs (tmsid from logo image URLs). The spectrumGrid strategy reads all channels
273
- // in a single evaluate pass, caches them, and navigates directly to /livetv?tmsid={stationId} — no clicking, no SPA state changes, no overlays. The channelSelector
274
- // matches against clean channel names (e.g., "ESPN", "CNN", "NBC") with callsign suffix tolerance and affiliate network name resolution.
275
- spectrum: {
276
- category: "multiChannel",
277
- channelSelection: { strategy: "spectrumGrid" },
278
- description: "Spectrum TV with guide grid channel selection. Set Channel Selector to the channel name (e.g., ESPN, CNN, NBC).",
279
- extends: "fullscreenApi",
280
- summary: "Spectrum TV (guide grid, needs selector)"
281
- },
282
187
  // Profile for non-video pages that should be captured as static visual content. Examples include weather displays (weatherscan.net), maps (windy.com), and
283
188
  // diagnostic pages. The noVideo flag tells the streaming code not to wait for a video element or set up playback monitoring - just capture whatever is displayed.
284
189
  staticPage: {
@@ -286,19 +191,39 @@ export const SITE_PROFILES = {
286
191
  description: "Base profile for non-video pages captured as static visual content.",
287
192
  noVideo: true,
288
193
  summary: "Static pages (no video)"
194
+ }
195
+ };
196
+ /* Provider profiles are internal profiles tied to specific provider modules. They have channel selection strategies, selectors, and flags tightly coupled to a
197
+ * specific streaming service's DOM structure and are not user-selectable. They live in a separate table from SITE_PROFILES so that UI-facing code (profile
198
+ * dropdowns, provider wizard, profile validation) can show only general-purpose profiles without maintaining an exclusion list. The extends mechanism works across
199
+ * both tables — a provider profile can extend a general profile (e.g., fullscreenApi) and profile resolution checks both tables transparently.
200
+ */
201
+ export const PROVIDER_PROFILES = {
202
+ // Profile for DisneyNOW (disneynow.com) which has a play button overlay that must be clicked to start playback and multiple video elements on the page.
203
+ disneyNow: {
204
+ category: "api",
205
+ clickSelector: ".overlay__button button",
206
+ description: "DisneyNOW player with play button overlay and multiple video elements.",
207
+ extends: "clickToPlayApi",
208
+ selectReadyVideo: true,
209
+ summary: "DisneyNOW player"
289
210
  },
290
- // Profile for YouTube TV (tv.youtube.com/live). The guide grid renders all ~256 channel rows in the DOM simultaneously (no virtualization), each containing a
291
- // direct watch URL. The youtubeGrid strategy performs a single querySelector to find the target channel's watch link via aria-label, extracts the URL, and
292
- // navigates directly — no scrolling, clicking, or timing workarounds needed. Uses selectReadyVideo because the watch page has ~36 video elements (live preview
293
- // thumbnails from the guide) but only one active stream with readyState >= 3 and videoWidth > 0. Extends fullscreenApi because requestFullscreen() works
294
- // directly on the active video element without gesture requirements.
295
- youtubeTV: {
211
+ // Profile for Disney+ live channels. The live channel shelf displays tiles with network logos. Clicking a tile opens an entity modal with a "WATCH LIVE" button
212
+ // (playSelector) that must be clicked to start the stream. Extends fullscreenApi for requestFullscreen() behavior. The player uses Web Components with Shadow DOM
213
+ // for its controls — the native <toggle-fullscreen> button cannot be clicked by Puppeteer (Shadow DOM boundary), so fullscreen is handled entirely by the inherited
214
+ // requestFullscreen() API. The controls toolbar is hidden via hideSelector to prevent it from appearing in the captured stream. Uses selectReadyVideo because the
215
+ // page has multiple video elements (previews, ads, main content).
216
+ disneyPlus: {
296
217
  category: "multiChannel",
297
- channelSelection: { strategy: "youtubeGrid" },
298
- description: "YouTube TV with EPG grid channel selection. Set Channel Selector to the channel name as shown in the guide (e.g., CNN, ESPN, NBC).",
218
+ channelSelection: {
219
+ matchSelector: "img[src*=\"{channel}\" i]", playSelector: "[data-testid=\"live-modal-watch-live-action-button\"]",
220
+ scrollToBottom: true, strategy: "tileClick"
221
+ },
222
+ description: "Disney+ live channels with tile selection and play button modal. Channel Selector is interpolated into matchSelector to find the element.",
299
223
  extends: "fullscreenApi",
224
+ hideSelector: ".controls__footer__wrapper",
300
225
  selectReadyVideo: true,
301
- summary: "YouTube TV (guide grid, needs selector)"
226
+ summary: "Disney+ (tile + play button, needs selector)"
302
227
  }
303
228
  };
304
229
  /* This mapping associates domain keys with site profiles, provider display names, and provider filter tags. Most keys are concise second-level domains
@@ -314,15 +239,16 @@ export const DOMAIN_CONFIG = {
314
239
  "abc.com": { profile: "keyboardMultiVideo", provider: "ABC.com" },
315
240
  "aetv.com": { profile: "fullscreenApi", provider: "A&E" },
316
241
  "bet.com": { profile: "fullscreenApi", provider: "BET.com" },
317
- "c-span.org": { profile: "brightcove", provider: "C-SPAN.org" },
318
- "cbs.com": { profile: "keyboardIframe", provider: "CBS.com" },
242
+ "c-span.org": { dismissSelector: ".videoAdUiSkipButtonExperimentalText", profile: "brightcove", provider: "C-SPAN.org" },
243
+ "cbs.com": { dismissSelector: "#mvpd__getstarted", profile: "keyboardIframe", provider: "CBS.com" },
319
244
  "cnbc.com": { profile: "fullscreenApi", provider: "CNBC.com" },
320
245
  "cnn.com": { profile: "fullscreenApi", provider: "CNN.com" },
321
246
  "disneynow.com": { profile: "disneyNow", provider: "DisneyNOW" },
322
- "disneyplus.com": { profile: "disneyPlus", provider: "Disney+", providerTag: "disneyplus" },
247
+ "disneyplus.com": { iconUrl: "https://static-assets.bamgrid.com/product/disneyplus/favicons/apple-touch-icon-aurora.d3af81fe0571b495a3c80ff8c3d0c8e7.png",
248
+ profile: "disneyPlus", provider: "Disney+", providerTag: "disneyplus" },
323
249
  "espn.com": { profile: "keyboardMultiVideo", provider: "ESPN.com" },
324
250
  "foodnetwork.com": { profile: "fullscreenApi", provider: "Food Network" },
325
- "fox.com": { loginUrl: "https://www.fox.com", profile: "foxLive", provider: "Fox", providerTag: "foxcom" },
251
+ "fox.com": { loginUrl: "https://www.fox.com", profile: "foxLive", provider: "Fox One", providerTag: "foxone" },
326
252
  "foxbusiness.com": { profile: "embeddedDynamicMultiVideo", provider: "Fox Business" },
327
253
  "foxnews.com": { profile: "embeddedDynamicMultiVideo", provider: "Fox News" },
328
254
  "foxsports.com": { profile: "fullscreenApi", provider: "Fox Sports" },
@@ -332,29 +258,35 @@ export const DOMAIN_CONFIG = {
332
258
  "golfchannel.com": { profile: "fullscreenApi", provider: "Golf Channel" },
333
259
  "hbomax.com": { profile: "hboMax", provider: "HBO Max", providerTag: "hbomax" },
334
260
  "history.com": { profile: "fullscreenApi", provider: "History.com" },
335
- "hulu.com": { profile: "huluLive", provider: "Hulu", providerTag: "hulu" },
261
+ "hulu.com": { iconUrl: "https://www.hulu.com/static/icons/apple-touch-icon.png", profile: "huluLive", provider: "Hulu", providerTag: "hulu" },
336
262
  "lakeshorepbs.org": { profile: "embeddedPlayer", provider: "Lakeshore PBS" },
337
263
  "ms.now": { profile: "keyboardDynamic", provider: "MS NOW" },
338
264
  "mylifetime.com": { profile: "fullscreenApi", provider: "Lifetime" },
339
265
  "nationalgeographic.com": { profile: "keyboardDynamicMultiVideo", provider: "Nat Geo" },
340
266
  "nba.com": { profile: "fullscreenApi", provider: "NBA.com" },
341
267
  "nbc.com": { maxContinuousPlayback: 4, profile: "keyboardDynamic", provider: "NBC.com" },
342
- "paramountplus.com": { profile: "fullscreenApi", provider: "Paramount+", providerTag: "paramountplus" },
268
+ "paramountplus.com": { dismissSelector: ".ppp-watch", iconUrl: "https://www.paramountplus.com/assets/images/pplus_App_Icon-Blue-144x144.png",
269
+ profile: "fullscreenApi", provider: "Paramount+", providerTag: "paramountplus" },
343
270
  "sling.com": { profile: "embeddedVolumeLock", provider: "Sling TV" },
344
271
  "starz.com": { profile: "fullscreenApi", provider: "Starz" },
345
272
  "stream.directv.com": { loginUrl: "https://stream.directv.com", profile: "directvStream", provider: "DirecTV Stream", providerTag: "directv" },
346
273
  "tbs.com": { profile: "fullscreenApi", provider: "TBS.com" },
347
274
  "tntdrama.com": { profile: "fullscreenApi", provider: "TNT" },
348
275
  "trutv.com": { profile: "fullscreenApi", provider: "truTV" },
349
- "tv.youtube.com": { profile: "youtubeTV", provider: "YouTube TV", providerTag: "yttv" },
350
- "usanetwork.com": { profile: "keyboardDynamicMultiVideo", provider: "USA Network", providerTag: "usa" },
276
+ "tv.youtube.com": { iconUrl: "https://www.youtube.com/yts/img/favicon_144-vfliLAfaB.png", profile: "youtubeTV", provider: "YouTube TV", providerTag: "yttv" },
277
+ "usanetwork.com": { iconUrl: "https://usanetwork.asset.viewlift.com/images/brand/2025/09/30/usa_favicon-1759230411162.ico",
278
+ profile: "keyboardDynamicMultiVideo", provider: "USA Network", providerTag: "usa" },
351
279
  "vh1.com": { profile: "fullscreenApi", provider: "VH1.com" },
352
280
  "watch.sling.com": { profile: "slingLive", provider: "Sling TV", providerTag: "sling" },
353
- "watch.spectrum.net": { profile: "spectrum", provider: "Spectrum TV", providerTag: "spectrum" },
281
+ "watch.spectrum.net": { iconUrl: "https://watch.spectrum.net/assets/17.28.0/images/apple-touch-icon.png", profile: "spectrum", provider: "Spectrum TV",
282
+ providerTag: "spectrum" },
354
283
  "watchhallmarktv.com": { profile: "fullscreenApi", provider: "Hallmark" },
284
+ "watchtv.cox.com": { iconUrl: "https://watchtv.cox.com/partners/cox/images/favicon-128x128.png", profile: "coxStream", provider: "Cox Contour TV",
285
+ providerTag: "cox" },
355
286
  "weatherscan.net": { profile: "staticPage", provider: "Weatherscan" },
356
287
  "windy.com": { profile: "staticPage", provider: "Windy" },
357
288
  "wttw.com": { profile: "fullscreenApi", provider: "WTTW" },
289
+ "xfinity.com": { profile: "xfinityStream", provider: "Xfinity Stream", providerTag: "xfinity" },
358
290
  "youtube.com": { profile: "keyboardDynamic", provider: "YouTube" }
359
291
  };
360
292
  /**
@@ -391,6 +323,47 @@ export function getDomainConfig(url) {
391
323
  }
392
324
  return DOMAIN_CONFIG[conciseDomain];
393
325
  }
326
+ // Provider module profiles registered at import time via registerProviderModuleProfile(). Provider modules define their profiles alongside their tuning code and
327
+ // register them here so the profile resolution system can find them without importing from browser/channelSelection.ts (which would create circular dependencies).
328
+ const providerModuleProfiles = new Map();
329
+ /**
330
+ * Registers a provider module's profile. Called by the coordinator in channelSelection.ts at module evaluation time to make provider profiles available to the
331
+ * profile resolution system. This avoids circular dependencies — sites.ts doesn't need to import from browser/ modules.
332
+ * @param name - The profile name (e.g., "huluLive", "slingLive").
333
+ * @param profile - The SiteProfile definition.
334
+ */
335
+ export function registerProviderModuleProfile(name, profile) {
336
+ if ((name in SITE_PROFILES) || (name in PROVIDER_PROFILES)) {
337
+ throw new Error("Provider module profile '" + name + "' collides with an existing static profile. Use a unique profileName.");
338
+ }
339
+ providerModuleProfiles.set(name, profile);
340
+ }
341
+ /**
342
+ * Looks up a built-in profile by name, checking the general SITE_PROFILES table, the static PROVIDER_PROFILES table, and dynamically registered provider module
343
+ * profiles. This is the single lookup function for all built-in profile resolution — callers should use this instead of accessing any table directly.
344
+ * @param name - The profile name to look up.
345
+ * @returns The matching SiteProfile, or undefined if not found in any source.
346
+ */
347
+ export function getBuiltinProfile(name) {
348
+ return SITE_PROFILES[name] ?? PROVIDER_PROFILES[name] ?? providerModuleProfiles.get(name);
349
+ }
350
+ /**
351
+ * Returns true if the given profile name is a provider-specific profile (either in the static PROVIDER_PROFILES table or registered by a provider module). Used
352
+ * by user profile validation to prevent users from extending provider-specific profiles that are tightly coupled to a streaming service's DOM structure.
353
+ * @param name - The profile name to check.
354
+ * @returns True if the profile is a provider profile.
355
+ */
356
+ export function isProviderProfile(name) {
357
+ return (name in PROVIDER_PROFILES) || providerModuleProfiles.has(name);
358
+ }
359
+ /**
360
+ * Returns all registered provider module profiles as an iterable of [name, profile] pairs. Used by the validation system to include dynamically registered
361
+ * profiles in inheritance chain checks.
362
+ * @returns Iterable of [name, SiteProfile] pairs.
363
+ */
364
+ export function getRegisteredProviderModuleProfiles() {
365
+ return providerModuleProfiles.entries();
366
+ }
394
367
  /* The default profile provides baseline behavior for sites not explicitly listed in the domain mapping or channel definitions. These settings work for most
395
368
  * standard HTML5 video players that follow common conventions. Each flag is explicitly set to its default value for documentation purposes and to ensure
396
369
  * predictable behavior - we don't rely on implicit defaults.
@@ -415,6 +388,8 @@ export const DEFAULT_SITE_PROFILE = {
415
388
  clickSelector: null,
416
389
  // Don't click to play - most sites start automatically or via other mechanisms.
417
390
  clickToPlay: false,
391
+ // No dismiss selector - most sites don't show intermittent modals.
392
+ dismissSelector: null,
418
393
  // No fullscreen key - many players work without explicit fullscreen.
419
394
  fullscreenKey: null,
420
395
  // No fullscreen button selector - most sites don't have a dedicated fullscreen button we need to click.
@@ -433,6 +408,8 @@ export const DEFAULT_SITE_PROFILE = {
433
408
  selectReadyVideo: false,
434
409
  // Don't use requestFullscreen() API.
435
410
  useRequestFullscreen: false,
411
+ // No per-domain video timeout override - use the global default.
412
+ videoTimeout: null,
436
413
  // Don't wait for network idle - assume player is ready on page load.
437
414
  waitForNetworkIdle: false
438
415
  };
@@ -1 +1 @@
1
- {"version":3,"file":"sites.js","sourceRoot":"","sources":["../../src/config/sites.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sites.js","sourceRoot":"","sources":["../../src/config/sites.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,MAAM,aAAa,GAAgC;IAExD,gKAAgK;IAChK,mKAAmK;IACnK,qJAAqJ;IACrJ,aAAa,EAAE;QAEb,QAAQ,EAAE,cAAc;QACxB,gBAAgB,EAAE,EAAE,aAAa,EAAE,2BAA2B,EAAE,QAAQ,EAAE,WAAW,EAAE;QACvF,WAAW,EAAE,sJAAsJ;QACnK,OAAO,EAAE,eAAe;QACxB,gBAAgB,EAAE,IAAI;QACtB,OAAO,EAAE,iDAAiD;KAC3D;IAED,6JAA6J;IAC7J,iKAAiK;IACjK,6JAA6J;IAC7J,mJAAmJ;IACnJ,UAAU,EAAE;QAEV,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,yEAAyE;QACtF,OAAO,EAAE,eAAe;QACxB,gBAAgB,EAAE,IAAI;QACtB,OAAO,EAAE,mCAAmC;QAC5C,kBAAkB,EAAE,IAAI;KACzB;IAED,iKAAiK;IACjK,wIAAwI;IACxI,cAAc,EAAE;QAEd,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,IAAI;QACjB,WAAW,EAAE,6HAA6H;QAC1I,OAAO,EAAE,eAAe;QACxB,OAAO,EAAE,gCAAgC;KAC1C;IAED,iKAAiK;IACjK,yHAAyH;IACzH,mBAAmB,EAAE;QAEnB,QAAQ,EAAE,UAAU;QACpB,WAAW,EAAE,IAAI;QACjB,WAAW,EAAE,0HAA0H;QACvI,OAAO,EAAE,oBAAoB;QAC7B,OAAO,EAAE,oCAAoC;KAC9C;IAED,wJAAwJ;IACxJ,yJAAyJ;IACzJ,yBAAyB,EAAE;QAEzB,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,mFAAmF;QAChG,OAAO,EAAE,gBAAgB;QACzB,gBAAgB,EAAE,IAAI;QACtB,OAAO,EAAE,qCAAqC;QAC9C,kBAAkB,EAAE,IAAI;KACzB;IAED,gKAAgK;IAChK,yJAAyJ;IACzJ,cAAc,EAAE;QAEd,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,6EAA6E;QAC1F,OAAO,EAAE,eAAe;QACxB,mBAAmB,EAAE,IAAI;QACzB,OAAO,EAAE,yBAAyB;KACnC;IAED,gKAAgK;IAChK,mKAAmK;IACnK,gDAAgD;IAChD,kBAAkB,EAAE;QAElB,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,uEAAuE;QACpF,OAAO,EAAE,gBAAgB;QACzB,oBAAoB,EAAE,IAAI;QAC1B,OAAO,EAAE,iCAAiC;KAC3C;IAED,+JAA+J;IAC/J,gKAAgK;IAChK,gDAAgD;IAChD,aAAa,EAAE;QAEb,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,iEAAiE;QAC9E,OAAO,EAAE,qCAAqC;QAC9C,oBAAoB,EAAE,IAAI;KAC3B;IAED,mKAAmK;IACnK,iKAAiK;IACjK,eAAe,EAAE;QAEf,QAAQ,EAAE,UAAU;QACpB,WAAW,EAAE,oFAAoF;QACjG,OAAO,EAAE,oBAAoB;QAC7B,OAAO,EAAE,oCAAoC;QAC7C,kBAAkB,EAAE,IAAI;KACzB;IAED,8JAA8J;IAC9J,gKAAgK;IAChK,4IAA4I;IAC5I,yBAAyB,EAAE;QAEzB,QAAQ,EAAE,cAAc;QACxB,gBAAgB,EAAE,EAAE,aAAa,EAAE,2BAA2B,EAAE,QAAQ,EAAE,cAAc,EAAE;QAC1F,WAAW,EAAE,kJAAkJ;QAC/J,OAAO,EAAE,iBAAiB;QAC1B,gBAAgB,EAAE,IAAI;QACtB,OAAO,EAAE,+CAA+C;KACzD;IAED,yJAAyJ;IACzJ,iKAAiK;IACjK,kBAAkB,EAAE;QAElB,QAAQ,EAAE,UAAU;QACpB,WAAW,EAAE,yEAAyE;QACtF,aAAa,EAAE,GAAG;QAClB,OAAO,EAAE,6BAA6B;KACvC;IAED,mKAAmK;IACnK,uGAAuG;IACvG,cAAc,EAAE;QAEd,QAAQ,EAAE,UAAU;QACpB,WAAW,EAAE,2DAA2D;QACxE,OAAO,EAAE,oBAAoB;QAC7B,mBAAmB,EAAE,IAAI;QACzB,OAAO,EAAE,qCAAqC;KAC/C;IAED,mKAAmK;IACnK,8HAA8H;IAC9H,kBAAkB,EAAE;QAElB,QAAQ,EAAE,UAAU;QACpB,WAAW,EAAE,yFAAyF;QACtG,OAAO,EAAE,oBAAoB;QAC7B,gBAAgB,EAAE,IAAI;QACtB,OAAO,EAAE,wCAAwC;KAClD;IAED,2JAA2J;IAC3J,kKAAkK;IAClK,UAAU,EAAE;QAEV,QAAQ,EAAE,SAAS;QACnB,WAAW,EAAE,qEAAqE;QAClF,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,yBAAyB;KACnC;CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAgC;IAE5D,wJAAwJ;IACxJ,SAAS,EAAE;QAET,QAAQ,EAAE,KAAK;QACf,aAAa,EAAE,yBAAyB;QACxC,WAAW,EAAE,wEAAwE;QACrF,OAAO,EAAE,gBAAgB;QACzB,gBAAgB,EAAE,IAAI;QACtB,OAAO,EAAE,kBAAkB;KAC5B;IAED,gKAAgK;IAChK,kKAAkK;IAClK,oKAAoK;IACpK,kKAAkK;IAClK,kEAAkE;IAClE,UAAU,EAAE;QAEV,QAAQ,EAAE,cAAc;QACxB,gBAAgB,EAAE;YAEhB,aAAa,EAAE,2BAA2B,EAAE,YAAY,EAAE,uDAAuD;YACjH,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW;SAC5C;QACD,WAAW,EAAE,2IAA2I;QACxJ,OAAO,EAAE,eAAe;QACxB,YAAY,EAAE,4BAA4B;QAC1C,gBAAgB,EAAE,IAAI;QACtB,OAAO,EAAE,8CAA8C;KACxD;CACF,CAAC;AAGF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,aAAa,GAAiC;IAEzD,SAAS,EAAE,EAAE,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,SAAS,EAAE;IACjE,UAAU,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,KAAK,EAAE;IACzD,SAAS,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC5D,YAAY,EAAE,EAAE,eAAe,EAAE,sCAAsC,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE;IACxH,SAAS,EAAE,EAAE,eAAe,EAAE,mBAAmB,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE;IACnG,UAAU,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,UAAU,EAAE;IAC9D,SAAS,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC5D,eAAe,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE;IAChE,gBAAgB,EAAE,EAAE,OAAO,EAAE,4HAA4H;QACvJ,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE;IACzE,UAAU,EAAE,EAAE,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,UAAU,EAAE;IACnE,iBAAiB,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE;IACzE,SAAS,EAAE,EAAE,QAAQ,EAAE,qBAAqB,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE;IAC9G,iBAAiB,EAAE,EAAE,OAAO,EAAE,2BAA2B,EAAE,QAAQ,EAAE,cAAc,EAAE;IACrF,aAAa,EAAE,EAAE,OAAO,EAAE,2BAA2B,EAAE,QAAQ,EAAE,UAAU,EAAE;IAC7E,eAAe,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,YAAY,EAAE;IACrE,cAAc,EAAE,EAAE,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,WAAW,EAAE;IACxE,cAAc,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,UAAU,EAAE;IAClE,QAAQ,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,KAAK,EAAE;IACvD,iBAAiB,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE;IACzE,YAAY,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE;IAC/E,aAAa,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,aAAa,EAAE;IACpE,UAAU,EAAE,EAAE,OAAO,EAAE,wDAAwD,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE;IAC7I,kBAAkB,EAAE,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,eAAe,EAAE;IAC5E,QAAQ,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,QAAQ,EAAE;IAC5D,gBAAgB,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,UAAU,EAAE;IACpE,wBAAwB,EAAE,EAAE,OAAO,EAAE,2BAA2B,EAAE,QAAQ,EAAE,SAAS,EAAE;IACvF,SAAS,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC5D,SAAS,EAAE,EAAE,qBAAqB,EAAE,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,SAAS,EAAE;IACxF,mBAAmB,EAAE,EAAE,eAAe,EAAE,YAAY,EAAE,OAAO,EAAE,6EAA6E;QAC1I,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE;IAClF,WAAW,EAAE,EAAE,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,UAAU,EAAE;IACpE,WAAW,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,OAAO,EAAE;IAC5D,oBAAoB,EAAE,EAAE,QAAQ,EAAE,4BAA4B,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,SAAS,EAAE;IAC9I,SAAS,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC5D,cAAc,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,KAAK,EAAE;IAC7D,WAAW,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,OAAO,EAAE;IAC5D,gBAAgB,EAAE,EAAE,OAAO,EAAE,2DAA2D,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE;IAC7J,gBAAgB,EAAE,EAAE,OAAO,EAAE,6FAA6F;QACxH,OAAO,EAAE,2BAA2B,EAAE,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,EAAE;IACrF,SAAS,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC5D,iBAAiB,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE;IACvF,oBAAoB,EAAE,EAAE,OAAO,EAAE,uEAAuE,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa;QACpJ,WAAW,EAAE,UAAU,EAAE;IAC3B,qBAAqB,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,UAAU,EAAE;IACzE,iBAAiB,EAAE,EAAE,OAAO,EAAE,iEAAiE,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,gBAAgB;QAC/I,WAAW,EAAE,KAAK,EAAE;IACtB,iBAAiB,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE;IACrE,WAAW,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE;IACzD,UAAU,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,EAAE;IAC1D,aAAa,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,SAAS,EAAE;IAC/F,aAAa,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,SAAS,EAAE;CACnE,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IAEzC,wJAAwJ;IACxJ,4HAA4H;IAC5H,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,IAAI,CAAC;QAEH,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;QAEvC,gDAAgD;QAChD,MAAM,iBAAiB,GAAG,WAAW,CAAC,QAAQ,CAA6B,CAAC;QAE5E,IAAG,iBAAiB,EAAE,CAAC;YAErB,OAAO,iBAAiB,CAAC;QAC3B,CAAC;QAED,iHAAiH;QACjH,MAAM,aAAa,GAAG,aAAa,CAAC,QAAQ,CAA6B,CAAC;QAE1E,IAAG,aAAa,EAAE,CAAC;YAEjB,OAAO,aAAa,CAAC;QACvB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QAEP,uDAAuD;IACzD,CAAC;IAED,MAAM,aAAa,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAEzC,2CAA2C;IAC3C,MAAM,gBAAgB,GAAG,WAAW,CAAC,aAAa,CAA6B,CAAC;IAEhF,IAAG,gBAAgB,EAAE,CAAC;QAEpB,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,OAAO,aAAa,CAAC,aAAa,CAA6B,CAAC;AAClE,CAAC;AAED,iKAAiK;AACjK,mKAAmK;AACnK,MAAM,sBAAsB,GAAG,IAAI,GAAG,EAAuB,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAAC,IAAY,EAAE,OAAoB;IAE9E,IAAG,CAAC,IAAI,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,IAAI,iBAAiB,CAAC,EAAE,CAAC;QAE1D,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,IAAI,GAAG,uEAAuE,CAAC,CAAC;IAChI,CAAC;IAED,sBAAsB,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAE5C,OAAQ,aAAa,CAAC,IAAI,CAA6B,IAAK,iBAAiB,CAAC,IAAI,CAA6B,IAAI,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACtJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAE5C,OAAO,CAAC,IAAI,IAAI,iBAAiB,CAAC,IAAI,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACzE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mCAAmC;IAEjD,OAAO,sBAAsB,CAAC,OAAO,EAAE,CAAC;AAC1C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAAwB;IAEvD,6DAA6D;IAC7D,gBAAgB,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;IAEtC,0EAA0E;IAC1E,eAAe,EAAE,IAAI;IAErB,oFAAoF;IACpF,aAAa,EAAE,IAAI;IAEnB,gFAAgF;IAChF,WAAW,EAAE,KAAK;IAElB,mEAAmE;IACnE,eAAe,EAAE,IAAI;IAErB,qEAAqE;IACrE,aAAa,EAAE,IAAI;IAEnB,wGAAwG;IACxG,kBAAkB,EAAE,IAAI;IAExB,mFAAmF;IACnF,YAAY,EAAE,IAAI;IAElB,qEAAqE;IACrE,oBAAoB,EAAE,KAAK;IAE3B,wEAAwE;IACxE,qBAAqB,EAAE,IAAI;IAE3B,2DAA2D;IAC3D,mBAAmB,EAAE,KAAK;IAE1B,iDAAiD;IACjD,OAAO,EAAE,KAAK;IAEd,0DAA0D;IAC1D,gBAAgB,EAAE,KAAK;IAEvB,qCAAqC;IACrC,oBAAoB,EAAE,KAAK;IAE3B,iEAAiE;IACjE,YAAY,EAAE,IAAI;IAElB,qEAAqE;IACrE,kBAAkB,EAAE,KAAK;CAC1B,CAAC"}
@@ -39,8 +39,10 @@ export declare function getChannelsParseErrorMessage(): string | undefined;
39
39
  export declare function loadUserChannels(): Promise<UserChannelsLoadResult>;
40
40
  /**
41
41
  * Saves user channels to the channels file and updates the in-memory cache. Changes take effect immediately for new stream requests without requiring a server
42
- * restart. Creates the data directory if it doesn't exist. Provider selections are also saved if any exist. Empty deltas (no overridden fields) for predefined
43
- * channel keys are stripped before saving to avoid storing no-op entries.
42
+ * restart. Creates the data directory if it doesn't exist. Provider selections are also saved if any exist. No-op deltas for predefined channel keys are
43
+ * normalized before saving: fields that match the predefined value or null-clear a field the predefined doesn't have are stripped. If the delta becomes empty
44
+ * after normalization, the entry is removed entirely. This ensures that any code path that writes deltas (inline edit, auto-number, browse modal, full edit)
45
+ * produces clean channels.json output without each handler needing to optimize its own delta.
44
46
  * @param channels - The channels to save (full definitions or delta overrides).
45
47
  * @throws If the file cannot be written.
46
48
  */
@@ -85,6 +87,9 @@ export declare function resolveStoredChannel(key: string, stored: StoredChannel)
85
87
  *
86
88
  * Override entries produce a new resolved Channel object (via resolveStoredChannel()), which is a different reference from PREDEFINED_CHANNELS[key]. The provider
87
89
  * system (providers.ts) relies on this reference difference to detect user overrides via isUserOverride(). Predefined-only entries preserve the original reference.
90
+ *
91
+ * The returned channel field is provider-resolved: when a non-default provider is selected for a channel, the entry's channel reflects the selected variant's URL,
92
+ * channelSelector, stationId, and channelNumber. The entry's key always remains the canonical key.
88
93
  * @returns Sorted array of channel listing entries.
89
94
  */
90
95
  export declare function getChannelListing(): ChannelListingEntry[];
@@ -111,6 +116,44 @@ export declare function getPredefinedChannel(key: string): Channel | undefined;
111
116
  * @returns True if the channel is predefined.
112
117
  */
113
118
  export declare function isPredefinedChannel(key: string): boolean;
119
+ /**
120
+ * Returns the East canonical key for a Pacific channel. Pacific canonicals are auto-generated by generatePacificDefinitions with a "p" suffix (e.g., "disneyp"
121
+ * from "disney"). When a Pacific canonical's logo or other brand-level metadata is unavailable, the East counterpart provides a fallback. Returns undefined
122
+ * when the key is not a Pacific canonical (doesn't end with "p" or the base key isn't predefined).
123
+ * @param key - The channel key to check.
124
+ * @returns The East canonical key if this is a Pacific channel, undefined otherwise.
125
+ */
126
+ export declare function getEastCanonicalKey(key: string): string | undefined;
127
+ /**
128
+ * Bulk-populates the logo cache from a stationId-to-URL map. Called by showInfo.ts after fetching logo data from the DVR. Existing entries are overwritten with
129
+ * fresh data to pick up any logo URL changes (e.g., network rebrands).
130
+ * @param logos - Map of Gracenote station ID to logo URL.
131
+ */
132
+ export declare function setChannelLogos(logos: Map<string, string>): void;
133
+ /**
134
+ * Sets a single logo cache entry. Called by showInfo.ts after a TMS station name search for a single channel (tier 2 population or channel add/edit).
135
+ * @param stationId - The Gracenote station ID.
136
+ * @param url - The logo URL.
137
+ */
138
+ export declare function setChannelLogo(stationId: string, url: string): void;
139
+ /**
140
+ * Clears the logo cache. Called on shutdown to release memory.
141
+ */
142
+ export declare function clearChannelLogos(): void;
143
+ /**
144
+ * Resolves a channel key to its effective Gracenote station ID. Pacific channels (e.g., "bravop") resolve to their east counterpart's station ID since
145
+ * they share the same brand logo. User channel overrides that change the stationId are reflected. Returns undefined if the channel has no stationId.
146
+ * @param channelKey - The channel key to resolve (e.g., "amc", "bravop").
147
+ * @returns The Gracenote station ID, or undefined.
148
+ */
149
+ export declare function getChannelStationId(channelKey: string): string | undefined;
150
+ /**
151
+ * Returns the logo URL for a channel from the cache. Pacific channels (e.g., "bravop") are resolved to their east counterpart automatically. The cache is
152
+ * populated by showInfo.ts from the Channels DVR API - this function only reads from it.
153
+ * @param channelKey - The channel key to look up (e.g., "amc", "bravop"). Pacific keys resolve to their east variant internally.
154
+ * @returns The logo URL if cached, undefined otherwise.
155
+ */
156
+ export declare function getChannelLogo(channelKey: string): string | undefined;
114
157
  /**
115
158
  * Checks if a channel key exists in the user channels.
116
159
  * @param key - The channel key to check.
@@ -180,6 +223,14 @@ export declare function isChannelAvailable(key: string): boolean;
180
223
  * @returns Error message if invalid, undefined if valid.
181
224
  */
182
225
  export declare function validateChannelKey(key: string, isNew: boolean): string | undefined;
226
+ /**
227
+ * Validates a channel number for range and uniqueness. Returns an error message if invalid, undefined if valid. Empty string means no channel number (valid).
228
+ * This is the single source of truth for channel number validation, shared by the full edit handler and the inline-edit handler.
229
+ * @param value - The channel number as a string (from form input or inline edit). Empty means "no number."
230
+ * @param excludeKey - The channel key being edited, excluded from the duplicate check.
231
+ * @returns Error message if invalid, undefined if valid.
232
+ */
233
+ export declare function validateChannelNumber(value: string, excludeKey: string): string | undefined;
183
234
  /**
184
235
  * Validates a channel URL.
185
236
  * @param url - The URL to validate.