prismcast 1.5.2 → 1.6.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 (158) 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/channelSelection.js +14 -2
  6. package/dist/browser/channelSelection.js.map +1 -1
  7. package/dist/browser/index.d.ts +23 -9
  8. package/dist/browser/index.js +205 -88
  9. package/dist/browser/index.js.map +1 -1
  10. package/dist/browser/precaching.js +3 -3
  11. package/dist/browser/precaching.js.map +1 -1
  12. package/dist/browser/tuning/directv.js +13 -0
  13. package/dist/browser/tuning/directv.js.map +1 -1
  14. package/dist/browser/tuning/fox.js +12 -0
  15. package/dist/browser/tuning/fox.js.map +1 -1
  16. package/dist/browser/tuning/hbo.js +11 -0
  17. package/dist/browser/tuning/hbo.js.map +1 -1
  18. package/dist/browser/tuning/hulu.js +23 -0
  19. package/dist/browser/tuning/hulu.js.map +1 -1
  20. package/dist/browser/tuning/sling.js +34 -4
  21. package/dist/browser/tuning/sling.js.map +1 -1
  22. package/dist/browser/tuning/spectrum.js +12 -0
  23. package/dist/browser/tuning/spectrum.js.map +1 -1
  24. package/dist/browser/tuning/xfinity.d.ts +2 -0
  25. package/dist/browser/tuning/xfinity.js +607 -0
  26. package/dist/browser/tuning/xfinity.js.map +1 -0
  27. package/dist/browser/tuning/youtubeTv.js +14 -0
  28. package/dist/browser/tuning/youtubeTv.js.map +1 -1
  29. package/dist/browser/video.d.ts +2 -0
  30. package/dist/browser/video.js +99 -17
  31. package/dist/browser/video.js.map +1 -1
  32. package/dist/channels/index.js +173 -56
  33. package/dist/channels/index.js.map +1 -1
  34. package/dist/config/health.d.ts +28 -28
  35. package/dist/config/health.js +52 -52
  36. package/dist/config/health.js.map +1 -1
  37. package/dist/config/paths.d.ts +12 -0
  38. package/dist/config/paths.js +16 -0
  39. package/dist/config/paths.js.map +1 -1
  40. package/dist/config/profiles.d.ts +3 -2
  41. package/dist/config/profiles.js +45 -34
  42. package/dist/config/profiles.js.map +1 -1
  43. package/dist/config/providers.d.ts +7 -0
  44. package/dist/config/providers.js +14 -0
  45. package/dist/config/providers.js.map +1 -1
  46. package/dist/config/sites.d.ts +28 -0
  47. package/dist/config/sites.js +93 -122
  48. package/dist/config/sites.js.map +1 -1
  49. package/dist/config/userChannels.d.ts +3 -0
  50. package/dist/config/userChannels.js +10 -3
  51. package/dist/config/userChannels.js.map +1 -1
  52. package/dist/config/userConfig.d.ts +1 -0
  53. package/dist/config/userConfig.js +4 -0
  54. package/dist/config/userConfig.js.map +1 -1
  55. package/dist/config/userProfiles.d.ts +0 -1
  56. package/dist/config/userProfiles.js +18 -10
  57. package/dist/config/userProfiles.js.map +1 -1
  58. package/dist/index.js +16 -7
  59. package/dist/index.js.map +1 -1
  60. package/dist/native/decrypt.d.ts +32 -0
  61. package/dist/native/decrypt.js +85 -0
  62. package/dist/native/decrypt.js.map +1 -0
  63. package/dist/native/index.d.ts +58 -0
  64. package/dist/native/index.js +341 -0
  65. package/dist/native/index.js.map +1 -0
  66. package/dist/native/intercept.d.ts +35 -0
  67. package/dist/native/intercept.js +184 -0
  68. package/dist/native/intercept.js.map +1 -0
  69. package/dist/native/probe.d.ts +48 -0
  70. package/dist/native/probe.js +270 -0
  71. package/dist/native/probe.js.map +1 -0
  72. package/dist/native/proxy.d.ts +52 -0
  73. package/dist/native/proxy.js +904 -0
  74. package/dist/native/proxy.js.map +1 -0
  75. package/dist/routes/config/channels/table.js +19 -25
  76. package/dist/routes/config/channels/table.js.map +1 -1
  77. package/dist/routes/config/providers.js +4 -4
  78. package/dist/routes/config/providers.js.map +1 -1
  79. package/dist/routes/debug.js +5 -5
  80. package/dist/routes/debug.js.map +1 -1
  81. package/dist/routes/hls.js +12 -2
  82. package/dist/routes/hls.js.map +1 -1
  83. package/dist/routes/index.d.ts +1 -0
  84. package/dist/routes/index.js +3 -0
  85. package/dist/routes/index.js.map +1 -1
  86. package/dist/routes/root/content.js +80 -20
  87. package/dist/routes/root/content.js.map +1 -1
  88. package/dist/routes/root/scripts/status.js +14 -13
  89. package/dist/routes/root/scripts/status.js.map +1 -1
  90. package/dist/routes/root/styles.js +4 -2
  91. package/dist/routes/root/styles.js.map +1 -1
  92. package/dist/streaming/fmp4Segmenter.d.ts +3 -0
  93. package/dist/streaming/fmp4Segmenter.js +143 -42
  94. package/dist/streaming/fmp4Segmenter.js.map +1 -1
  95. package/dist/streaming/hls.d.ts +24 -19
  96. package/dist/streaming/hls.js +486 -261
  97. package/dist/streaming/hls.js.map +1 -1
  98. package/dist/streaming/hlsResume.d.ts +7 -0
  99. package/dist/streaming/hlsResume.js +22 -2
  100. package/dist/streaming/hlsResume.js.map +1 -1
  101. package/dist/streaming/hlsSegments.d.ts +42 -2
  102. package/dist/streaming/hlsSegments.js +109 -8
  103. package/dist/streaming/hlsSegments.js.map +1 -1
  104. package/dist/streaming/lifecycle.js +20 -2
  105. package/dist/streaming/lifecycle.js.map +1 -1
  106. package/dist/streaming/monitor.d.ts +1 -0
  107. package/dist/streaming/monitor.js +369 -21
  108. package/dist/streaming/monitor.js.map +1 -1
  109. package/dist/streaming/mp4Parser.d.ts +52 -6
  110. package/dist/streaming/mp4Parser.js +156 -30
  111. package/dist/streaming/mp4Parser.js.map +1 -1
  112. package/dist/streaming/mpegts.d.ts +2 -2
  113. package/dist/streaming/mpegts.js +156 -109
  114. package/dist/streaming/mpegts.js.map +1 -1
  115. package/dist/streaming/playlistBuilder.d.ts +38 -0
  116. package/dist/streaming/playlistBuilder.js +66 -0
  117. package/dist/streaming/playlistBuilder.js.map +1 -0
  118. package/dist/streaming/preroll.d.ts +106 -0
  119. package/dist/streaming/preroll.js +373 -0
  120. package/dist/streaming/preroll.js.map +1 -0
  121. package/dist/streaming/pretune.d.ts +8 -0
  122. package/dist/streaming/pretune.js +226 -0
  123. package/dist/streaming/pretune.js.map +1 -0
  124. package/dist/streaming/registry.d.ts +24 -3
  125. package/dist/streaming/registry.js +23 -1
  126. package/dist/streaming/registry.js.map +1 -1
  127. package/dist/streaming/setup.d.ts +7 -0
  128. package/dist/streaming/setup.js +27 -6
  129. package/dist/streaming/setup.js.map +1 -1
  130. package/dist/streaming/showInfo.d.ts +24 -0
  131. package/dist/streaming/showInfo.js +55 -3
  132. package/dist/streaming/showInfo.js.map +1 -1
  133. package/dist/streaming/statusEmitter.d.ts +6 -4
  134. package/dist/streaming/statusEmitter.js +9 -3
  135. package/dist/streaming/statusEmitter.js.map +1 -1
  136. package/dist/types/channels.d.ts +1 -0
  137. package/dist/types/index.d.ts +1 -1
  138. package/dist/types/profiles.d.ts +8 -1
  139. package/dist/types/selection.d.ts +4 -1
  140. package/dist/types/streaming.d.ts +7 -0
  141. package/dist/utils/chromeFetch.d.ts +20 -0
  142. package/dist/utils/chromeFetch.js +43 -0
  143. package/dist/utils/chromeFetch.js.map +1 -0
  144. package/dist/utils/debugFilter.js +15 -0
  145. package/dist/utils/debugFilter.js.map +1 -1
  146. package/dist/utils/delay.d.ts +16 -0
  147. package/dist/utils/delay.js +15 -1
  148. package/dist/utils/delay.js.map +1 -1
  149. package/dist/utils/ffmpeg.d.ts +1 -7
  150. package/dist/utils/ffmpeg.js +86 -127
  151. package/dist/utils/ffmpeg.js.map +1 -1
  152. package/dist/utils/index.d.ts +2 -0
  153. package/dist/utils/index.js +2 -0
  154. package/dist/utils/index.js.map +1 -1
  155. package/dist/utils/pid.d.ts +40 -0
  156. package/dist/utils/pid.js +83 -0
  157. package/dist/utils/pid.js.map +1 -0
  158. package/package.json +5 -5
