prismcast 1.4.1 → 1.5.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 (182) hide show
  1. package/dist/app.js +18 -1
  2. package/dist/app.js.map +1 -1
  3. package/dist/browser/cdp.d.ts +2 -1
  4. package/dist/browser/cdp.js +44 -23
  5. package/dist/browser/cdp.js.map +1 -1
  6. package/dist/browser/channelSelection.d.ts +45 -1
  7. package/dist/browser/channelSelection.js +164 -27
  8. package/dist/browser/channelSelection.js.map +1 -1
  9. package/dist/browser/display.d.ts +0 -4
  10. package/dist/browser/display.js +0 -7
  11. package/dist/browser/display.js.map +1 -1
  12. package/dist/browser/index.d.ts +5 -0
  13. package/dist/browser/index.js +14 -0
  14. package/dist/browser/index.js.map +1 -1
  15. package/dist/browser/precaching.d.ts +5 -0
  16. package/dist/browser/precaching.js +112 -0
  17. package/dist/browser/precaching.js.map +1 -0
  18. package/dist/browser/tuning/directv.d.ts +2 -0
  19. package/dist/browser/tuning/directv.js +723 -0
  20. package/dist/browser/tuning/directv.js.map +1 -0
  21. package/dist/browser/tuning/fox.d.ts +2 -2
  22. package/dist/browser/tuning/fox.js +141 -22
  23. package/dist/browser/tuning/fox.js.map +1 -1
  24. package/dist/browser/tuning/hbo.d.ts +2 -2
  25. package/dist/browser/tuning/hbo.js +110 -41
  26. package/dist/browser/tuning/hbo.js.map +1 -1
  27. package/dist/browser/tuning/hulu.d.ts +2 -2
  28. package/dist/browser/tuning/hulu.js +537 -211
  29. package/dist/browser/tuning/hulu.js.map +1 -1
  30. package/dist/browser/tuning/sling.d.ts +2 -2
  31. package/dist/browser/tuning/sling.js +200 -56
  32. package/dist/browser/tuning/sling.js.map +1 -1
  33. package/dist/browser/tuning/youtubeTv.d.ts +2 -2
  34. package/dist/browser/tuning/youtubeTv.js +243 -57
  35. package/dist/browser/tuning/youtubeTv.js.map +1 -1
  36. package/dist/browser/video.d.ts +1 -1
  37. package/dist/browser/video.js +4 -2
  38. package/dist/browser/video.js.map +1 -1
  39. package/dist/channels/index.js +280 -34
  40. package/dist/channels/index.js.map +1 -1
  41. package/dist/config/health.d.ts +78 -0
  42. package/dist/config/health.js +202 -0
  43. package/dist/config/health.js.map +1 -0
  44. package/dist/config/paths.d.ts +10 -0
  45. package/dist/config/paths.js +14 -0
  46. package/dist/config/paths.js.map +1 -1
  47. package/dist/config/profiles.d.ts +6 -4
  48. package/dist/config/profiles.js +65 -14
  49. package/dist/config/profiles.js.map +1 -1
  50. package/dist/config/providerPacks.d.ts +46 -0
  51. package/dist/config/providerPacks.js +200 -0
  52. package/dist/config/providerPacks.js.map +1 -0
  53. package/dist/config/providers.d.ts +47 -6
  54. package/dist/config/providers.js +211 -17
  55. package/dist/config/providers.js.map +1 -1
  56. package/dist/config/sites.d.ts +1 -12
  57. package/dist/config/sites.js +40 -7
  58. package/dist/config/sites.js.map +1 -1
  59. package/dist/config/userChannels.d.ts +41 -19
  60. package/dist/config/userChannels.js +152 -35
  61. package/dist/config/userChannels.js.map +1 -1
  62. package/dist/config/userConfig.d.ts +5 -1
  63. package/dist/config/userConfig.js +58 -6
  64. package/dist/config/userConfig.js.map +1 -1
  65. package/dist/config/userProfiles.d.ts +81 -0
  66. package/dist/config/userProfiles.js +424 -0
  67. package/dist/config/userProfiles.js.map +1 -0
  68. package/dist/routes/config/channels/index.d.ts +3 -0
  69. package/dist/routes/config/channels/index.js +3 -0
  70. package/dist/routes/config/channels/index.js.map +1 -0
  71. package/dist/routes/config/channels/routes.d.ts +6 -0
  72. package/dist/routes/config/channels/routes.js +797 -0
  73. package/dist/routes/config/channels/routes.js.map +1 -0
  74. package/dist/routes/config/channels/table.d.ts +46 -0
  75. package/dist/routes/config/channels/table.js +811 -0
  76. package/dist/routes/config/channels/table.js.map +1 -0
  77. package/dist/routes/config/index.d.ts +37 -0
  78. package/dist/routes/config/index.js +81 -0
  79. package/dist/routes/config/index.js.map +1 -0
  80. package/dist/routes/config/providers.d.ts +18 -0
  81. package/dist/routes/config/providers.js +573 -0
  82. package/dist/routes/config/providers.js.map +1 -0
  83. package/dist/routes/config/settings.d.ts +39 -0
  84. package/dist/routes/config/settings.js +820 -0
  85. package/dist/routes/config/settings.js.map +1 -0
  86. package/dist/routes/index.d.ts +3 -2
  87. package/dist/routes/index.js +7 -4
  88. package/dist/routes/index.js.map +1 -1
  89. package/dist/routes/playlist.d.ts +5 -1
  90. package/dist/routes/playlist.js +32 -7
  91. package/dist/routes/playlist.js.map +1 -1
  92. package/dist/routes/providers.d.ts +6 -0
  93. package/dist/routes/providers.js +166 -0
  94. package/dist/routes/providers.js.map +1 -0
  95. package/dist/routes/root/content.d.ts +32 -0
  96. package/dist/routes/root/content.js +857 -0
  97. package/dist/routes/root/content.js.map +1 -0
  98. package/dist/routes/root/index.js +197 -0
  99. package/dist/routes/root/index.js.map +1 -0
  100. package/dist/routes/root/scripts/channels.d.ts +1 -0
  101. package/dist/routes/root/scripts/channels.js +745 -0
  102. package/dist/routes/root/scripts/channels.js.map +1 -0
  103. package/dist/routes/root/scripts/config.d.ts +1 -0
  104. package/dist/routes/root/scripts/config.js +1662 -0
  105. package/dist/routes/root/scripts/config.js.map +1 -0
  106. package/dist/routes/root/scripts/index.d.ts +3 -0
  107. package/dist/routes/root/scripts/index.js +8 -0
  108. package/dist/routes/root/scripts/index.js.map +1 -0
  109. package/dist/routes/root/scripts/status.d.ts +1 -0
  110. package/dist/routes/root/scripts/status.js +436 -0
  111. package/dist/routes/root/scripts/status.js.map +1 -0
  112. package/dist/routes/root/styles.d.ts +5 -0
  113. package/dist/routes/root/styles.js +447 -0
  114. package/dist/routes/root/styles.js.map +1 -0
  115. package/dist/routes/theme.js +7 -1
  116. package/dist/routes/theme.js.map +1 -1
  117. package/dist/routes/ui.js +8 -3
  118. package/dist/routes/ui.js.map +1 -1
  119. package/dist/service/commands.d.ts +5 -3
  120. package/dist/service/commands.js +117 -33
  121. package/dist/service/commands.js.map +1 -1
  122. package/dist/service/generators.d.ts +27 -0
  123. package/dist/service/generators.js +97 -6
  124. package/dist/service/generators.js.map +1 -1
  125. package/dist/streaming/hls.js +18 -1
  126. package/dist/streaming/hls.js.map +1 -1
  127. package/dist/streaming/lifecycle.js +1 -1
  128. package/dist/streaming/lifecycle.js.map +1 -1
  129. package/dist/streaming/monitor.d.ts +1 -38
  130. package/dist/streaming/monitor.js +2 -289
  131. package/dist/streaming/monitor.js.map +1 -1
  132. package/dist/streaming/recovery.d.ts +143 -0
  133. package/dist/streaming/recovery.js +286 -0
  134. package/dist/streaming/recovery.js.map +1 -0
  135. package/dist/streaming/registry.d.ts +1 -1
  136. package/dist/streaming/setup.d.ts +1 -1
  137. package/dist/streaming/setup.js +3 -1
  138. package/dist/streaming/setup.js.map +1 -1
  139. package/dist/streaming/showInfo.js +12 -14
  140. package/dist/streaming/showInfo.js.map +1 -1
  141. package/dist/streaming/statusEmitter.d.ts +4 -2
  142. package/dist/streaming/statusEmitter.js +5 -0
  143. package/dist/streaming/statusEmitter.js.map +1 -1
  144. package/dist/types/channels.d.ts +68 -0
  145. package/dist/types/channels.js +2 -0
  146. package/dist/types/channels.js.map +1 -0
  147. package/dist/types/config.d.ts +127 -0
  148. package/dist/types/config.js +2 -0
  149. package/dist/types/config.js.map +1 -0
  150. package/dist/types/index.d.ts +7 -406
  151. package/dist/types/index.js +1 -5
  152. package/dist/types/index.js.map +1 -1
  153. package/dist/types/profiles.d.ts +141 -0
  154. package/dist/types/profiles.js +2 -0
  155. package/dist/types/profiles.js.map +1 -0
  156. package/dist/types/selection.d.ts +101 -0
  157. package/dist/types/selection.js +6 -0
  158. package/dist/types/selection.js.map +1 -0
  159. package/dist/types/shared.d.ts +7 -0
  160. package/dist/types/shared.js +6 -0
  161. package/dist/types/shared.js.map +1 -0
  162. package/dist/types/streaming.d.ts +96 -0
  163. package/dist/types/streaming.js +2 -0
  164. package/dist/types/streaming.js.map +1 -0
  165. package/dist/utils/debugFilter.js +3 -1
  166. package/dist/utils/debugFilter.js.map +1 -1
  167. package/dist/utils/format.d.ts +7 -0
  168. package/dist/utils/format.js +22 -0
  169. package/dist/utils/format.js.map +1 -1
  170. package/dist/utils/index.d.ts +1 -0
  171. package/dist/utils/index.js +1 -0
  172. package/dist/utils/index.js.map +1 -1
  173. package/dist/utils/sanitize.d.ts +14 -0
  174. package/dist/utils/sanitize.js +37 -0
  175. package/dist/utils/sanitize.js.map +1 -0
  176. package/package.json +6 -4
  177. package/dist/routes/config.d.ts +0 -72
  178. package/dist/routes/config.js +0 -1987
  179. package/dist/routes/config.js.map +0 -1
  180. package/dist/routes/root.js +0 -2959
  181. package/dist/routes/root.js.map +0 -1
  182. /package/dist/routes/{root.d.ts → root/index.d.ts} +0 -0
