prismcast 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -4
- package/dist/app.js +5 -20
- package/dist/app.js.map +1 -1
- package/dist/browser/cdp.js +1 -4
- package/dist/browser/cdp.js.map +1 -1
- package/dist/browser/channelSelection.d.ts +5 -0
- package/dist/browser/channelSelection.js +803 -53
- package/dist/browser/channelSelection.js.map +1 -1
- package/dist/browser/display.js +1 -4
- package/dist/browser/display.js.map +1 -1
- package/dist/browser/index.js +10 -28
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/video.d.ts +24 -10
- package/dist/browser/video.js +101 -44
- package/dist/browser/video.js.map +1 -1
- package/dist/channels/index.d.ts +1 -17
- package/dist/channels/index.js +246 -137
- package/dist/channels/index.js.map +1 -1
- package/dist/config/index.js +10 -9
- package/dist/config/index.js.map +1 -1
- package/dist/config/presets.js +1 -4
- package/dist/config/presets.js.map +1 -1
- package/dist/config/profiles.d.ts +14 -13
- package/dist/config/profiles.js +47 -287
- package/dist/config/profiles.js.map +1 -1
- package/dist/config/providers.d.ts +75 -0
- package/dist/config/providers.js +283 -0
- package/dist/config/providers.js.map +1 -0
- package/dist/config/sites.d.ts +20 -0
- package/dist/config/sites.js +350 -0
- package/dist/config/sites.js.map +1 -0
- package/dist/config/userChannels.d.ts +15 -3
- package/dist/config/userChannels.js +85 -33
- package/dist/config/userChannels.js.map +1 -1
- package/dist/config/userConfig.d.ts +1 -0
- package/dist/config/userConfig.js +12 -26
- package/dist/config/userConfig.js.map +1 -1
- package/dist/hdhr/channelMap.js +3 -6
- package/dist/hdhr/channelMap.js.map +1 -1
- package/dist/hdhr/deviceId.js +1 -4
- package/dist/hdhr/deviceId.js.map +1 -1
- package/dist/hdhr/discover.js.map +1 -1
- package/dist/hdhr/index.js +1 -4
- package/dist/hdhr/index.js.map +1 -1
- package/dist/index.js +4 -16
- package/dist/index.js.map +1 -1
- package/dist/routes/assets.js +1 -4
- package/dist/routes/assets.js.map +1 -1
- package/dist/routes/auth.js +4 -2
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/channels.js +2 -2
- package/dist/routes/channels.js.map +1 -1
- package/dist/routes/components.js.map +1 -1
- package/dist/routes/config.js +163 -34
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/health.js +1 -4
- package/dist/routes/health.js.map +1 -1
- package/dist/routes/hls.js +1 -4
- package/dist/routes/hls.js.map +1 -1
- package/dist/routes/index.js +1 -4
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/logs.js +3 -12
- package/dist/routes/logs.js.map +1 -1
- package/dist/routes/mpegts.js +1 -4
- package/dist/routes/mpegts.js.map +1 -1
- package/dist/routes/play.js +1 -4
- package/dist/routes/play.js.map +1 -1
- package/dist/routes/playlist.js +2 -5
- package/dist/routes/playlist.js.map +1 -1
- package/dist/routes/root.js +43 -12
- package/dist/routes/root.js.map +1 -1
- package/dist/routes/streams.js +2 -8
- package/dist/routes/streams.js.map +1 -1
- package/dist/routes/theme.js +1 -4
- package/dist/routes/theme.js.map +1 -1
- package/dist/routes/ui.js +1 -4
- package/dist/routes/ui.js.map +1 -1
- package/dist/service/commands.js +1 -4
- package/dist/service/commands.js.map +1 -1
- package/dist/service/generators.js +4 -16
- package/dist/service/generators.js.map +1 -1
- package/dist/streaming/clients.js.map +1 -1
- package/dist/streaming/fmp4Segmenter.d.ts +1 -0
- package/dist/streaming/fmp4Segmenter.js +7 -12
- package/dist/streaming/fmp4Segmenter.js.map +1 -1
- package/dist/streaming/hls.d.ts +3 -0
- package/dist/streaming/hls.js +39 -21
- package/dist/streaming/hls.js.map +1 -1
- package/dist/streaming/hlsSegments.js +1 -4
- package/dist/streaming/hlsSegments.js.map +1 -1
- package/dist/streaming/lifecycle.js +1 -4
- package/dist/streaming/lifecycle.js.map +1 -1
- package/dist/streaming/monitor.d.ts +1 -0
- package/dist/streaming/monitor.js +296 -76
- package/dist/streaming/monitor.js.map +1 -1
- package/dist/streaming/mp4Parser.js.map +1 -1
- package/dist/streaming/mpegts.js +1 -4
- package/dist/streaming/mpegts.js.map +1 -1
- package/dist/streaming/registry.d.ts +7 -0
- package/dist/streaming/registry.js +10 -0
- package/dist/streaming/registry.js.map +1 -1
- package/dist/streaming/setup.d.ts +4 -1
- package/dist/streaming/setup.js +35 -33
- package/dist/streaming/setup.js.map +1 -1
- package/dist/streaming/showInfo.js +3 -6
- package/dist/streaming/showInfo.js.map +1 -1
- package/dist/streaming/statusEmitter.d.ts +2 -0
- package/dist/streaming/statusEmitter.js +2 -4
- package/dist/streaming/statusEmitter.js.map +1 -1
- package/dist/types/index.d.ts +34 -2
- package/dist/utils/errors.js +1 -4
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/evaluate.js +3 -6
- package/dist/utils/evaluate.js.map +1 -1
- package/dist/utils/ffmpeg.js +2 -8
- package/dist/utils/ffmpeg.js.map +1 -1
- package/dist/utils/fileLogger.js +9 -30
- package/dist/utils/fileLogger.js.map +1 -1
- package/dist/utils/format.d.ts +7 -0
- package/dist/utils/format.js +20 -0
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/html.js +1 -4
- package/dist/utils/html.js.map +1 -1
- package/dist/utils/logEmitter.js +1 -4
- package/dist/utils/logEmitter.js.map +1 -1
- package/dist/utils/logger.js +4 -16
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/m3u.js +1 -4
- package/dist/utils/m3u.js.map +1 -1
- package/dist/utils/morganStream.js +1 -4
- package/dist/utils/morganStream.js.map +1 -1
- package/dist/utils/platform.js.map +1 -1
- package/dist/utils/retry.js +1 -4
- package/dist/utils/retry.js.map +1 -1
- package/dist/utils/streamContext.js.map +1 -1
- package/package.json +3 -3
package/dist/config/profiles.js
CHANGED
|
@@ -1,274 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
/*
|
|
3
|
-
* SITE PROFILES SYSTEM
|
|
4
|
-
*
|
|
5
|
-
* Streaming sites implement their video players in wildly different ways. Some use standard HTML5 video with keyboard shortcuts, others embed players in iframes,
|
|
6
|
-
* and many have unique quirks like auto-muting or requiring specific fullscreen methods. Rather than scattering site-specific conditionals throughout the streaming
|
|
7
|
-
* code, we define "site profiles" that describe each site's behavior in a declarative way.
|
|
8
|
-
*
|
|
9
|
-
* The profile system has three components:
|
|
10
|
-
*
|
|
11
|
-
* 1. SITE_PROFILES: Named behavior configurations describing how to handle different player implementations. Profiles can inherit from other profiles using the
|
|
12
|
-
* "extends" property, allowing us to define base profiles for common patterns (like "keyboardFullscreen" for sites using the f key) and then extend them with
|
|
13
|
-
* site-specific variations.
|
|
14
|
-
*
|
|
15
|
-
* 2. DOMAIN_TO_PROFILE: A mapping from domain patterns to profile names. When streaming a URL, we check if it matches any known domain and use the corresponding
|
|
16
|
-
* profile. This is the primary mechanism for automatically selecting the right behavior.
|
|
17
|
-
*
|
|
18
|
-
* 3. Channel-level profile hints: Individual channel definitions can specify an explicit profile name, overriding URL-based detection. This is useful when a
|
|
19
|
-
* channel's URL doesn't match the expected domain pattern, or when the same domain serves multiple channel types that need different handling.
|
|
20
|
-
*
|
|
21
|
-
* Profile resolution happens at stream startup and the resolved profile is passed through the entire streaming pipeline. The profile flags control:
|
|
22
|
-
* - How fullscreen is triggered (keyboard shortcut vs JavaScript API)
|
|
23
|
-
* - Whether to search for video elements in iframes
|
|
24
|
-
* - Which video element to select when multiple exist
|
|
25
|
-
* - Whether to wait for network activity to settle before playback
|
|
26
|
-
* - Whether to lock volume properties to prevent auto-muting
|
|
27
|
-
* - Whether the page is static content (no video element expected)
|
|
28
|
-
*
|
|
29
|
-
* When adding support for a new streaming site, first check if an existing profile matches its behavior. Only create a new profile if the site requires unique
|
|
30
|
-
* handling not covered by existing profiles.
|
|
31
|
-
*/
|
|
32
|
-
/*
|
|
33
|
-
* SITE PROFILES
|
|
34
|
-
*
|
|
35
|
-
* Each profile defines a set of behavior flags that control how we interact with the video player. Profiles are organized in an inheritance hierarchy based on
|
|
36
|
-
* behavior patterns rather than site ownership. This makes it easier to identify the right profile when adding new channels.
|
|
37
|
-
*
|
|
38
|
-
* Base profiles (no extends):
|
|
39
|
-
* - keyboardFullscreen: Sites using the f key for fullscreen toggle
|
|
40
|
-
* - fullscreenApi: Sites requiring the JavaScript requestFullscreen() API
|
|
41
|
-
* - staticPage: Non-video pages captured as static visual content
|
|
42
|
-
*
|
|
43
|
-
* Derived profiles (extends a base):
|
|
44
|
-
* - keyboardDynamic: Keyboard fullscreen + network idle wait (extends keyboardFullscreen)
|
|
45
|
-
* - keyboardMultiVideo: Keyboard fullscreen + multi-video selection (extends keyboardFullscreen)
|
|
46
|
-
* - keyboardIframe: Keyboard fullscreen + iframe handling (extends keyboardFullscreen)
|
|
47
|
-
* - keyboardDynamicMultiVideo: Keyboard + network idle + multi-video selection (extends keyboardDynamic)
|
|
48
|
-
* - brightcove: Brightcove players using API fullscreen + network idle wait (extends fullscreenApi)
|
|
49
|
-
* - embeddedPlayer: Iframe-based players using fullscreen API (extends fullscreenApi)
|
|
50
|
-
* - apiMultiVideo: API fullscreen + multi-video + tile-based channel selection (extends fullscreenApi)
|
|
51
|
-
* - embeddedDynamicMultiVideo: Embedded + network idle + multi-video selection (extends embeddedPlayer)
|
|
52
|
-
* - embeddedVolumeLock: Embedded + volume property locking (extends embeddedPlayer)
|
|
53
|
-
*
|
|
54
|
-
* Each profile includes a description field documenting its purpose. This is metadata only - it's stripped during profile resolution and exists purely for
|
|
55
|
-
* documentation.
|
|
56
|
-
*/
|
|
57
|
-
export const SITE_PROFILES = {
|
|
58
|
-
// Profile for multi-channel live TV pages that present a grid or shelf of live channel tiles requiring tile-based selection followed by a play button click. Uses
|
|
59
|
-
// the fullscreen API and multi-video selection to find the actively playing stream after channel selection. Does not use iframe handling or network idle wait
|
|
60
|
-
// because these sites serve video directly in the main page and have persistent connections that prevent network idle.
|
|
61
|
-
apiMultiVideo: {
|
|
62
|
-
channelSelection: { strategy: "tileClick" },
|
|
63
|
-
description: "Multi-channel live TV pages requiring tile-based channel selection with API fullscreen.",
|
|
64
|
-
extends: "fullscreenApi",
|
|
65
|
-
selectReadyVideo: true,
|
|
66
|
-
summary: "Multi-channel live TV (tile selection)"
|
|
67
|
-
},
|
|
68
|
-
// Profile for sites using the Brightcove player platform. Brightcove players require waiting for network activity to settle before the video player is fully
|
|
69
|
-
// initialized. The player dynamically loads its configuration and stream manifest, so waitForNetworkIdle ensures we don't try to interact with the player before
|
|
70
|
-
// it's ready. Uses the JavaScript fullscreen API rather than keyboard shortcuts because Brightcove intercepts keyboard events.
|
|
71
|
-
brightcove: {
|
|
72
|
-
description: "Brightcove player sites requiring network idle wait and API fullscreen.",
|
|
73
|
-
extends: "fullscreenApi",
|
|
74
|
-
summary: "Brightcove players (network wait)",
|
|
75
|
-
waitForNetworkIdle: true
|
|
76
|
-
},
|
|
77
|
-
// Profile for iframe-embedded players that also have multiple video elements (ads, placeholders, main content) and need network activity to settle. The
|
|
78
|
-
// selectReadyVideo flag ensures we find the video with actual content rather than an ad placeholder. Combines iframe handling with API-based fullscreen.
|
|
79
|
-
embeddedDynamicMultiVideo: {
|
|
80
|
-
description: "Iframe-embedded players with multiple video elements requiring network idle wait.",
|
|
81
|
-
extends: "embeddedPlayer",
|
|
82
|
-
selectReadyVideo: true,
|
|
83
|
-
summary: "Embedded multi-video (network wait)",
|
|
84
|
-
waitForNetworkIdle: true
|
|
85
|
-
},
|
|
86
|
-
// Intermediate profile for sites that both embed their player in an iframe AND require the JavaScript fullscreen API. Many modern players use this architecture
|
|
87
|
-
// to isolate ad content and use programmatic fullscreen rather than keyboard shortcuts. This profile combines iframe handling with API-based fullscreen.
|
|
88
|
-
embeddedPlayer: {
|
|
89
|
-
description: "Intermediate base profile for iframe-embedded players using fullscreen API.",
|
|
90
|
-
extends: "fullscreenApi",
|
|
91
|
-
needsIframeHandling: true,
|
|
92
|
-
summary: "Embedded iframe players"
|
|
93
|
-
},
|
|
94
|
-
// Profile for iframe-embedded players that aggressively mute audio after page load - likely to comply with autoplay policies or for accessibility reasons. Some
|
|
95
|
-
// sites set video.muted = true even after we unmute it. The lockVolumeProperties flag uses Object.defineProperty to override the muted and volume getters/setters,
|
|
96
|
-
// preventing the site from re-muting the video.
|
|
97
|
-
embeddedVolumeLock: {
|
|
98
|
-
description: "Iframe-embedded players that aggressively mute audio after page load.",
|
|
99
|
-
extends: "embeddedPlayer",
|
|
100
|
-
lockVolumeProperties: true,
|
|
101
|
-
summary: "Embedded players that auto-mute"
|
|
102
|
-
},
|
|
103
|
-
// Base profile for sites that require the JavaScript fullscreen API (element.requestFullscreen()) instead of keyboard shortcuts. Many modern players intercept
|
|
104
|
-
// keyboard events for their own controls, making the f key unreliable. Calling requestFullscreen() directly on the video element bypasses the player's keyboard
|
|
105
|
-
// handling and reliably enters fullscreen mode.
|
|
106
|
-
fullscreenApi: {
|
|
107
|
-
description: "Base profile for sites requiring the JavaScript fullscreen API.",
|
|
108
|
-
summary: "Sites needing JavaScript fullscreen",
|
|
109
|
-
useRequestFullscreen: true
|
|
110
|
-
},
|
|
111
|
-
// 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
|
|
112
|
-
// 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.
|
|
113
|
-
keyboardDynamic: {
|
|
114
|
-
description: "Keyboard fullscreen sites requiring network idle wait for dynamic content loading.",
|
|
115
|
-
extends: "keyboardFullscreen",
|
|
116
|
-
summary: "Dynamic sites ('f' key fullscreen)",
|
|
117
|
-
waitForNetworkIdle: true
|
|
118
|
-
},
|
|
119
|
-
// Profile for multi-channel player pages that use keyboard fullscreen and need both network idle wait and multi-video selection. These pages present multiple
|
|
120
|
-
// channels to choose from, and the channelSelector property in the channel definition specifies which one to select. Extends keyboardDynamic to inherit network
|
|
121
|
-
// idle wait behavior. Uses thumbnailRow strategy for channel selection (find channel by thumbnail image URL, click adjacent show entry).
|
|
122
|
-
keyboardDynamicMultiVideo: {
|
|
123
|
-
channelSelection: { strategy: "thumbnailRow" },
|
|
124
|
-
description: "Multi-channel keyboard players requiring network idle wait and video selection.",
|
|
125
|
-
extends: "keyboardDynamic",
|
|
126
|
-
selectReadyVideo: true,
|
|
127
|
-
summary: "Multi-channel dynamic players"
|
|
128
|
-
},
|
|
129
|
-
// Base profile for sites that respond to the f key for fullscreen toggle. This is the most common fullscreen mechanism, following YouTube-style keyboard
|
|
130
|
-
// shortcuts. The f key is sent as a keyboard event to the page, triggering the player's built-in fullscreen toggle. This works with most standard video players.
|
|
131
|
-
keyboardFullscreen: {
|
|
132
|
-
description: "Base profile for sites that respond to the f key for fullscreen toggle.",
|
|
133
|
-
fullscreenKey: "f",
|
|
134
|
-
summary: "Standard 'f' key fullscreen"
|
|
135
|
-
},
|
|
136
|
-
// Profile for sites using keyboard fullscreen with video players embedded in iframes. The video element is not directly in the main page DOM, so we need to search
|
|
137
|
-
// through all frames to find it. Once found, the player responds to the standard f key for fullscreen.
|
|
138
|
-
keyboardIframe: {
|
|
139
|
-
description: "Keyboard fullscreen sites with video embedded in iframes.",
|
|
140
|
-
extends: "keyboardFullscreen",
|
|
141
|
-
needsIframeHandling: true,
|
|
142
|
-
summary: "Iframe players ('f' key fullscreen)"
|
|
143
|
-
},
|
|
144
|
-
// Profile for sites using keyboard fullscreen that load multiple video elements simultaneously - placeholder videos, ad videos, and the main content. We must find
|
|
145
|
-
// the video element that has actually loaded playable data (readyState >= 3) rather than just taking the first video element.
|
|
146
|
-
keyboardMultiVideo: {
|
|
147
|
-
description: "Keyboard fullscreen sites with multiple video elements requiring ready-state selection.",
|
|
148
|
-
extends: "keyboardFullscreen",
|
|
149
|
-
selectReadyVideo: true,
|
|
150
|
-
summary: "Multi-video sites ('f' key fullscreen)"
|
|
151
|
-
},
|
|
152
|
-
// Profile for non-video pages that should be captured as static visual content. Examples include weather displays (weatherscan.net), maps (windy.com), and
|
|
153
|
-
// 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.
|
|
154
|
-
staticPage: {
|
|
155
|
-
description: "Base profile for non-video pages captured as static visual content.",
|
|
156
|
-
noVideo: true,
|
|
157
|
-
summary: "Static pages (no video)"
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
/*
|
|
161
|
-
* DOMAIN TO PROFILE MAPPING
|
|
162
|
-
*
|
|
163
|
-
* This mapping associates domain patterns with profile names for automatic profile detection. When resolving a profile for a URL, we check if the URL contains any
|
|
164
|
-
* of these domain strings. Using string containment rather than exact hostname matching allows us to handle:
|
|
165
|
-
*
|
|
166
|
-
* - Subdomains: "www.nbc.com" matches "nbc.com"
|
|
167
|
-
* - Path-based matching: "example.com/live" would match "example.com"
|
|
168
|
-
* - Regional variations: "nbc.com.au" would match "nbc.com"
|
|
1
|
+
/* Copyright(C) 2024-2026, HJD (https://github.com/hjdhjd). All rights reserved.
|
|
169
2
|
*
|
|
170
|
-
*
|
|
171
|
-
* "site.com" both existed, the first matching entry would be used.
|
|
172
|
-
*
|
|
173
|
-
* Domains not listed here will use DEFAULT_SITE_PROFILE, which works for most standard video players. Only add entries here when a site requires specific handling.
|
|
174
|
-
*/
|
|
175
|
-
export const DOMAIN_TO_PROFILE = {
|
|
176
|
-
// Sites with multiple video elements requiring ready-state selection.
|
|
177
|
-
"abc.com": "keyboardMultiVideo",
|
|
178
|
-
// Brightcove player sites requiring network idle wait.
|
|
179
|
-
"c-span.org": "brightcove",
|
|
180
|
-
// Keyboard fullscreen sites with iframe-embedded players.
|
|
181
|
-
"cbs.com": "keyboardIframe",
|
|
182
|
-
// Sites using the JavaScript fullscreen API.
|
|
183
|
-
"cnbc.com": "fullscreenApi",
|
|
184
|
-
"cnn.com": "fullscreenApi",
|
|
185
|
-
// Tile-based channel selection from the shared live TV page.
|
|
186
|
-
"disneyplus.com": "apiMultiVideo",
|
|
187
|
-
// Sites using the JavaScript fullscreen API.
|
|
188
|
-
"foodnetwork.com": "fullscreenApi",
|
|
189
|
-
// Iframe-embedded players with complex multi-video setup.
|
|
190
|
-
"foxbusiness.com": "embeddedDynamicMultiVideo",
|
|
191
|
-
"foxnews.com": "embeddedDynamicMultiVideo",
|
|
192
|
-
// Sites using the JavaScript fullscreen API.
|
|
193
|
-
"foxsports.com": "fullscreenApi",
|
|
194
|
-
// Iframe-embedded players that require volume locking.
|
|
195
|
-
"france24.com": "embeddedVolumeLock",
|
|
196
|
-
// Sites using the JavaScript fullscreen API.
|
|
197
|
-
"hbomax.com": "fullscreenApi",
|
|
198
|
-
// Keyboard fullscreen sites with dynamic content loading.
|
|
199
|
-
"ms.now": "keyboardDynamic",
|
|
200
|
-
// Keyboard fullscreen sites with dynamic content and multiple video elements.
|
|
201
|
-
"nationalgeographic.com": "keyboardDynamicMultiVideo",
|
|
202
|
-
// Keyboard fullscreen sites with dynamic content loading.
|
|
203
|
-
"nbc.com": "keyboardDynamic",
|
|
204
|
-
// Sites using the JavaScript fullscreen API.
|
|
205
|
-
"paramountplus.com": "fullscreenApi",
|
|
206
|
-
"tbs.com": "fullscreenApi",
|
|
207
|
-
"tntdrama.com": "fullscreenApi",
|
|
208
|
-
// Multi-channel keyboard players with dynamic content.
|
|
209
|
-
"usanetwork.com": "keyboardDynamicMultiVideo",
|
|
210
|
-
// Sites using the JavaScript fullscreen API.
|
|
211
|
-
"vh1.com": "fullscreenApi",
|
|
212
|
-
// Static pages without video content.
|
|
213
|
-
"weatherscan.net": "staticPage",
|
|
214
|
-
"windy.com": "staticPage",
|
|
215
|
-
// Sites using the JavaScript fullscreen API.
|
|
216
|
-
"wttw.com": "fullscreenApi",
|
|
217
|
-
// Keyboard fullscreen sites with dynamic content loading.
|
|
218
|
-
"youtube.com": "keyboardDynamic"
|
|
219
|
-
};
|
|
220
|
-
/*
|
|
221
|
-
* DEFAULT SITE PROFILE
|
|
222
|
-
*
|
|
223
|
-
* The default profile provides baseline behavior for sites not explicitly listed in the domain mapping or channel definitions. These settings work for most
|
|
224
|
-
* standard HTML5 video players that follow common conventions. Each flag is explicitly set to its default value for documentation purposes and to ensure
|
|
225
|
-
* predictable behavior - we don't rely on implicit defaults.
|
|
226
|
-
*
|
|
227
|
-
* Sites matching the default profile:
|
|
228
|
-
* - Use standard HTML5 video without iframe embedding
|
|
229
|
-
* - Have a single video element on the page
|
|
230
|
-
* - Don't require clicking to start playback
|
|
231
|
-
* - Don't auto-mute aggressively
|
|
232
|
-
* - Don't require waiting for network activity
|
|
233
|
-
* - Have video content (not static pages)
|
|
234
|
-
*
|
|
235
|
-
* Neither keyboard fullscreen nor API fullscreen is enabled by default because many sites work fine without explicit fullscreen triggering - the video is already
|
|
236
|
-
* displayed at full size in the viewport. Fullscreen is only needed when the player has visible controls or surrounding content that we want to hide.
|
|
3
|
+
* profiles.ts: Site profile resolution and validation for PrismCast.
|
|
237
4
|
*/
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
channelSelector: null,
|
|
243
|
-
// Don't click to play - most sites start automatically or via other mechanisms.
|
|
244
|
-
clickToPlay: false,
|
|
245
|
-
// No fullscreen key - many players work without explicit fullscreen.
|
|
246
|
-
fullscreenKey: null,
|
|
247
|
-
// Don't lock volume properties - most sites don't aggressively mute.
|
|
248
|
-
lockVolumeProperties: false,
|
|
249
|
-
// Don't search iframes - assume video is in main page DOM.
|
|
250
|
-
needsIframeHandling: false,
|
|
251
|
-
// Expect video content - wait for video element.
|
|
252
|
-
noVideo: false,
|
|
253
|
-
// Use first video element - assume only one video exists.
|
|
254
|
-
selectReadyVideo: false,
|
|
255
|
-
// Don't use requestFullscreen() API.
|
|
256
|
-
useRequestFullscreen: false,
|
|
257
|
-
// Don't wait for network idle - assume player is ready on page load.
|
|
258
|
-
waitForNetworkIdle: false
|
|
259
|
-
};
|
|
5
|
+
import { DEFAULT_SITE_PROFILE, DOMAIN_CONFIG, SITE_PROFILES, getDomainConfig } from "./sites.js";
|
|
6
|
+
import { CHANNELS } from "../channels/index.js";
|
|
7
|
+
// Re-export site data so existing consumers can import from either module.
|
|
8
|
+
export { DEFAULT_SITE_PROFILE, DOMAIN_CONFIG, SITE_PROFILES, getDomainConfig };
|
|
260
9
|
/*
|
|
261
|
-
* PROFILE RESOLUTION
|
|
262
|
-
*
|
|
263
10
|
* Profile resolution is the process of determining which behavior flags to use for a given stream. The resolution process handles inheritance, merging parent and
|
|
264
11
|
* child profile properties, and falling back to defaults for unspecified flags.
|
|
265
12
|
*
|
|
266
13
|
* Resolution order (highest to lowest priority):
|
|
14
|
+
*
|
|
267
15
|
* 1. Channel's explicit profile property (if specified)
|
|
268
|
-
* 2. URL-based detection via
|
|
16
|
+
* 2. URL-based detection via DOMAIN_CONFIG
|
|
269
17
|
* 3. DEFAULT_SITE_PROFILE
|
|
270
18
|
*
|
|
271
19
|
* Within a profile, inheritance works as follows:
|
|
20
|
+
*
|
|
272
21
|
* 1. Start with DEFAULT_SITE_PROFILE for base values
|
|
273
22
|
* 2. Apply parent profile properties (if extends is set)
|
|
274
23
|
* 3. Apply current profile properties (overriding parent)
|
|
@@ -281,6 +30,7 @@ export const DEFAULT_SITE_PROFILE = {
|
|
|
281
30
|
* is resolved recursively, with child profile properties overriding parent properties.
|
|
282
31
|
*
|
|
283
32
|
* The resolution process:
|
|
33
|
+
*
|
|
284
34
|
* 1. Start with a copy of DEFAULT_SITE_PROFILE
|
|
285
35
|
* 2. If the profile extends another, recursively resolve the parent and merge its properties
|
|
286
36
|
* 3. Merge the current profile's properties, overriding any inherited values
|
|
@@ -309,20 +59,17 @@ export function resolveProfile(profileName) {
|
|
|
309
59
|
const parent = resolveProfile(profile.extends);
|
|
310
60
|
resolved = { ...resolved, ...parent };
|
|
311
61
|
}
|
|
312
|
-
// Apply current profile properties, excluding metadata fields that should not be
|
|
313
|
-
//
|
|
62
|
+
// Apply current profile properties, excluding metadata fields that should not be in the resolved profile. The category, description, extends, and summary
|
|
63
|
+
// properties are for UI categorization, documentation, inheritance specification, and UI display only.
|
|
314
64
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
315
|
-
const { description: _description, extends: _extends, ...profileFlags } = profile;
|
|
65
|
+
const { category: _category, description: _description, extends: _extends, summary: _summary, ...profileFlags } = profile;
|
|
316
66
|
resolved = { ...resolved, ...profileFlags };
|
|
317
67
|
return resolved;
|
|
318
68
|
}
|
|
319
69
|
/**
|
|
320
|
-
* Resolves the site profile for a given URL by
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
* The matching is done by checking if the URL contains the domain string anywhere. This is simpler than hostname extraction and handles edge cases like URLs with
|
|
324
|
-
* unusual formatting.
|
|
325
|
-
*
|
|
70
|
+
* Resolves the site profile for a given URL by looking it up in DOMAIN_CONFIG via getDomainConfig(), which tries the full hostname first for subdomain-specific
|
|
71
|
+
* overrides before falling back to the concise domain. Falls back to the default profile if no matching domain is found or the matching domain has no profile
|
|
72
|
+
* configured.
|
|
326
73
|
* @param url - The URL to resolve a profile for.
|
|
327
74
|
* @returns The site profile containing behavior flags.
|
|
328
75
|
*/
|
|
@@ -331,16 +78,18 @@ export function getProfileForUrl(url) {
|
|
|
331
78
|
if (!url) {
|
|
332
79
|
return { profile: { ...DEFAULT_SITE_PROFILE }, profileName: "default" };
|
|
333
80
|
}
|
|
334
|
-
//
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
81
|
+
// Look up the domain configuration, trying the full hostname first for subdomain-specific overrides (e.g., "tv.youtube.com" before "youtube.com").
|
|
82
|
+
const config = getDomainConfig(url);
|
|
83
|
+
// Resolve the profile from the domain configuration, falling back to the default profile for unrecognized domains or domains without a profile entry.
|
|
84
|
+
const profile = config?.profile ? resolveProfile(config.profile) : { ...DEFAULT_SITE_PROFILE };
|
|
85
|
+
const profileName = config?.profile ?? "default";
|
|
86
|
+
// Merge domain-level properties that represent site policies rather than player behaviors. maxContinuousPlayback is a site-imposed session limit, not a player
|
|
87
|
+
// characteristic, so it lives in DOMAIN_CONFIG rather than in site profiles. Note: getProfileForChannel() performs this same merge for the explicit-profile path
|
|
88
|
+
// where this function is bypassed. If adding new domain-level policies here, update getProfileForChannel() as well.
|
|
89
|
+
if (config?.maxContinuousPlayback !== undefined) {
|
|
90
|
+
profile.maxContinuousPlayback = config.maxContinuousPlayback;
|
|
341
91
|
}
|
|
342
|
-
|
|
343
|
-
return { profile: { ...DEFAULT_SITE_PROFILE }, profileName: "default" };
|
|
92
|
+
return { profile, profileName };
|
|
344
93
|
}
|
|
345
94
|
/**
|
|
346
95
|
* Resolves the site profile for a channel. Channels can explicitly declare their profile by name, which takes precedence over URL-based detection. This is useful
|
|
@@ -380,6 +129,15 @@ export function getProfileForChannel(channel) {
|
|
|
380
129
|
profile = { ...DEFAULT_SITE_PROFILE };
|
|
381
130
|
profileName = "default";
|
|
382
131
|
}
|
|
132
|
+
// Merge domain-level site policies that apply regardless of how the profile was resolved. These represent site-imposed constraints (like session duration limits)
|
|
133
|
+
// rather than player behaviors, so they must always be applied based on the channel's URL even when the player profile is explicitly overridden. For the URL-based
|
|
134
|
+
// path above, getProfileForUrl() already merges these — the re-application here is idempotent. For the explicit-profile path, this fills the gap.
|
|
135
|
+
if (channel.url) {
|
|
136
|
+
const domainConfig = getDomainConfig(channel.url);
|
|
137
|
+
if (domainConfig?.maxContinuousPlayback !== undefined) {
|
|
138
|
+
profile = { ...profile, maxContinuousPlayback: domainConfig.maxContinuousPlayback };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
383
141
|
// Merge channel-specific properties into the profile. Currently only channelSelector is supported, which specifies a CSS selector for the channel button in
|
|
384
142
|
// multi-channel player pages. The channelSelector on the channel overrides any channelSelector from the profile.
|
|
385
143
|
if (channel.channelSelector) {
|
|
@@ -388,8 +146,6 @@ export function getProfileForChannel(channel) {
|
|
|
388
146
|
return { profile, profileName };
|
|
389
147
|
}
|
|
390
148
|
/*
|
|
391
|
-
* PROFILE VALIDATION
|
|
392
|
-
*
|
|
393
149
|
* Before starting the server, we validate all profile configurations to catch errors early. Invalid configurations would cause runtime failures that are difficult
|
|
394
150
|
* to diagnose:
|
|
395
151
|
*
|
|
@@ -406,6 +162,7 @@ export function getProfileForChannel(channel) {
|
|
|
406
162
|
* function runs at startup before the server begins accepting connections.
|
|
407
163
|
*
|
|
408
164
|
* Validation checks:
|
|
165
|
+
*
|
|
409
166
|
* 1. Circular inheritance detection - walks the extends chain for each profile to detect cycles
|
|
410
167
|
* 2. Invalid extends references - ensures all extends targets exist
|
|
411
168
|
* 3. Domain mapping validation - ensures all domain profile references exist
|
|
@@ -438,11 +195,13 @@ export function validateProfiles() {
|
|
|
438
195
|
}
|
|
439
196
|
}
|
|
440
197
|
}
|
|
441
|
-
// Validate all domain-to-profile mappings reference existing profiles. This catches typos in
|
|
442
|
-
for (const [domain,
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
198
|
+
// Validate all domain-to-profile mappings reference existing profiles. This catches typos in DOMAIN_CONFIG profile entries.
|
|
199
|
+
for (const [domain, config] of Object.entries(DOMAIN_CONFIG)) {
|
|
200
|
+
if (config.profile) {
|
|
201
|
+
const domainProfile = SITE_PROFILES[config.profile];
|
|
202
|
+
if (!domainProfile) {
|
|
203
|
+
errors.push(["Domain ", domain, " references non-existent profile: ", config.profile].join(""));
|
|
204
|
+
}
|
|
446
205
|
}
|
|
447
206
|
}
|
|
448
207
|
// Validate all channel profile references point to existing profiles. This catches typos in channel definitions.
|
|
@@ -459,14 +218,15 @@ export function validateProfiles() {
|
|
|
459
218
|
}
|
|
460
219
|
}
|
|
461
220
|
/**
|
|
462
|
-
* Returns all profiles with their descriptions and summaries, sorted alphabetically by name. Used by the channel configuration UI to populate the
|
|
463
|
-
* dropdown with tooltips and the profile reference section.
|
|
221
|
+
* Returns all profiles with their descriptions, categories, and summaries, sorted alphabetically by name. Used by the channel configuration UI to populate the
|
|
222
|
+
* profile dropdown with tooltips and the profile reference section.
|
|
464
223
|
* @returns Array of profile info objects.
|
|
465
224
|
*/
|
|
466
225
|
export function getProfiles() {
|
|
467
226
|
return Object.keys(SITE_PROFILES).sort().map((name) => {
|
|
468
227
|
const profile = SITE_PROFILES[name];
|
|
469
228
|
return {
|
|
229
|
+
category: profile.category ?? "special",
|
|
470
230
|
description: profile.description ?? "",
|
|
471
231
|
name,
|
|
472
232
|
summary: profile.summary ?? profile.description ?? ""
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profiles.js","sourceRoot":"","sources":["../../src/config/profiles.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"profiles.js","sourceRoot":"","sources":["../../src/config/profiles.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Channel, ChannelMap, ProviderGroup } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Builds provider groups by scanning all channels and grouping them by key patterns. A key like "espn-disneyplus" is a variant of "espn" because it starts with
|
|
4
|
+
* "espn-". Should be called at startup after channels are loaded.
|
|
5
|
+
* @param channels - The merged channel map (predefined + user channels).
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildProviderGroups(channels: ChannelMap): void;
|
|
8
|
+
/**
|
|
9
|
+
* Resolves a URL to a friendly provider display name. Checks DOMAIN_CONFIG via getDomainConfig() for a provider name, trying the full hostname first for
|
|
10
|
+
* subdomain-specific overrides before falling back to the concise domain. Returns the raw domain string if no provider name is configured.
|
|
11
|
+
* @param url - The URL to resolve a provider display name for.
|
|
12
|
+
* @returns The provider display name, or the concise domain if no provider name is configured.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getProviderDisplayName(url: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Gets the provider group for a channel key. Works with both canonical and variant keys.
|
|
17
|
+
* @param key - Any channel key in the group.
|
|
18
|
+
* @returns The provider group if the channel is part of a multi-provider group, undefined otherwise.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getProviderGroup(key: string): ProviderGroup | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Checks if a channel key is a non-canonical provider variant. Used to filter variants from channel listings.
|
|
23
|
+
* @param key - The channel key to check.
|
|
24
|
+
* @returns True if the key is a variant (not canonical) in a provider group.
|
|
25
|
+
*/
|
|
26
|
+
export declare function isProviderVariant(key: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Checks if a channel has multiple provider options. Used to determine whether to show a provider dropdown in the UI.
|
|
29
|
+
* @param key - The channel key to check.
|
|
30
|
+
* @returns True if the channel has more than one provider variant.
|
|
31
|
+
*/
|
|
32
|
+
export declare function hasMultipleProviders(key: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Gets the canonical key for any channel key. For variant keys, returns the canonical key. For non-grouped or canonical keys, returns the input unchanged.
|
|
35
|
+
* Handles the PREDEFINED_SUFFIX used when a user has overridden a predefined channel.
|
|
36
|
+
* @param key - Any channel key.
|
|
37
|
+
* @returns The canonical key for the channel's provider group, or the input key if not part of a group.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getCanonicalKey(key: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* Sets the user's provider selections. Called when loading from channels.json.
|
|
42
|
+
* @param selections - Provider selections keyed by canonical channel key.
|
|
43
|
+
*/
|
|
44
|
+
export declare function setProviderSelections(selections: Record<string, string>): void;
|
|
45
|
+
/**
|
|
46
|
+
* Gets all provider selections.
|
|
47
|
+
* @returns Copy of the provider selections object.
|
|
48
|
+
*/
|
|
49
|
+
export declare function getProviderSelections(): Record<string, string>;
|
|
50
|
+
/**
|
|
51
|
+
* Gets the provider selection for a specific channel.
|
|
52
|
+
* @param canonicalKey - The canonical channel key.
|
|
53
|
+
* @returns The selected provider key, or undefined if using the default.
|
|
54
|
+
*/
|
|
55
|
+
export declare function getProviderSelection(canonicalKey: string): string | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Sets the provider selection for a channel.
|
|
58
|
+
* @param canonicalKey - The canonical channel key.
|
|
59
|
+
* @param providerKey - The selected provider key.
|
|
60
|
+
*/
|
|
61
|
+
export declare function setProviderSelection(canonicalKey: string, providerKey: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* Resolves a canonical channel key to the actual channel key based on user selection. If the user has selected a specific provider for this channel, returns that
|
|
64
|
+
* provider's key. Otherwise returns the canonical key (default provider).
|
|
65
|
+
* @param canonicalKey - The canonical channel key.
|
|
66
|
+
* @returns The resolved provider key to use for streaming.
|
|
67
|
+
*/
|
|
68
|
+
export declare function resolveProviderKey(canonicalKey: string): string;
|
|
69
|
+
/**
|
|
70
|
+
* Gets a channel with inheritance applied. For provider variants, this merges the variant's properties with inherited properties from the canonical entry.
|
|
71
|
+
* Inherited properties: `name`, `stationId`. Explicit properties on the variant take precedence.
|
|
72
|
+
* @param key - The channel key (canonical or variant).
|
|
73
|
+
* @returns The complete channel with inheritance applied, or undefined if the channel doesn't exist.
|
|
74
|
+
*/
|
|
75
|
+
export declare function getResolvedChannel(key: string): Channel | undefined;
|