@@ -0,0 +1,607 @@
1
+ import { LOG, delay, formatError } from "../../utils/index.js";
2
+ import { CONFIG } from "../../config/index.js";
3
+ import { logAvailableChannels } from "../channelSelection.js";
4
+ /* Xfinity Stream uses a Polymer SPA (`TV-APP`) that manages channel playback via an internal `channelMap` object. The `channelMap.channels` property is populated
5
+ * from the channelmap API during page load and contains the complete channel lineup (~1389 entries). Calling `_watchChannelEventHandler(null, { channel })` on the
6
+ * `TV-APP` element switches channels in-page in ~2-3 seconds — matching native browser performance. This avoids the ~15-second cost of full page navigation.
7
+ *
8
+ * The channelmap API at xtvapi.cloudtv.comcast.net returns the complete channel lineup in a single response during guide page load. We intercept this response to
9
+ * populate a Node-side channel cache for name matching and channel discovery. At tune time, the strategy waits for the SPA's `channelMap.channels` to populate,
10
+ * looks up the target channel by callSign, and invokes `_watchChannelEventHandler` via `page.evaluate()`.
11
+ *
12
+ * Some entertainment channels (e.g., Discovery) display a "Watch Now" modal button after the SPA switches channels. A fire-and-forget poll detects and clicks this
13
+ * button concurrently with `waitForVideoReady`. News channels (e.g., CNN) auto-play without any modal.
14
+ *
15
+ * Tuning flow:
16
+ * 1. resolveDirectUrl: sets up channelmap API interception and returns null. On warm tunes, also enables CDP request interception to serve the cached channelmap
17
+ * response instantly, eliminating the 3-5s network round-trip.
18
+ * 2. The caller (tuneToChannel in video.ts) navigates to the guide URL, loading the Polymer SPA.
19
+ * 3. xfinityDirectStrategy: waits for `TV-APP.channelMap.channels` to populate, finds the target channel by callSign, and calls `_watchChannelEventHandler`.
20
+ * 4. A fire-and-forget poll watches for a visible "Watch Now" modal button and clicks it if it appears.
21
+ * 5. initializePlayback continues with waitForVideoReady, fullscreen, etc.
22
+ */
23
+ // Guide page URL. The channelmap API fires automatically when this page loads.
24
+ const XFINITY_GUIDE_URL = "https://www.xfinity.com/stream/listings";
25
+ // URL pattern for the channelmap API response. Matched against response URLs to identify channelmap data.
26
+ const CHANNELMAP_API_PATTERN = "xtvapi.cloudtv.comcast.net/channelmap";
27
+ // Polling interval for cold-cache wait. 200ms balances responsiveness against CPU overhead.
28
+ const CACHE_POLL_INTERVAL = 200;
29
+ // Broadcast network verbose names from callSignVoiceOverHint, mapped to standard abbreviations. Used to identify local affiliates and set the channelSelector to the
30
+ // network abbreviation rather than the verbose name or callSign.
31
+ const BROADCAST_HINTS = {
32
+ "american broadcasting company": "ABC",
33
+ "columbia broadcasting system": "CBS",
34
+ "fox broadcasting company": "Fox",
35
+ "national broadcasting company": "NBC",
36
+ "public broadcasting service": "PBS"
37
+ };
38
+ // Audio-only channel brand prefixes to skip during channelmap processing. These channels produce static screens with music and are not useful for video capture.
39
+ // Matched against the lowercased branchOf/company/callSign field using prefix comparison to catch genre variants (e.g., "Music Choice Hip-Hop").
40
+ const AUDIO_ONLY_PREFIXES = ["music choice", "stingray"];
41
+ // Common Xfinity callSign suffixes to strip when building secondary cache keys. Stripped in order — the first match is used. Only strip when the result is at least
42
+ // 2 characters to avoid degenerate cases. Intentionally excludes "d" and "h" — those appear as meaningful parts of callSigns (ESPND, BETHH) rather than pure
43
+ // technology suffixes, causing cache key collisions with unrelated channels.
44
+ const CALLSIGN_SUFFIXES = ["str", "hd"];
45
+ // Duration in milliseconds to poll for the Watch Now modal button. Matches the dismiss poll constants in video.ts.
46
+ const WATCH_NOW_POLL_DURATION = 5000;
47
+ // Interval in milliseconds between Watch Now modal poll checks. Matches the dismiss poll constants in video.ts.
48
+ const WATCH_NOW_POLL_INTERVAL = 500;
49
+ // Unified channel cache. Maps lowercased lookup keys to combined discovery and tuning data. Multiple keys may reference the same entry (callSign, stripped callSign,
50
+ // branchOf name). Populated during channelmap API interception or discovery. Cleared on browser disconnect via clearXfinityCache().
51
+ const xfinityChannelCache = new Map();
52
+ // Tracks whether the channel cache has been fully enumerated from a complete channelmap API response. Guards getCachedChannels to avoid returning partial data.
53
+ let xfinityFullyEnumerated = false;
54
+ // Cached channelmap API response for CDP request interception on warm tunes. Stored on the first successful API response. The exact URL and headers are replayed so
55
+ // that only the correct request is intercepted (the SPA makes multiple requests to URLs matching the channelmap pattern, but only one is the actual channel lineup).
56
+ let cachedChannelmapBody = null;
57
+ let cachedChannelmapUrl = null;
58
+ let cachedChannelmapHeaders = {};
59
+ // Tracks which pages have response interception listeners registered to avoid duplicate registrations.
60
+ const pagesWithListeners = new WeakSet();
61
+ /**
62
+ * Strips common Xfinity callSign suffixes to produce a normalized lookup key. Strips the first matching suffix from the end of the callSign, but only when the
63
+ * remaining string is at least 2 characters. Examples: CNNHD→CNN, AESTR→AE.
64
+ * @param callSign - The raw callSign from the channelmap API.
65
+ * @returns The stripped callSign, or the original if no suffix matched or stripping would produce a string shorter than 2 characters.
66
+ */
67
+ function stripCallSignSuffix(callSign) {
68
+ const lower = callSign.toLowerCase();
69
+ for (const suffix of CALLSIGN_SUFFIXES) {
70
+ if (lower.endsWith(suffix) && ((lower.length - suffix.length) >= 2)) {
71
+ return lower.slice(0, -suffix.length);
72
+ }
73
+ }
74
+ return lower;
75
+ }
76
+ /**
77
+ * Caches a single channel entry with multi-key lookups. Creates up to four cache keys per channel: (a) lowercased callSign, (b) stripped callSign with common
78
+ * suffixes removed, (c) lowercased branchOf/company/callSign, and (d) broadcast network abbreviation for local affiliates. All keys use first-write-wins except
79
+ * broadcast network keys, which are unconditionally written so local affiliates override national feeds.
80
+ * @param callSign - The raw callSign string (already validated non-null by caller).
81
+ * @param branchOf - The branchOf/company/callSign value from the API.
82
+ * @param entry - The unified cache entry to store.
83
+ * @param affiliate - The broadcast network abbreviation (e.g., "NBC") or undefined for non-broadcast channels.
84
+ * @returns True if the entry was cached (at least one key written), false if all keys were already occupied.
85
+ */
86
+ function cacheChannelEntry(callSign, branchOf, entry, affiliate) {
87
+ const callSignLower = callSign.toLowerCase();
88
+ let keysWritten = 0;
89
+ // Primary key: lowercased callSign (e.g., "cnnhd").
90
+ if (!xfinityChannelCache.has(callSignLower)) {
91
+ xfinityChannelCache.set(callSignLower, entry);
92
+ keysWritten++;
93
+ }
94
+ // Secondary key: stripped callSign with common suffixes removed (e.g., "cnn" from "cnnhd").
95
+ const strippedKey = stripCallSignSuffix(callSign);
96
+ if ((strippedKey !== callSignLower) && !xfinityChannelCache.has(strippedKey)) {
97
+ xfinityChannelCache.set(strippedKey, entry);
98
+ keysWritten++;
99
+ }
100
+ // Tertiary key: lowercased branchOf/company/callSign (e.g., "cnn", "animal planet").
101
+ if (branchOf) {
102
+ const branchKey = branchOf.toLowerCase();
103
+ if ((branchKey !== callSignLower) && (branchKey !== strippedKey) && !xfinityChannelCache.has(branchKey)) {
104
+ xfinityChannelCache.set(branchKey, entry);
105
+ keysWritten++;
106
+ }
107
+ }
108
+ // Broadcast network key (e.g., "nbc", "abc"). Unconditional write ensures local affiliates override any previously-cached national entry for the same network.
109
+ if (affiliate) {
110
+ xfinityChannelCache.set(affiliate.toLowerCase(), entry);
111
+ keysWritten++;
112
+ }
113
+ return keysWritten > 0;
114
+ }
115
+ /**
116
+ * Processes a channelmap API response and populates the unified channel cache using three-pass tiered filtering. Channels are prioritized: non-TVE HD entitled
117
+ * first (cable HD — optimal for a home-network server), then TVE entitled (fallback for channels without a cable HD entry), then non-TVE SD entitled (safety net
118
+ * for SD-only channels). All passes share a single seenCallSigns set for exact callSign deduplication. Cross-tier dedup is handled naturally by
119
+ * cacheChannelEntry's first-write-wins guards — lower-tier entries cannot overwrite cache keys already occupied by higher-tier entries.
120
+ *
121
+ * Local affiliates are detected via callSignVoiceOverHint matching against BROADCAST_HINTS and preferred over national feeds (e.g., local KOMOD over national
122
+ * WLSD1 for ABC). Local identification uses a pre-scan of non-TVE entries — stations present in the non-TVE lineup are local to the subscriber's market.
123
+ * Sub-feeds (DATLN, TODAY) sharing the same voiceOverHint as the primary affiliate are deduplicated by the broadcast network key guard.
124
+ * @param data - The parsed channelmap API response.
125
+ */
126
+ function processChannelmapResponse(data) {
127
+ const channels = data._embedded?.channels;
128
+ if (!Array.isArray(channels)) {
129
+ return;
130
+ }
131
+ // Pre-scan for non-TVE local broadcast callSigns. These identify which entries are local affiliates vs national feeds. Non-TVE entries are always local to the
132
+ // subscriber's market, so an entry whose callSign also appears in the non-TVE lineup is the local affiliate for that broadcast network.
133
+ const localBroadcastCallSigns = new Set();
134
+ for (const channel of channels) {
135
+ if (channel.isTve || !channel.callSign || !channel.callSignVoiceOverHint) {
136
+ continue;
137
+ }
138
+ const hint = channel.callSignVoiceOverHint.toLowerCase();
139
+ if (BROADCAST_HINTS[hint]) {
140
+ localBroadcastCallSigns.add(channel.callSign.toLowerCase());
141
+ }
142
+ }
143
+ // Track callSigns we have already processed to enforce first-write-wins deduplication across all passes.
144
+ const seenCallSigns = new Set();
145
+ let count = 0;
146
+ // Three-pass tiered filtering. Each pass processes channels matching specific criteria. All passes share seenCallSigns for exact callSign dedup and use the
147
+ // same entry creation and caching logic. Cross-tier dedup is handled by cacheChannelEntry's first-write-wins guards on stripped callSign and branchOf keys.
148
+ const passes = [
149
+ // Pass 1: Non-TVE HD entitled. Cable HD channels — the primary version for a home-network server. Includes channels like PBS (KCTSD) and CW (KSTWD) that
150
+ // have no TVE entries at all, plus HD cable variants of channels that also have TVE entries.
151
+ { filter: (ch) => !ch.isTve && (ch.isHD === true) && (ch.entitled === true) },
152
+ // Pass 2: TVE entitled. TV Everywhere channels that work from any network. Serves as fallback for channels without a cable HD entry.
153
+ { filter: (ch) => (ch.isTve === true) && (ch.entitled === true) },
154
+ // Pass 3: Non-TVE SD entitled. Safety net for SD-only channels with no HD or TVE variant (e.g., PBS World, local digital subchannels).
155
+ { filter: (ch) => !ch.isTve && !ch.isHD && (ch.entitled === true) }
156
+ ];
157
+ for (const pass of passes) {
158
+ for (const channel of channels) {
159
+ if (!channel.callSign || !pass.filter(channel)) {
160
+ continue;
161
+ }
162
+ const callSignLower = channel.callSign.toLowerCase();
163
+ // Deduplicate by callSign — first occurrence wins (typically the lowest channel number).
164
+ if (seenCallSigns.has(callSignLower)) {
165
+ continue;
166
+ }
167
+ seenCallSigns.add(callSignLower);
168
+ // Skip audio-only channels (Music Choice, Stingray) — they produce static screens with music and are not useful for video capture.
169
+ const branchOf = channel["branchOf/company/callSign"] ?? "";
170
+ const branchLower = branchOf.toLowerCase();
171
+ if (AUDIO_ONLY_PREFIXES.some((prefix) => branchLower.startsWith(prefix))) {
172
+ continue;
173
+ }
174
+ // Determine the display name. For broadcast affiliates identified by callSignVoiceOverHint, use the network abbreviation. For cable channels, use the
175
+ // branchOf/company/callSign value (the network's display name). The channelSelector always uses the raw callSign for guaranteed uniqueness — branchOf
176
+ // names like "Cinemax" or "BET" are shared across multiple distinct channels (MAXHD, MXPLD, MXACD, etc.).
177
+ const voiceOverHint = (channel.callSignVoiceOverHint ?? "").toLowerCase();
178
+ let displayName = (branchOf.length > 0) ? branchOf : (channel.callSignVoiceOverHint ?? channel.callSign);
179
+ let affiliate;
180
+ const broadcastNetwork = BROADCAST_HINTS[voiceOverHint];
181
+ if (broadcastNetwork) {
182
+ // Broadcast affiliate handling: prefer local affiliates over national feeds. The channelmap API may include both a national feed (e.g., WLSD1 for
183
+ // ABC) and the subscriber's local affiliate (e.g., KOMOD for ABC). We identify local affiliates by checking whether their callSign appears in the
184
+ // non-TVE entries, which are always local to the subscriber's market.
185
+ const networkKey = broadcastNetwork.toLowerCase();
186
+ const isLocal = localBroadcastCallSigns.has(callSignLower);
187
+ const existingEntry = xfinityChannelCache.get(networkKey);
188
+ if (existingEntry) {
189
+ // Network already cached. Override only when this entry is a better match: local replacing national, or lower channel number when both are local
190
+ // (e.g., KBTCD ch 108 over KCTSD ch 109 for PBS).
191
+ const existingIsLocal = localBroadcastCallSigns.has(existingEntry.callSign.toLowerCase());
192
+ const newNumber = channel.number ?? Infinity;
193
+ if (!isLocal || (existingIsLocal && (newNumber >= existingEntry.channelNumber))) {
194
+ continue;
195
+ }
196
+ // Better affiliate found: remove the old entry's cache keys so it doesn't appear as a duplicate in channel discovery.
197
+ const oldCallSign = existingEntry.callSign.toLowerCase();
198
+ xfinityChannelCache.delete(oldCallSign);
199
+ const oldStripped = stripCallSignSuffix(existingEntry.callSign);
200
+ if (oldStripped !== oldCallSign) {
201
+ xfinityChannelCache.delete(oldStripped);
202
+ }
203
+ count--;
204
+ }
205
+ displayName = broadcastNetwork;
206
+ affiliate = broadcastNetwork;
207
+ }
208
+ const discovered = {
209
+ ...(affiliate ? { affiliate } : {}),
210
+ channelSelector: channel.callSign,
211
+ name: displayName
212
+ };
213
+ const entry = {
214
+ callSign: channel.callSign,
215
+ channelNumber: channel.number ?? Infinity,
216
+ discovered
217
+ };
218
+ if (cacheChannelEntry(channel.callSign, branchOf, entry, affiliate)) {
219
+ count++;
220
+ }
221
+ }
222
+ }
223
+ if (count > 0) {
224
+ xfinityFullyEnumerated = true;
225
+ LOG.debug("tuning:xfinity", "Channelmap API: cached %s channels (%s cache keys).", count, xfinityChannelCache.size);
226
+ }
227
+ }
228
+ /**
229
+ * Sets up response interception on the page to capture Xfinity's channelmap API response. The API fires automatically on guide page load and returns the complete
230
+ * channel lineup in a single response. Uses a WeakSet to prevent duplicate listener registration on the same page.
231
+ * @param page - The Puppeteer page object.
232
+ */
233
+ function setupChannelmapInterception(page) {
234
+ if (pagesWithListeners.has(page)) {
235
+ return;
236
+ }
237
+ pagesWithListeners.add(page);
238
+ page.on("response", (response) => {
239
+ const url = response.url();
240
+ if (!url.includes(CHANNELMAP_API_PATTERN) || (response.status() !== 200)) {
241
+ return;
242
+ }
243
+ void response.text().then((text) => {
244
+ // Cache the exact URL, headers, and body for CDP request interception on warm tunes. The exact URL ensures we only intercept the correct channelmap request —
245
+ // the SPA makes multiple requests to URLs matching the pattern, but only this one returns the channel lineup. We strip content-encoding and content-length
246
+ // because response.text() returns the decoded (decompressed) body — replaying encoding headers with decoded content would cause double-decompression.
247
+ cachedChannelmapUrl = url;
248
+ cachedChannelmapBody = text;
249
+ const headers = response.headers();
250
+ delete headers["content-encoding"];
251
+ delete headers["content-length"];
252
+ cachedChannelmapHeaders = headers;
253
+ const data = JSON.parse(text);
254
+ processChannelmapResponse(data);
255
+ }).catch(() => {
256
+ // Response parsing failed — cold cache fallback handles it.
257
+ });
258
+ });
259
+ }
260
+ /**
261
+ * Looks up a channel in the unified cache using three-tier matching:
262
+ *
263
+ * 1. Exact match: cache key equals the lowercased input (matches callSigns, stripped callSigns, and branchOf names).
264
+ * 2. Suffix-tolerant: input + "hd" or input + "d" matches a cache key (e.g., "cnn" → "cnnhd", "espn" → "espnd").
265
+ * 3. Display name iteration: iterate all cache entries, check if discovered.name (lowercased) equals input. Catches verbose display names not covered by cache keys.
266
+ *
267
+ * When a non-exact match succeeds, the result is cached under the input key for O(1) lookup on subsequent calls.
268
+ * @param channelName - The channelSelector value (e.g., "CNN", "CNNHD", "Animal Planet").
269
+ * @returns The matching cache entry or null if no match is found.
270
+ */
271
+ function findXfinityChannel(channelName) {
272
+ const lower = channelName.toLowerCase();
273
+ // Tier 1: Exact match on any cache key (callSigns, stripped names, branchOf names).
274
+ const exact = xfinityChannelCache.get(lower);
275
+ if (exact) {
276
+ return exact;
277
+ }
278
+ // Tier 2: Suffix-tolerant. Try appending common technology suffixes.
279
+ const hdMatch = xfinityChannelCache.get(lower + "hd");
280
+ if (hdMatch) {
281
+ xfinityChannelCache.set(lower, hdMatch);
282
+ return hdMatch;
283
+ }
284
+ const dMatch = xfinityChannelCache.get(lower + "d");
285
+ if (dMatch) {
286
+ xfinityChannelCache.set(lower, dMatch);
287
+ return dMatch;
288
+ }
289
+ // Tier 3: Display name iteration. Check if any entry's discovered.name matches the input. This catches verbose display names (e.g., "Cable News Network") that
290
+ // may not have a matching cache key.
291
+ const seen = new Set();
292
+ for (const entry of xfinityChannelCache.values()) {
293
+ if (seen.has(entry)) {
294
+ continue;
295
+ }
296
+ seen.add(entry);
297
+ if (entry.discovered.name.toLowerCase() === lower) {
298
+ xfinityChannelCache.set(lower, entry);
299
+ return entry;
300
+ }
301
+ }
302
+ return null;
303
+ }
304
+ /**
305
+ * Sets up channelmap API interception for the upcoming page navigation and, on warm tunes, enables CDP request interception to serve the cached channelmap response
306
+ * instantly. Like DirecTV's resolveDirectUrl, this always returns null — all tuning happens in the strategy's execute function via `_watchChannelEventHandler`.
307
+ * @param _channelSelector - The channel selector string (unused — channel lookup happens in the strategy).
308
+ * @param page - The Puppeteer page for response interception setup.
309
+ * @returns Always null — no direct URL navigation.
310
+ */
311
+ async function resolveXfinityDirectUrl(_channelSelector, page) {
312
+ // Set up response interception so the channelmap API response is captured during guide page navigation.
313
+ setupChannelmapInterception(page);
314
+ // On warm cache, intercept the channelmap API request and serve the cached response immediately. This eliminates the 3-5s network round-trip on warm tunes. We
315
+ // match on the exact URL captured during the cold tune — the SPA makes multiple requests to URLs matching the channelmap pattern, but only one is the channel lineup.
316
+ if (cachedChannelmapBody && cachedChannelmapUrl) {
317
+ const targetUrl = cachedChannelmapUrl;
318
+ const body = cachedChannelmapBody;
319
+ const headers = cachedChannelmapHeaders;
320
+ await page.setRequestInterception(true);
321
+ page.on("request", (request) => {
322
+ if (request.url() === targetUrl) {
323
+ LOG.debug("tuning:xfinity", "Channelmap API: served from cache.");
324
+ void request.respond({
325
+ body,
326
+ headers,
327
+ status: 200
328
+ }).catch(() => {
329
+ // Serve failed — fall back to the network so the cold-cache path takes over.
330
+ void request.continue().catch(() => {
331
+ // Page closed — ignore.
332
+ });
333
+ });
334
+ return;
335
+ }
336
+ void request.continue().catch(() => {
337
+ // Page closed — ignore.
338
+ });
339
+ });
340
+ }
341
+ return null;
342
+ }
343
+ /**
344
+ * Polls for a visible "Watch Now" modal button and clicks it if found. Some entertainment channels (e.g., Discovery) display this modal after
345
+ * `_watchChannelEventHandler` switches channels. News channels (e.g., CNN) auto-play without any modal. Runs as a fire-and-forget background task alongside
346
+ * `waitForVideoReady` — channels without modals resolve via `waitForVideoReady` alone, while channels with modals get unblocked by the click.
347
+ *
348
+ * The button requires JS-based detection because multiple `button.style-scope.tv-button` elements exist on the page with zero dimensions. We filter by text
349
+ * content ("Watch Now") and non-zero bounding rect to find the visible one.
350
+ * @param page - The Puppeteer page object.
351
+ */
352
+ async function watchNowModalPoll(page) {
353
+ const checks = Math.ceil(WATCH_NOW_POLL_DURATION / WATCH_NOW_POLL_INTERVAL);
354
+ for (let i = 0; i < checks; i++) {
355
+ // Delay between checks, but not before the first one — the first check is immediate.
356
+ if (i > 0) {
357
+ // eslint-disable-next-line no-await-in-loop
358
+ await delay(WATCH_NOW_POLL_INTERVAL);
359
+ }
360
+ try {
361
+ // eslint-disable-next-line no-await-in-loop
362
+ const clicked = await page.evaluate(() => {
363
+ const buttons = Array.from(document.querySelectorAll("button.style-scope.tv-button"));
364
+ for (const button of buttons) {
365
+ const text = button.textContent.trim();
366
+ const rect = button.getBoundingClientRect();
367
+ if ((text === "Watch Now") && (rect.width > 0)) {
368
+ button.click();
369
+ return true;
370
+ }
371
+ }
372
+ return false;
373
+ });
374
+ if (clicked) {
375
+ LOG.debug("tuning:xfinity", "Watch Now modal dismissed.");
376
+ return;
377
+ }
378
+ }
379
+ catch {
380
+ // Page closed or navigated away — exit silently.
381
+ return;
382
+ }
383
+ }
384
+ }
385
+ /**
386
+ * In-page SPA tuning strategy for Xfinity Stream. Waits for the Polymer SPA's `TV-APP` element and its `channelMap.channels` to populate, then invokes
387
+ * `_watchChannelEventHandler(null, { channel })` to switch channels in-page. This is the execute path for both warm and cold cache scenarios — the guide URL
388
+ * navigation loads the SPA, and this strategy performs the channel switch within it.
389
+ * @param page - The Puppeteer page object (on the guide page after SPA load).
390
+ * @param profile - The resolved site profile with a non-null channelSelector.
391
+ * @returns Result object with success status and optional failure reason.
392
+ */
393
+ async function xfinityDirectStrategy(page, profile) {
394
+ const channelName = profile.channelSelector;
395
+ const timeout = CONFIG.streaming.videoTimeout;
396
+ // Wait for the TV-APP Polymer element to be present in the DOM.
397
+ try {
398
+ await page.waitForSelector("tv-app", { timeout });
399
+ }
400
+ catch {
401
+ return { reason: "Xfinity Stream guide page did not load within timeout.", success: false };
402
+ }
403
+ // Wait for the SPA's channelMap.channels to populate. The channelmap API fires during page load and the SPA stores the response in this property.
404
+ try {
405
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-argument,
406
+ @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any */
407
+ await page.waitForFunction(() => {
408
+ const tvApp = document.querySelector("tv-app");
409
+ if (!tvApp) {
410
+ return false;
411
+ }
412
+ const channels = tvApp.channelMap?.channels;
413
+ return channels && (typeof channels === "object") && (Object.keys(channels).length > 0);
414
+ }, { timeout });
415
+ /* eslint-enable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-argument,
416
+ @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any */
417
+ }
418
+ catch {
419
+ // If we served a cached response and the SPA couldn't process it, the cached data is likely stale or corrupt. Clear it so the next tune falls through to a
420
+ // fresh network fetch.
421
+ invalidateCachedResponse();
422
+ return { reason: "Xfinity Stream channel lineup did not load within timeout.", success: false };
423
+ }
424
+ // Poll for Node-side cache population. The channelmap API response is intercepted by setupChannelmapInterception (called by resolveXfinityDirectUrl before we
425
+ // got here). We need the Node-side cache for findXfinityChannel's three-tier matching.
426
+ const deadline = Date.now() + timeout;
427
+ while ((xfinityChannelCache.size === 0) && (Date.now() < deadline)) {
428
+ // eslint-disable-next-line no-await-in-loop
429
+ await delay(CACHE_POLL_INTERVAL);
430
+ }
431
+ if (xfinityChannelCache.size === 0) {
432
+ return { reason: "Xfinity Stream channel lineup API did not respond within timeout.", success: false };
433
+ }
434
+ // Look up the target channel in the Node-side cache.
435
+ const entry = findXfinityChannel(channelName);
436
+ if (!entry) {
437
+ logAvailableChannels({
438
+ availableChannels: buildXfinityDiscoveredChannels().map((ch) => ch.name + " (" + ch.channelSelector + ")").sort(),
439
+ channelName,
440
+ guideUrl: XFINITY_GUIDE_URL,
441
+ presetSuffix: "-xfinity",
442
+ providerName: "Xfinity Stream"
443
+ });
444
+ return { reason: "Channel " + channelName + " was not found in the Xfinity Stream channel lineup.", success: false };
445
+ }
446
+ // Call _watchChannelEventHandler on the TV-APP element to switch channels in-page. The SPA's channelMap.channels is keyed by internal ID tags, not callSigns,
447
+ // so we iterate the values to find the matching callSign.
448
+ const targetCallSign = entry.callSign;
449
+ try {
450
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-argument,
451
+ @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any */
452
+ const found = await page.evaluate((callSign) => {
453
+ const tvApp = document.querySelector("tv-app");
454
+ if (!tvApp) {
455
+ return false;
456
+ }
457
+ const channelMap = tvApp.channelMap?.channels;
458
+ if (!channelMap) {
459
+ return false;
460
+ }
461
+ // Find the channel object by matching callSign. The channelMap is keyed by internal ID tags, so we iterate values.
462
+ for (const channel of Object.values(channelMap)) {
463
+ if (channel?.callSign === callSign) {
464
+ tvApp._watchChannelEventHandler(null, { channel });
465
+ return true;
466
+ }
467
+ }
468
+ return false;
469
+ }, targetCallSign);
470
+ /* eslint-enable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-argument,
471
+ @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any */
472
+ if (!found) {
473
+ // The Node-side cache had this callSign but the SPA's channelMap doesn't — the cached response is stale. Clear it so the next tune fetches fresh data.
474
+ invalidateCachedResponse();
475
+ return { reason: "Channel " + targetCallSign + " is no longer available in the Xfinity Stream channel lineup.", success: false };
476
+ }
477
+ }
478
+ catch (error) {
479
+ return { reason: "Failed to switch Xfinity Stream channel: " + formatError(error) + ".", success: false };
480
+ }
481
+ LOG.debug("tuning:xfinity", "Invoked _watchChannelEventHandler for %s (callSign: %s).", channelName, targetCallSign);
482
+ // Launch fire-and-forget Watch Now modal poll. Some entertainment channels show a modal after channel switch that must be clicked to start playback.
483
+ void watchNowModalPoll(page);
484
+ return { success: true };
485
+ }
486
+ /**
487
+ * Derives a deduplicated DiscoveredChannel array from the unified channel cache. Multiple cache keys may point to the same XfinityChannelEntry, so we deduplicate
488
+ * via Set reference equality. Sorts by name before returning.
489
+ * @returns Sorted, deduplicated array of discovered channels.
490
+ */
491
+ function buildXfinityDiscoveredChannels() {
492
+ const channels = [];
493
+ const seen = new Set();
494
+ for (const entry of xfinityChannelCache.values()) {
495
+ if (seen.has(entry)) {
496
+ continue;
497
+ }
498
+ seen.add(entry);
499
+ channels.push(entry.discovered);
500
+ }
501
+ channels.sort((a, b) => a.name.localeCompare(b.name));
502
+ return channels;
503
+ }
504
+ /**
505
+ * Discovers all channels from Xfinity Stream by navigating to the guide page and intercepting the channelmap API response. Returns cached results if the cache is
506
+ * already fully populated. Sets handlesOwnNavigation so the route handler does not navigate before calling this function.
507
+ * @param page - The Puppeteer page object (fresh page, not yet navigated).
508
+ * @returns Array of discovered channels.
509
+ */
510
+ async function discoverXfinityChannels(page) {
511
+ // Return from cache if already fully enumerated.
512
+ if (xfinityFullyEnumerated && (xfinityChannelCache.size > 0)) {
513
+ return buildXfinityDiscoveredChannels();
514
+ }
515
+ // Set up response interception before navigation so we capture the channelmap API response during page load.
516
+ setupChannelmapInterception(page);
517
+ try {
518
+ await page.goto(XFINITY_GUIDE_URL, { timeout: CONFIG.streaming.navigationTimeout, waitUntil: "networkidle2" });
519
+ }
520
+ catch (error) {
521
+ LOG.warn("Failed to load Xfinity Stream guide page: %s.", formatError(error));
522
+ return [];
523
+ }
524
+ // Poll for cache population.
525
+ const deadline = Date.now() + CONFIG.streaming.videoTimeout;
526
+ while ((xfinityChannelCache.size === 0) && (Date.now() < deadline)) {
527
+ // eslint-disable-next-line no-await-in-loop
528
+ await delay(CACHE_POLL_INTERVAL);
529
+ }
530
+ if (xfinityChannelCache.size === 0) {
531
+ LOG.warn("Xfinity Stream channel lineup did not return any channels.");
532
+ return [];
533
+ }
534
+ return buildXfinityDiscoveredChannels();
535
+ }
536
+ /**
537
+ * Returns cached discovered channels from the unified channel cache, or null if the cache is empty or has not been fully enumerated.
538
+ * @returns Sorted array of discovered channels or null.
539
+ */
540
+ function getXfinityCachedChannels() {
541
+ if (!xfinityFullyEnumerated || (xfinityChannelCache.size === 0)) {
542
+ return null;
543
+ }
544
+ return buildXfinityDiscoveredChannels();
545
+ }
546
+ /**
547
+ * Clears the cached channelmap API response so the next tune fetches fresh data from the network. Called when the strategy detects that the cached response produced
548
+ * a failure — either the SPA couldn't populate channelMap.channels, or a callSign present in the Node-side cache was missing from the SPA's channelMap. The current
549
+ * tune still fails (the channelmap request already fired), but the next tune self-heals via the cold-cache path.
550
+ */
551
+ function invalidateCachedResponse() {
552
+ if (!cachedChannelmapBody) {
553
+ return;
554
+ }
555
+ cachedChannelmapBody = null;
556
+ cachedChannelmapHeaders = {};
557
+ cachedChannelmapUrl = null;
558
+ LOG.debug("tuning:xfinity", "Channelmap API: invalidated cached response — next tune will fetch from network.");
559
+ }
560
+ /**
561
+ * Clears the Xfinity channel cache. Called by clearChannelSelectionCaches() in the coordinator when the browser restarts, since a fresh browser session may have
562
+ * different channel availability.
563
+ */
564
+ function clearXfinityCache() {
565
+ cachedChannelmapBody = null;
566
+ cachedChannelmapHeaders = {};
567
+ cachedChannelmapUrl = null;
568
+ xfinityChannelCache.clear();
569
+ xfinityFullyEnumerated = false;
570
+ }
571
+ /**
572
+ * Invalidates the cached channel entry for the given channel selector. Called when a stream fails to start after tuning, allowing the next tune attempt to
573
+ * re-resolve via fresh channelmap data.
574
+ * @param channelSelector - The channel selector string to invalidate.
575
+ */
576
+ function invalidateXfinityDirectUrl(channelSelector) {
577
+ xfinityChannelCache.delete(channelSelector.toLowerCase());
578
+ }
579
+ export const xfinityProvider = {
580
+ discoverChannels: discoverXfinityChannels,
581
+ getCachedChannels: getXfinityCachedChannels,
582
+ guideUrl: XFINITY_GUIDE_URL,
583
+ handlesOwnNavigation: true,
584
+ label: "Xfinity Stream",
585
+ // Profile for Xfinity Stream (xfinity.com/stream) live channels. The channelmap API at xtvapi.cloudtv.comcast.net returns the complete channel lineup (~1389
586
+ // entries). Tuning uses in-page SPA channel switching: after the guide page loads the Polymer SPA, the strategy calls `_watchChannelEventHandler(null, { channel })`
587
+ // on the `TV-APP` element to switch channels in ~2-3 seconds without page navigation. Extends fullscreenApi for requestFullscreen() behavior on the player page.
588
+ profile: {
589
+ category: "multiChannel",
590
+ channelSelection: { strategy: "xfinityDirect" },
591
+ description: "Xfinity Stream with in-page SPA channel switching. Set Channel Selector to the channel callSign (e.g., CNNHD, ESPND) " +
592
+ "or network name (e.g., CNN, ESPN).",
593
+ extends: "fullscreenApi",
594
+ summary: "Xfinity Stream (SPA tuning, needs selector)"
595
+ },
596
+ profileName: "xfinityStream",
597
+ slug: "xfinity",
598
+ strategy: {
599
+ clearCache: clearXfinityCache,
600
+ execute: xfinityDirectStrategy,
601
+ invalidateDirectUrl: invalidateXfinityDirectUrl,
602
+ resolveDirectUrl: resolveXfinityDirectUrl
603
+ },
604
+ strategyName: "xfinityDirect",
605
+ tinySegmentThreshold: 150
606
+ };
607
+ //# sourceMappingURL=xfinity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xfinity.js","sourceRoot":"","sources":["../../../src/browser/tuning/xfinity.ts"],"names":[],"mappings":"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"}