@@ -1,406 +1,7 @@
1
- import type { Frame, Page } from "puppeteer-core";
2
- import type { RecoveryMetrics } from "../streaming/monitor.js";
3
- /**
4
- * A utility type that represents a value that can be null.
5
- * @typeParam T - The type that can be nullable.
6
- */
7
- export type Nullable<T> = T | null;
8
- /**
9
- * Browser-related configuration controlling Chrome launch behavior. Viewport dimensions are derived from the quality preset via getViewport() and are not stored in
10
- * this configuration object.
11
- */
12
- export interface BrowserConfig {
13
- executablePath: Nullable<string>;
14
- initTimeout: number;
15
- }
16
- /**
17
- * Filesystem paths for Chrome profile data and extension files.
18
- */
19
- export interface PathsConfig {
20
- chromeDataDir: Nullable<string>;
21
- chromeProfileName: string;
22
- extensionDirName: string;
23
- logFile: Nullable<string>;
24
- }
25
- /**
26
- * Playback monitoring and recovery timing configuration. These values control how quickly the system detects playback problems and how aggressively it attempts
27
- * recovery. The defaults balance responsiveness against false positives from temporary buffering.
28
- */
29
- export interface PlaybackConfig {
30
- bufferingGracePeriod: number;
31
- channelSelectorDelay: number;
32
- channelSwitchDelay: number;
33
- clickToPlayDelay: number;
34
- iframeInitDelay: number;
35
- maxPageReloads: number;
36
- monitorInterval: number;
37
- pageReloadWindow: number;
38
- sourceReloadDelay: number;
39
- stallCountThreshold: number;
40
- stallThreshold: number;
41
- sustainedPlaybackRequired: number;
42
- }
43
- /**
44
- * Recovery behavior configuration controlling retry logic, backoff timing, and circuit breaker thresholds. These settings determine how the system handles
45
- * failures and prevents runaway resource consumption from broken streams.
46
- */
47
- export interface RecoveryConfig {
48
- backoffJitter: number;
49
- circuitBreakerThreshold: number;
50
- circuitBreakerWindow: number;
51
- maxBackoffDelay: number;
52
- stalePageCleanupInterval: number;
53
- stalePageGracePeriod: number;
54
- }
55
- /**
56
- * HLS streaming configuration controlling segment generation and lifecycle.
57
- */
58
- export interface HLSConfig {
59
- idleTimeout: number;
60
- maxSegments: number;
61
- segmentDuration: number;
62
- }
63
- /**
64
- * Channels configuration controlling which predefined channels are enabled.
65
- */
66
- export interface ChannelsConfig {
67
- disabledPredefined: string[];
68
- enabledProviders: string[];
69
- }
70
- /**
71
- * HDHomeRun emulation configuration. When enabled, PrismCast runs a separate HTTP server that emulates the HDHomeRun API, allowing Plex to discover and use
72
- * PrismCast as a virtual tuner for live TV and DVR recording. The emulated device appears in Plex's tuner setup and serves PrismCast's HLS streams directly.
73
- */
74
- export interface HdhrConfig {
75
- deviceId: string;
76
- enabled: boolean;
77
- friendlyName: string;
78
- port: number;
79
- }
80
- /**
81
- * Logging configuration controlling file-based logging behavior.
82
- */
83
- export interface LoggingConfig {
84
- debugFilter: string;
85
- httpLogLevel: "all" | "errors" | "filtered" | "none";
86
- maxSize: number;
87
- }
88
- /**
89
- * HTTP server configuration controlling network binding.
90
- */
91
- export interface ServerConfig {
92
- host: string;
93
- port: number;
94
- }
95
- /**
96
- * Capture mode for media recording. Determines how video/audio is captured from the browser and processed for HLS output.
97
- * - "ffmpeg": Captures WebM (H264+Opus) and uses FFmpeg to transcode audio to AAC. More stable for long recordings.
98
- * - "native": Captures fMP4 (H264+AAC) directly from Chrome. No dependencies but may be unstable with long recordings.
99
- */
100
- export type CaptureMode = "ffmpeg" | "native";
101
- /**
102
- * Media streaming configuration controlling video capture quality, timeouts, and concurrency limits.
103
- */
104
- export interface StreamingConfig {
105
- audioBitsPerSecond: number;
106
- captureMode: CaptureMode;
107
- frameRate: number;
108
- maxConcurrentStreams: number;
109
- maxNavigationRetries: number;
110
- navigationTimeout: number;
111
- qualityPreset: string;
112
- videoBitsPerSecond: number;
113
- videoTimeout: number;
114
- }
115
- /**
116
- * Root configuration object containing all application settings organized by functional area.
117
- */
118
- export interface Config {
119
- browser: BrowserConfig;
120
- channels: ChannelsConfig;
121
- hdhr: HdhrConfig;
122
- hls: HLSConfig;
123
- logging: LoggingConfig;
124
- paths: PathsConfig;
125
- playback: PlaybackConfig;
126
- recovery: RecoveryConfig;
127
- server: ServerConfig;
128
- streaming: StreamingConfig;
129
- }
130
- /**
131
- * UI category for profile grouping in dropdowns and reference documentation. Profiles are grouped by their fullscreen mechanism and special characteristics.
132
- * - "api": Profiles using the JavaScript fullscreen API (including embedded iframe and click-to-play variants).
133
- * - "keyboard": Profiles using keyboard shortcuts (typically the 'f' key) for fullscreen.
134
- * - "multiChannel": Multi-channel profiles requiring a channel selector for tile or thumbnail-based channel selection.
135
- * - "special": Special-purpose profiles like static page capture.
136
- */
137
- export type ProfileCategory = "api" | "keyboard" | "multiChannel" | "special";
138
- /**
139
- * Site profile definition with optional flags. All flags are optional because profiles can inherit from other profiles, and only the flags that differ from the
140
- * parent need to be specified. The DEFAULT_SITE_PROFILE provides baseline values for any flags not set through inheritance.
141
- */
142
- export interface SiteProfile {
143
- category?: ProfileCategory;
144
- channelSelection?: ChannelSelectionConfig;
145
- channelSelector?: Nullable<string>;
146
- clickSelector?: Nullable<string>;
147
- clickToPlay?: boolean;
148
- description?: string;
149
- extends?: string;
150
- summary?: string;
151
- fullscreenKey?: Nullable<string>;
152
- fullscreenSelector?: Nullable<string>;
153
- hideSelector?: Nullable<string>;
154
- lockVolumeProperties?: boolean;
155
- needsIframeHandling?: boolean;
156
- noVideo?: boolean;
157
- selectReadyVideo?: boolean;
158
- useRequestFullscreen?: boolean;
159
- waitForNetworkIdle?: boolean;
160
- }
161
- /**
162
- * Fully-resolved site profile with all flags having concrete values. After resolving inheritance chains and applying defaults, every flag has a definite boolean
163
- * or string value. This interface is used by stream handling code that needs to check profile flags without worrying about undefined values.
164
- */
165
- export interface ResolvedSiteProfile {
166
- channelSelection: ChannelSelectionConfig;
167
- channelSelector: Nullable<string>;
168
- clickSelector: Nullable<string>;
169
- clickToPlay: boolean;
170
- fullscreenKey: Nullable<string>;
171
- fullscreenSelector: Nullable<string>;
172
- hideSelector: Nullable<string>;
173
- lockVolumeProperties: boolean;
174
- maxContinuousPlayback: Nullable<number>;
175
- needsIframeHandling: boolean;
176
- noVideo: boolean;
177
- selectReadyVideo: boolean;
178
- useRequestFullscreen: boolean;
179
- waitForNetworkIdle: boolean;
180
- }
181
- /**
182
- * Result of resolving a site profile. Includes both the resolved profile configuration and the name of the profile that was matched. The name indicates whether the
183
- * profile came from a channel hint, domain-based autodetection, or the default fallback.
184
- */
185
- export interface ProfileResolutionResult {
186
- profile: ResolvedSiteProfile;
187
- profileName: string;
188
- }
189
- /**
190
- * Channel definition mapping a short name to a streaming URL with optional configuration overrides.
191
- */
192
- export interface Channel {
193
- channelNumber?: number;
194
- channelSelector?: string;
195
- name?: string;
196
- profile?: string;
197
- provider?: string;
198
- stationId?: string;
199
- url: string;
200
- }
201
- /**
202
- * Enriched channel entry returned by getChannelListing(). Wraps a Channel definition with source classification and enabled status metadata, providing the
203
- * single source of truth for merged channel data across the codebase.
204
- */
205
- export interface ChannelListingEntry {
206
- availableByProvider: boolean;
207
- channel: Channel;
208
- enabled: boolean;
209
- key: string;
210
- source: "override" | "predefined" | "user";
211
- }
212
- /**
213
- * Map of channel short names to channel definitions. Channel names must be URL-safe strings (lowercase letters, numbers, hyphens) since they appear in stream
214
- * request URLs.
215
- */
216
- export type ChannelMap = Record<string, Channel>;
217
- /**
218
- * Represents a group of provider variants for the same content. Used by the UI to display provider selection dropdowns for multi-provider channels.
219
- */
220
- export interface ProviderGroup {
221
- canonicalKey: string;
222
- variants: {
223
- key: string;
224
- label: string;
225
- }[];
226
- }
227
- /**
228
- * Information about an active streaming session. Created when a stream request is received and deleted when the stream ends.
229
- */
230
- export interface StreamInfo {
231
- channelName: Nullable<string>;
232
- id: number;
233
- page: Page;
234
- startTime: Date;
235
- stopMonitor: Nullable<() => RecoveryMetrics>;
236
- url: string;
237
- }
238
- /**
239
- * Snapshot of a video element's playback state. Collected by the playback health monitor to detect stalls, errors, and other problems.
240
- */
241
- export interface VideoState {
242
- currentTime: number;
243
- ended: boolean;
244
- error: boolean;
245
- muted: boolean;
246
- networkState: number;
247
- paused: boolean;
248
- readyState: number;
249
- time: number;
250
- volume: number;
251
- }
252
- /**
253
- * Strategy for selecting a video element when multiple are present. "selectFirstVideo" takes the first video in DOM order; "selectReadyVideo" finds the video
254
- * with readyState >= 3, which typically identifies the actively playing main content rather than preloaded ads.
255
- */
256
- export type VideoSelectorType = "selectFirstVideo" | "selectReadyVideo";
257
- /**
258
- * Result of URL validation indicating whether the URL is safe to navigate to.
259
- */
260
- export interface UrlValidationResult {
261
- reason?: string;
262
- valid: boolean;
263
- }
264
- /**
265
- * Alias for UrlValidationResult maintained for backward compatibility with existing code.
266
- */
267
- export type UrlValidation = UrlValidationResult;
268
- /**
269
- * Health check response structure returned by the /health endpoint.
270
- */
271
- export interface HealthStatus {
272
- browser: {
273
- connected: boolean;
274
- pageCount: number;
275
- };
276
- captureMode: string;
277
- chrome: Nullable<string>;
278
- clients: {
279
- byType: {
280
- count: number;
281
- type: string;
282
- }[];
283
- total: number;
284
- };
285
- ffmpegAvailable: boolean;
286
- memory: {
287
- heapTotal: number;
288
- heapUsed: number;
289
- rss: number;
290
- segmentBuffers: number;
291
- };
292
- message?: string;
293
- status: "degraded" | "healthy" | "unhealthy";
294
- streams: {
295
- active: number;
296
- limit: number;
297
- };
298
- timestamp: string;
299
- uptime: number;
300
- version: string;
301
- }
302
- /**
303
- * Information about a single active stream as returned by the /streams endpoint.
304
- */
305
- export interface StreamListItem {
306
- channel: Nullable<string>;
307
- duration: number;
308
- id: number;
309
- startTime: string;
310
- url: string;
311
- }
312
- /**
313
- * Response structure for the /streams endpoint.
314
- */
315
- export interface StreamListResponse {
316
- count: number;
317
- limit: number;
318
- streams: StreamListItem[];
319
- }
320
- /**
321
- * Available channel selection strategies. Each strategy implements a different approach to finding and selecting channels in a multi-channel player UI.
322
- *
323
- * - "foxGrid": Find channel by station code in a non-virtualized guide grid, click the channel logo button via DOM .click(). Used by Fox.com.
324
- * - "guideGrid": Find channel by exact-matching image alt text, click nearest clickable ancestor. Optionally clicks a tab to reveal the list first. Used by Hulu
325
- * Live TV.
326
- * - "hboGrid": Discover the HBO tab page URL from the homepage menu bar, scrape the live channel tile rail for a matching channel name, and navigate to the watch
327
- * URL. Caches the tab URL across tunes with stale-cache fallback. Used by HBO Max.
328
- * - "none": No channel selection needed (single-channel sites). This is the default.
329
- * - "slingGrid": Find channel by data-testid in a virtualized A-Z guide grid, scroll via binary search on .guide-cell scrollTop, click the on-now program
330
- * cell. Used by Sling TV.
331
- * - "thumbnailRow": Find channel element using the profile's matchSelector (defaults to image URL matching), click adjacent element on the same row. Used by
332
- * USA Network.
333
- * - "tileClick": Find channel element using the profile's matchSelector (defaults to image URL matching), click tile, then optionally click play button if
334
- * playSelector is configured. Used by Disney+.
335
- * - "youtubeGrid": Find channel by aria-label in a non-virtualized EPG grid, extract the watch URL, and navigate directly. Used by YouTube TV.
336
- */
337
- export type ChannelSelectionStrategy = "foxGrid" | "guideGrid" | "hboGrid" | "none" | "slingGrid" | "thumbnailRow" | "tileClick" | "youtubeGrid";
338
- /**
339
- * Configuration for channel selection behavior within a site profile.
340
- */
341
- export interface ChannelSelectionConfig {
342
- listSelector?: string;
343
- matchSelector?: string;
344
- playSelector?: string;
345
- strategy: ChannelSelectionStrategy;
346
- }
347
- export interface ChannelSelectionProfile extends ResolvedSiteProfile {
348
- channelSelector: string;
349
- }
350
- export declare function isChannelSelectionProfile(profile: ResolvedSiteProfile): profile is ChannelSelectionProfile;
351
- /**
352
- * Result of attempting to select a channel from a multi-channel player UI.
353
- */
354
- export interface ChannelSelectorResult {
355
- reason?: string;
356
- success: boolean;
357
- }
358
- /**
359
- * The strategy function signature. All strategies take the Puppeteer page and a narrowed profile with guaranteed non-null channelSelector.
360
- */
361
- export type ChannelStrategyHandler = (page: Page, profile: ChannelSelectionProfile) => Promise<ChannelSelectorResult>;
362
- /**
363
- * The complete contract for a channel selection strategy. Each provider file exports a single object implementing this interface. The coordinator accesses all
364
- * provider behavior through these hooks — no strategy-specific imports or hardcoded strategy name checks outside the registry.
365
- */
366
- export interface ChannelStrategyEntry {
367
- /**
368
- * Resets all module-level caches (row positions, discovered URLs, watch URLs). Called on browser restart when cached state may be stale.
369
- */
370
- clearCache?: () => void;
371
- /**
372
- * Selects the target channel in the provider's guide UI. Receives a Puppeteer page and a profile with a guaranteed non-null channelSelector. Must handle its
373
- * own retry logic (e.g., overlay dismiss) and return a result indicating success or failure with a diagnostic reason.
374
- */
375
- execute: ChannelStrategyHandler;
376
- /**
377
- * Removes a cached watch URL after it failed to produce a working stream. Called by the coordinator when a cached direct navigation fails.
378
- */
379
- invalidateDirectUrl?: (channelSelector: string) => void;
380
- /**
381
- * Returns a watch URL for direct navigation, bypassing guide page loading. Implementations may perform async work such as fetching current asset IDs from
382
- * provider APIs. The page parameter allows setting up response interception or accessing browser context when needed (e.g., cold cache setup).
383
- */
384
- resolveDirectUrl?: (channelSelector: string, page: Page) => Promise<Nullable<string>>;
385
- }
386
- /**
387
- * Coordinates for a click target, used when clicking channel selector elements.
388
- */
389
- export interface ClickTarget {
390
- x: number;
391
- y: number;
392
- }
393
- /**
394
- * Result of tuning to a channel, containing the video context needed for monitoring.
395
- */
396
- export interface TuneResult {
397
- context: Frame | Page;
398
- }
399
- /**
400
- * Browser chrome dimensions (toolbars, borders) calculated by comparing window.outerHeight/Width to window.innerHeight/Width. Used to set window size such that
401
- * the viewport (content area) matches our target dimensions.
402
- */
403
- export interface UiSize {
404
- height: number;
405
- width: number;
406
- }
1
+ export type { BrowserConfig, CaptureMode, ChannelsConfig, Config, HdhrConfig, HLSConfig, LoggingConfig, PathsConfig, PlaybackConfig, RecoveryConfig, ServerConfig, StreamingConfig } from "./config.js";
2
+ export type { Channel, ChannelDelta, ChannelListingEntry, ChannelMap, ProviderGroup, StoredChannel, StoredChannelMap } from "./channels.js";
3
+ export type { ChannelSelectionConfig, ChannelSelectionStrategy, DomainConfig, ProfileCategory, ProfileResolutionResult, ProfilesValidationResult, ProviderPack, ResolvedSiteProfile, SiteProfile, UserProfilesFile, UserProfilesLoadResult } from "./profiles.js";
4
+ export type { ChannelSelectionProfile, ChannelSelectorResult, ChannelStrategyEntry, ChannelStrategyHandler, ClickTarget, DiscoveredChannel, ProviderModule, TuneResult, UiSize } from "./selection.js";
5
+ export type { ChannelSortField, Nullable, SortDirection } from "./shared.js";
6
+ export type { HealthStatus, StreamInfo, StreamListItem, StreamListResponse, UrlValidation, UrlValidationResult, VideoSelectorType, VideoState } from "./streaming.js";
7
+ export { isChannelSelectionProfile } from "./selection.js";
@@ -1,6 +1,2 @@
1
- // Type guard that proves channelSelector is a non-empty string. Matches the original !channelSelector truthiness check, which rejects both null and empty string.
2
- // Used by the coordinator before dispatching to strategy functions.
3
- export function isChannelSelectionProfile(profile) {
4
- return (profile.channelSelector !== null) && (profile.channelSelector.length > 0);
5
- }
1
+ export { isChannelSelectionProfile } from "./selection.js";
6
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAm1BA,kKAAkK;AAClK,oEAAoE;AACpE,MAAM,UAAU,yBAAyB,CAAC,OAA4B;IAEpE,OAAO,CAAC,OAAO,CAAC,eAAe,KAAK,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACpF,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,141 @@
1
+ import type { ChannelMap } from "./channels.js";
2
+ import type { Nullable } from "./shared.js";
3
+ /**
4
+ * Available channel selection strategies. Each strategy implements a different approach to finding and selecting channels in a multi-channel player UI.
5
+ *
6
+ * - "directvGrid": Tune via webpack injection — captures __webpack_require__, extracts the Redux store from the React fiber tree, matches by channel name, and
7
+ * dispatches playConsumable. Falls back to logo aria-label click when the interceptor fails. Used by DirecTV Stream.
8
+ * - "foxGrid": Find channel by station code in a non-virtualized guide grid, click the channel logo button via DOM .click(). Used by Fox.com.
9
+ * - "guideGrid": Find channel by exact-matching image alt text, click nearest clickable ancestor. Optionally clicks a tab to reveal the list first. Used by Hulu
10
+ * Live TV.
11
+ * - "hboGrid": Discover the HBO tab page URL from the homepage menu bar, scrape the live channel tile rail for a matching channel name, and navigate to the watch
12
+ * URL. Caches the tab URL across tunes with stale-cache fallback. Used by HBO Max.
13
+ * - "none": No channel selection needed (single-channel sites). This is the default.
14
+ * - "slingGrid": Find channel by data-testid in a virtualized A-Z guide grid, scroll via binary search on .guide-cell scrollTop, click the on-now program
15
+ * cell. Used by Sling TV.
16
+ * - "thumbnailRow": Find channel element using the profile's matchSelector (defaults to image URL matching), click adjacent element on the same row. Used by
17
+ * USA Network.
18
+ * - "tileClick": Find channel element using the profile's matchSelector (defaults to image URL matching), click tile, then optionally click play button if
19
+ * playSelector is configured. Used by Disney+.
20
+ * - "youtubeGrid": Find channel by aria-label in a non-virtualized EPG grid, extract the watch URL, and navigate directly. Used by YouTube TV.
21
+ */
22
+ export type ChannelSelectionStrategy = "directvGrid" | "foxGrid" | "guideGrid" | "hboGrid" | "none" | "slingGrid" | "thumbnailRow" | "tileClick" | "youtubeGrid";
23
+ /**
24
+ * Configuration for channel selection behavior within a site profile.
25
+ */
26
+ export interface ChannelSelectionConfig {
27
+ listSelector?: string;
28
+ matchSelector?: string;
29
+ playSelector?: string;
30
+ scrollSelector?: string;
31
+ scrollTarget?: string;
32
+ scrollToBottom?: boolean;
33
+ strategy: ChannelSelectionStrategy;
34
+ }
35
+ /**
36
+ * UI category for profile grouping in dropdowns and reference documentation. Profiles are grouped by their fullscreen mechanism and special characteristics.
37
+ * - "api": Profiles using the JavaScript fullscreen API (including embedded iframe and click-to-play variants).
38
+ * - "custom": User-defined profiles created via the profile builder wizard or imported from provider packs.
39
+ * - "keyboard": Profiles using keyboard shortcuts (typically the 'f' key) for fullscreen.
40
+ * - "multiChannel": Multi-channel profiles requiring a channel selector for tile or thumbnail-based channel selection.
41
+ * - "special": Special-purpose profiles like static page capture.
42
+ */
43
+ export type ProfileCategory = "api" | "custom" | "keyboard" | "multiChannel" | "special";
44
+ /**
45
+ * Site profile definition with optional flags. All flags are optional because profiles can inherit from other profiles, and only the flags that differ from the
46
+ * parent need to be specified. The DEFAULT_SITE_PROFILE provides baseline values for any flags not set through inheritance.
47
+ */
48
+ export interface SiteProfile {
49
+ category?: ProfileCategory;
50
+ channelSelection?: ChannelSelectionConfig;
51
+ channelSelector?: Nullable<string>;
52
+ clickSelector?: Nullable<string>;
53
+ clickToPlay?: boolean;
54
+ description?: string;
55
+ extends?: string;
56
+ summary?: string;
57
+ fullscreenKey?: Nullable<string>;
58
+ fullscreenSelector?: Nullable<string>;
59
+ hideSelector?: Nullable<string>;
60
+ lockVolumeProperties?: boolean;
61
+ needsIframeHandling?: boolean;
62
+ noVideo?: boolean;
63
+ selectReadyVideo?: boolean;
64
+ useRequestFullscreen?: boolean;
65
+ waitForNetworkIdle?: boolean;
66
+ }
67
+ /**
68
+ * Fully-resolved site profile with all flags having concrete values. After resolving inheritance chains and applying defaults, every flag has a definite boolean
69
+ * or string value. This interface is used by stream handling code that needs to check profile flags without worrying about undefined values.
70
+ */
71
+ export interface ResolvedSiteProfile {
72
+ channelSelection: ChannelSelectionConfig;
73
+ channelSelector: Nullable<string>;
74
+ clickSelector: Nullable<string>;
75
+ clickToPlay: boolean;
76
+ fullscreenKey: Nullable<string>;
77
+ fullscreenSelector: Nullable<string>;
78
+ hideSelector: Nullable<string>;
79
+ lockVolumeProperties: boolean;
80
+ maxContinuousPlayback: Nullable<number>;
81
+ needsIframeHandling: boolean;
82
+ noVideo: boolean;
83
+ selectReadyVideo: boolean;
84
+ useRequestFullscreen: boolean;
85
+ waitForNetworkIdle: boolean;
86
+ }
87
+ /**
88
+ * Result of resolving a site profile. Includes both the resolved profile configuration and the name of the profile that was matched. The name indicates whether the
89
+ * profile came from a channel hint, domain-based autodetection, or the default fallback.
90
+ */
91
+ export interface ProfileResolutionResult {
92
+ profile: ResolvedSiteProfile;
93
+ profileName: string;
94
+ }
95
+ /**
96
+ * Domain-level configuration associating domain patterns with site profiles and provider display names. Each entry can specify a site profile for behavior
97
+ * configuration and/or a provider display name for friendly UI labels. Used by both built-in domain mappings in sites.ts and user-defined mappings in profiles.json.
98
+ */
99
+ export interface DomainConfig {
100
+ loginUrl?: string;
101
+ maxContinuousPlayback?: number;
102
+ profile?: string;
103
+ provider?: string;
104
+ providerTag?: string;
105
+ }
106
+ /**
107
+ * Storage format for profiles.json. Contains user-defined site profiles and domain mappings that extend or override the built-in configurations.
108
+ */
109
+ export interface UserProfilesFile {
110
+ domains?: Record<string, DomainConfig>;
111
+ profiles?: Record<string, SiteProfile>;
112
+ }
113
+ /**
114
+ * Result of loading user profiles from the profiles.json file.
115
+ */
116
+ export interface UserProfilesLoadResult {
117
+ domains: Record<string, DomainConfig>;
118
+ parseError: boolean;
119
+ parseErrorMessage?: string;
120
+ profiles: Record<string, SiteProfile>;
121
+ }
122
+ /**
123
+ * Provider pack distribution format. Bundles a profile, domain mapping(s), and optionally channels for a streaming provider into a single JSON file. On import,
124
+ * its contents are split and written to profiles.json and channels.json.
125
+ */
126
+ export interface ProviderPack {
127
+ channels?: ChannelMap;
128
+ domains?: Record<string, DomainConfig>;
129
+ name: string;
130
+ profiles: Record<string, SiteProfile>;
131
+ version: number;
132
+ }
133
+ /**
134
+ * Validation result for profile and domain imports.
135
+ */
136
+ export interface ProfilesValidationResult {
137
+ domains: Record<string, DomainConfig>;
138
+ errors: string[];
139
+ profiles: Record<string, SiteProfile>;
140
+ valid: boolean;
141
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=profiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.js","sourceRoot":"","sources":["../../src/types/profiles.ts"],"names":[],"mappings":""}
@@ -0,0 +1,101 @@
1
+ import type { ChannelSelectionStrategy, ResolvedSiteProfile } from "./profiles.js";
2
+ import type { Frame, Page } from "puppeteer-core";
3
+ import type { Nullable } from "./shared.js";
4
+ export interface ChannelSelectionProfile extends ResolvedSiteProfile {
5
+ channelSelector: string;
6
+ }
7
+ export declare function isChannelSelectionProfile(profile: ResolvedSiteProfile): profile is ChannelSelectionProfile;
8
+ /**
9
+ * Result of attempting to select a channel from a multi-channel player UI.
10
+ */
11
+ export interface ChannelSelectorResult {
12
+ directTune?: boolean;
13
+ reason?: string;
14
+ success: boolean;
15
+ }
16
+ /**
17
+ * The strategy function signature. All strategies take the Puppeteer page and a narrowed profile with guaranteed non-null channelSelector.
18
+ */
19
+ export type ChannelStrategyHandler = (page: Page, profile: ChannelSelectionProfile) => Promise<ChannelSelectorResult>;
20
+ /**
21
+ * The complete contract for a channel selection strategy. Each provider file exports a single object implementing this interface. The coordinator accesses all
22
+ * provider behavior through these hooks — no strategy-specific imports or hardcoded strategy name checks outside the registry.
23
+ */
24
+ export interface ChannelStrategyEntry {
25
+ /**
26
+ * Resets all module-level caches (row positions, discovered URLs, watch URLs). Called on browser restart when cached state may be stale.
27
+ */
28
+ clearCache?: () => void;
29
+ /**
30
+ * Selects the target channel in the provider's guide UI. Receives a Puppeteer page and a profile with a guaranteed non-null channelSelector. Must handle its
31
+ * own retry logic (e.g., overlay dismiss) and return a result indicating success or failure with a diagnostic reason.
32
+ */
33
+ execute: ChannelStrategyHandler;
34
+ /**
35
+ * Removes a cached watch URL after it failed to produce a working stream. Called by the coordinator when a cached direct navigation fails.
36
+ */
37
+ invalidateDirectUrl?: (channelSelector: string) => void;
38
+ /**
39
+ * Returns a watch URL for direct navigation, bypassing guide page loading. Implementations may perform async work such as fetching current asset IDs from
40
+ * provider APIs. The page parameter allows setting up response interception or accessing browser context when needed (e.g., cold cache setup).
41
+ */
42
+ resolveDirectUrl?: (channelSelector: string, page: Page) => Promise<Nullable<string>>;
43
+ }
44
+ /**
45
+ * Standardized output shape for a channel discovered from a provider's guide. Produced by each provider's discoverChannels implementation and returned as
46
+ * a JSON array from the GET /providers/:slug/channels endpoint. Mirrors the shape of channel definitions in channels/index.ts so discovery output can be
47
+ * used directly to populate new entries.
48
+ */
49
+ export interface DiscoveredChannel {
50
+ affiliate?: string;
51
+ channelSelector: string;
52
+ name: string;
53
+ tier?: string;
54
+ }
55
+ /**
56
+ * Unified provider contract that bundles identity metadata, tuning strategy, and channel discovery into a single registry entry. Each provider tuning file
57
+ * exports one ProviderModule. The coordinator builds its strategy dispatch lookup from provider modules at evaluation time. Generic strategies (thumbnailRow,
58
+ * tileClick) remain bare ChannelStrategyEntry objects — they are not providers.
59
+ */
60
+ export interface ProviderModule {
61
+ /**
62
+ * Discovers all available channels from the provider's guide. The route handler navigates to guideUrl before calling this function unless handlesOwnNavigation
63
+ * is set. Returns a standardized DiscoveredChannel array.
64
+ */
65
+ discoverChannels: (page: Page) => Promise<DiscoveredChannel[]>;
66
+ /**
67
+ * Returns cached discovered channels if the provider has already fully enumerated its lineup from a previous tune or discovery call, or null if no enumeration
68
+ * has occurred. When non-null, the route handler can skip browser page creation entirely and return the cached result immediately.
69
+ */
70
+ getCachedChannels: () => Nullable<DiscoveredChannel[]>;
71
+ guideUrl: string;
72
+ handlesOwnNavigation?: boolean;
73
+ label: string;
74
+ slug: string;
75
+ strategy: ChannelStrategyEntry;
76
+ strategyName: ChannelSelectionStrategy;
77
+ validatePrecache?: (channels: DiscoveredChannel[]) => boolean;
78
+ validateTune?: (channelSelector: string) => boolean;
79
+ }
80
+ /**
81
+ * Coordinates for a click target, used when clicking channel selector elements.
82
+ */
83
+ export interface ClickTarget {
84
+ x: number;
85
+ y: number;
86
+ }
87
+ /**
88
+ * Result of tuning to a channel, containing the video context needed for monitoring.
89
+ */
90
+ export interface TuneResult {
91
+ context: Frame | Page;
92
+ directTune?: boolean;
93
+ }
94
+ /**
95
+ * Browser chrome dimensions (toolbars, borders) calculated by comparing window.outerHeight/Width to window.innerHeight/Width. Used to set window size such that
96
+ * the viewport (content area) matches our target dimensions.
97
+ */
98
+ export interface UiSize {
99
+ height: number;
100
+ width: number;
101
+ }