prismcast 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -1
- package/dist/app.js +29 -2
- package/dist/app.js.map +1 -1
- package/dist/browser/cdp.js +1 -1
- package/dist/browser/cdp.js.map +1 -1
- package/dist/browser/channelSelection.d.ts +14 -4
- package/dist/browser/channelSelection.js +48 -704
- package/dist/browser/channelSelection.js.map +1 -1
- package/dist/browser/index.d.ts +18 -4
- package/dist/browser/index.js +205 -39
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/tuning/fox.d.ts +19 -0
- package/dist/browser/tuning/fox.js +61 -0
- package/dist/browser/tuning/fox.js.map +1 -0
- package/dist/browser/tuning/hbo.d.ts +22 -0
- package/dist/browser/tuning/hbo.js +182 -0
- package/dist/browser/tuning/hbo.js.map +1 -0
- package/dist/browser/tuning/hulu.d.ts +30 -0
- package/dist/browser/tuning/hulu.js +514 -0
- package/dist/browser/tuning/hulu.js.map +1 -0
- package/dist/browser/tuning/sling.d.ts +22 -0
- package/dist/browser/tuning/sling.js +287 -0
- package/dist/browser/tuning/sling.js.map +1 -0
- package/dist/browser/tuning/thumbnailRow.d.ts +18 -0
- package/dist/browser/tuning/thumbnailRow.js +107 -0
- package/dist/browser/tuning/thumbnailRow.js.map +1 -0
- package/dist/browser/tuning/tileClick.d.ts +18 -0
- package/dist/browser/tuning/tileClick.js +102 -0
- package/dist/browser/tuning/tileClick.js.map +1 -0
- package/dist/browser/tuning/youtubeTv.d.ts +17 -0
- package/dist/browser/tuning/youtubeTv.js +99 -0
- package/dist/browser/tuning/youtubeTv.js.map +1 -0
- package/dist/browser/video.d.ts +2 -2
- package/dist/browser/video.js +18 -8
- package/dist/browser/video.js.map +1 -1
- package/dist/channels/index.js +131 -12
- package/dist/channels/index.js.map +1 -1
- package/dist/config/profiles.d.ts +5 -5
- package/dist/config/profiles.js +35 -11
- package/dist/config/profiles.js.map +1 -1
- package/dist/config/providers.d.ts +48 -4
- package/dist/config/providers.js +182 -22
- package/dist/config/providers.js.map +1 -1
- package/dist/config/sites.d.ts +10 -0
- package/dist/config/sites.js +96 -17
- package/dist/config/sites.js.map +1 -1
- package/dist/config/userChannels.js +21 -3
- package/dist/config/userChannels.js.map +1 -1
- package/dist/config/userConfig.d.ts +2 -1
- package/dist/config/userConfig.js +12 -4
- package/dist/config/userConfig.js.map +1 -1
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/routes/auth.js +6 -0
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/config.d.ts +5 -0
- package/dist/routes/config.js +273 -35
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/debug.d.ts +6 -0
- package/dist/routes/debug.js +274 -0
- package/dist/routes/debug.js.map +1 -0
- package/dist/routes/index.d.ts +1 -0
- package/dist/routes/index.js +3 -0
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/logs.js +17 -5
- package/dist/routes/logs.js.map +1 -1
- package/dist/routes/root.js +507 -128
- package/dist/routes/root.js.map +1 -1
- package/dist/routes/theme.js +7 -0
- package/dist/routes/theme.js.map +1 -1
- package/dist/service/commands.js +8 -8
- package/dist/service/commands.js.map +1 -1
- package/dist/service/generators.js +22 -16
- package/dist/service/generators.js.map +1 -1
- package/dist/streaming/fmp4Segmenter.d.ts +7 -0
- package/dist/streaming/fmp4Segmenter.js +124 -15
- package/dist/streaming/fmp4Segmenter.js.map +1 -1
- package/dist/streaming/hls.d.ts +74 -6
- package/dist/streaming/hls.js +212 -130
- package/dist/streaming/hls.js.map +1 -1
- package/dist/streaming/hlsSegments.js +11 -4
- package/dist/streaming/hlsSegments.js.map +1 -1
- package/dist/streaming/lifecycle.js +1 -1
- package/dist/streaming/lifecycle.js.map +1 -1
- package/dist/streaming/monitor.d.ts +1 -1
- package/dist/streaming/monitor.js +202 -53
- package/dist/streaming/monitor.js.map +1 -1
- package/dist/streaming/mp4Parser.d.ts +29 -1
- package/dist/streaming/mp4Parser.js +243 -18
- package/dist/streaming/mp4Parser.js.map +1 -1
- package/dist/streaming/mpegts.d.ts +5 -2
- package/dist/streaming/mpegts.js +122 -29
- package/dist/streaming/mpegts.js.map +1 -1
- package/dist/streaming/registry.d.ts +1 -1
- package/dist/streaming/registry.js.map +1 -1
- package/dist/streaming/setup.d.ts +13 -1
- package/dist/streaming/setup.js +136 -36
- package/dist/streaming/setup.js.map +1 -1
- package/dist/streaming/showInfo.js +9 -9
- package/dist/streaming/showInfo.js.map +1 -1
- package/dist/streaming/statusEmitter.js +5 -6
- package/dist/streaming/statusEmitter.js.map +1 -1
- package/dist/types/index.d.ts +16 -3
- package/dist/types/index.js +5 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/debugFilter.d.ts +38 -0
- package/dist/utils/debugFilter.js +157 -0
- package/dist/utils/debugFilter.js.map +1 -0
- package/dist/utils/evaluate.js.map +1 -1
- package/dist/utils/ffmpeg.d.ts +5 -0
- package/dist/utils/ffmpeg.js +13 -2
- package/dist/utils/ffmpeg.js.map +1 -1
- package/dist/utils/fileLogger.d.ts +2 -1
- package/dist/utils/fileLogger.js +4 -2
- package/dist/utils/fileLogger.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/logEmitter.d.ts +1 -0
- package/dist/utils/logEmitter.js.map +1 -1
- package/dist/utils/logger.d.ts +9 -8
- package/dist/utils/logger.js +52 -28
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/retry.d.ts +1 -1
- package/dist/utils/retry.js +3 -3
- package/dist/utils/retry.js.map +1 -1
- package/dist/utils/version.js +4 -9
- package/dist/utils/version.js.map +1 -1
- package/package.json +6 -6
|
@@ -1,4 +1,48 @@
|
|
|
1
1
|
import type { Channel, ChannelMap, ProviderGroup } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Gets the provider tag for a channel key. For variant keys (e.g., "espn-hulu"), extracts the suffix after the canonical prefix (e.g., "hulu"). For canonical keys,
|
|
4
|
+
* looks up the URL domain via getDomainConfig() and reads the providerTag field, falling back to "direct" if not found.
|
|
5
|
+
* @param key - The channel key.
|
|
6
|
+
* @returns The provider tag string.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getProviderTagForChannel(key: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Returns all provider tags for a channel (canonical tag + all variant suffix tags). Used to determine which providers offer this channel.
|
|
11
|
+
* @param canonicalKey - The canonical channel key.
|
|
12
|
+
* @returns Array of provider tag strings.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getChannelProviderTags(canonicalKey: string): string[];
|
|
15
|
+
/**
|
|
16
|
+
* Scans all provider groups and collects unique provider tags with display names. Display names are derived from the provider field in DOMAIN_CONFIG entries that
|
|
17
|
+
* have a providerTag, with any trailing parenthetical stripped (e.g., "Hulu (Live Guide)" becomes "Hulu").
|
|
18
|
+
* @returns Array of { displayName, tag } objects sorted alphabetically by display name, with "direct" always first.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getAllProviderTags(): {
|
|
21
|
+
displayName: string;
|
|
22
|
+
tag: string;
|
|
23
|
+
}[];
|
|
24
|
+
/**
|
|
25
|
+
* Gets the current enabled provider tags.
|
|
26
|
+
* @returns Copy of the enabled providers array. Empty means no filter (all shown).
|
|
27
|
+
*/
|
|
28
|
+
export declare function getEnabledProviders(): string[];
|
|
29
|
+
/**
|
|
30
|
+
* Sets the enabled provider tags. Empty array means "no filter" (all providers shown).
|
|
31
|
+
* @param tags - The provider tags to enable.
|
|
32
|
+
*/
|
|
33
|
+
export declare function setEnabledProviders(tags: string[]): void;
|
|
34
|
+
/**
|
|
35
|
+
* Checks if a provider tag is currently enabled. Returns true if the tag is enabled, if no filter is active (empty set), or if the tag is "direct".
|
|
36
|
+
* @param tag - The provider tag to check.
|
|
37
|
+
* @returns True if the provider is available.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isProviderTagEnabled(tag: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Centralized availability check for the provider filter. Returns true if the channel has at least one variant whose provider tag is enabled.
|
|
42
|
+
* @param canonicalKey - The canonical channel key.
|
|
43
|
+
* @returns True if the channel passes the provider filter.
|
|
44
|
+
*/
|
|
45
|
+
export declare function isChannelAvailableByProvider(canonicalKey: string): boolean;
|
|
2
46
|
/**
|
|
3
47
|
* 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
48
|
* "espn-". Should be called at startup after channels are loaded.
|
|
@@ -6,9 +50,8 @@ import type { Channel, ChannelMap, ProviderGroup } from "../types/index.js";
|
|
|
6
50
|
*/
|
|
7
51
|
export declare function buildProviderGroups(channels: ChannelMap): void;
|
|
8
52
|
/**
|
|
9
|
-
* Resolves a URL to a friendly provider display name. Checks DOMAIN_CONFIG for a provider name
|
|
10
|
-
*
|
|
11
|
-
* is preferred over a raw domain like "hulu.com".
|
|
53
|
+
* Resolves a URL to a friendly provider display name. Checks DOMAIN_CONFIG via getDomainConfig() for a provider name, trying the full hostname first for
|
|
54
|
+
* subdomain-specific overrides before falling back to the concise domain. Returns the raw domain string if no provider name is configured.
|
|
12
55
|
* @param url - The URL to resolve a provider display name for.
|
|
13
56
|
* @returns The provider display name, or the concise domain if no provider name is configured.
|
|
14
57
|
*/
|
|
@@ -62,7 +105,8 @@ export declare function getProviderSelection(canonicalKey: string): string | und
|
|
|
62
105
|
export declare function setProviderSelection(canonicalKey: string, providerKey: string): void;
|
|
63
106
|
/**
|
|
64
107
|
* 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
|
|
65
|
-
* provider's key. Otherwise returns the canonical key (default provider).
|
|
108
|
+
* provider's key. Otherwise returns the canonical key (default provider). When the provider filter is active, falls back to the first enabled variant if the stored
|
|
109
|
+
* selection's provider is filtered out.
|
|
66
110
|
* @param canonicalKey - The canonical channel key.
|
|
67
111
|
* @returns The resolved provider key to use for streaming.
|
|
68
112
|
*/
|
package/dist/config/providers.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { DOMAIN_CONFIG, getDomainConfig } from "./sites.js";
|
|
1
2
|
import { LOG, extractDomain } from "../utils/index.js";
|
|
2
|
-
import { DOMAIN_CONFIG } from "./sites.js";
|
|
3
3
|
import { PREDEFINED_CHANNELS } from "../channels/index.js";
|
|
4
4
|
/* Provider groups allow multiple streaming providers to offer the same content. For example, ESPN can be watched via ESPN.com (native) or Disney+.
|
|
5
5
|
*
|
|
@@ -25,7 +25,143 @@ const providerGroups = new Map();
|
|
|
25
25
|
// Reference to the channels map for inheritance resolution.
|
|
26
26
|
let channelsRef = {};
|
|
27
27
|
// User's provider selections, keyed by canonical channel key. Values are the selected provider key (e.g., "espn-disneyplus").
|
|
28
|
-
let providerSelections =
|
|
28
|
+
let providerSelections = new Map();
|
|
29
|
+
// Provider Tag System.
|
|
30
|
+
// Module-level state for the provider filter. Empty array means "no filter" (all providers shown). Non-empty means only these tags are active.
|
|
31
|
+
let enabledProviders = [];
|
|
32
|
+
/**
|
|
33
|
+
* Gets the provider tag for a channel key. For variant keys (e.g., "espn-hulu"), extracts the suffix after the canonical prefix (e.g., "hulu"). For canonical keys,
|
|
34
|
+
* looks up the URL domain via getDomainConfig() and reads the providerTag field, falling back to "direct" if not found.
|
|
35
|
+
* @param key - The channel key.
|
|
36
|
+
* @returns The provider tag string.
|
|
37
|
+
*/
|
|
38
|
+
export function getProviderTagForChannel(key) {
|
|
39
|
+
const group = providerGroups.get(key);
|
|
40
|
+
// For variant keys, the suffix after the canonical key (minus the hyphen) IS the tag.
|
|
41
|
+
if (group && (group.canonicalKey !== key)) {
|
|
42
|
+
const suffix = key.slice(group.canonicalKey.length + 1);
|
|
43
|
+
return suffix;
|
|
44
|
+
}
|
|
45
|
+
// For canonical keys, derive from the URL domain via DOMAIN_CONFIG.
|
|
46
|
+
const channel = channelsRef[key] ?? PREDEFINED_CHANNELS[key];
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
48
|
+
if (!channel) {
|
|
49
|
+
return "direct";
|
|
50
|
+
}
|
|
51
|
+
const config = getDomainConfig(channel.url);
|
|
52
|
+
return config?.providerTag ?? "direct";
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Returns all provider tags for a channel (canonical tag + all variant suffix tags). Used to determine which providers offer this channel.
|
|
56
|
+
* @param canonicalKey - The canonical channel key.
|
|
57
|
+
* @returns Array of provider tag strings.
|
|
58
|
+
*/
|
|
59
|
+
export function getChannelProviderTags(canonicalKey) {
|
|
60
|
+
const tags = new Set();
|
|
61
|
+
// Add the canonical entry's tag.
|
|
62
|
+
tags.add(getProviderTagForChannel(canonicalKey));
|
|
63
|
+
// Add tags for all variants.
|
|
64
|
+
const group = providerGroups.get(canonicalKey);
|
|
65
|
+
if (group) {
|
|
66
|
+
for (const variant of group.variants) {
|
|
67
|
+
// Skip predefined suffix variants — they share the canonical's tag.
|
|
68
|
+
if (variant.key.endsWith(PREDEFINED_SUFFIX)) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
tags.add(getProviderTagForChannel(variant.key));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return [...tags];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Scans all provider groups and collects unique provider tags with display names. Display names are derived from the provider field in DOMAIN_CONFIG entries that
|
|
78
|
+
* have a providerTag, with any trailing parenthetical stripped (e.g., "Hulu (Live Guide)" becomes "Hulu").
|
|
79
|
+
* @returns Array of { displayName, tag } objects sorted alphabetically by display name, with "direct" always first.
|
|
80
|
+
*/
|
|
81
|
+
export function getAllProviderTags() {
|
|
82
|
+
const tags = new Set();
|
|
83
|
+
// Scan all channels (not just grouped ones) to find all provider tags.
|
|
84
|
+
const allKeys = new Set([...Object.keys(channelsRef), ...Object.keys(PREDEFINED_CHANNELS)]);
|
|
85
|
+
for (const key of allKeys) {
|
|
86
|
+
// Skip variant keys — they are covered by getChannelProviderTags() on the canonical.
|
|
87
|
+
const group = providerGroups.get(key);
|
|
88
|
+
if (group && (group.canonicalKey !== key)) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const channelTags = getChannelProviderTags(key);
|
|
92
|
+
for (const tag of channelTags) {
|
|
93
|
+
tags.add(tag);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Build a tag → display name map from DOMAIN_CONFIG's provider fields, stripping any trailing parenthetical (e.g., "Hulu (Live Guide)" → "Hulu"). First match wins
|
|
97
|
+
// for each tag.
|
|
98
|
+
const tagDisplayNames = new Map();
|
|
99
|
+
tagDisplayNames.set("direct", "Direct");
|
|
100
|
+
for (const config of Object.values(DOMAIN_CONFIG)) {
|
|
101
|
+
if (config.providerTag && config.provider && !tagDisplayNames.has(config.providerTag)) {
|
|
102
|
+
tagDisplayNames.set(config.providerTag, config.provider.replace(/\s*\(.*\)$/, ""));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Build result with display names.
|
|
106
|
+
const result = [];
|
|
107
|
+
for (const tag of tags) {
|
|
108
|
+
result.push({ displayName: tagDisplayNames.get(tag) ?? tag, tag });
|
|
109
|
+
}
|
|
110
|
+
// Sort alphabetically by display name, but keep "direct" first.
|
|
111
|
+
result.sort((a, b) => {
|
|
112
|
+
if (a.tag === "direct") {
|
|
113
|
+
return -1;
|
|
114
|
+
}
|
|
115
|
+
if (b.tag === "direct") {
|
|
116
|
+
return 1;
|
|
117
|
+
}
|
|
118
|
+
return a.displayName.localeCompare(b.displayName);
|
|
119
|
+
});
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Gets the current enabled provider tags.
|
|
124
|
+
* @returns Copy of the enabled providers array. Empty means no filter (all shown).
|
|
125
|
+
*/
|
|
126
|
+
export function getEnabledProviders() {
|
|
127
|
+
return [...enabledProviders];
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Sets the enabled provider tags. Empty array means "no filter" (all providers shown).
|
|
131
|
+
* @param tags - The provider tags to enable.
|
|
132
|
+
*/
|
|
133
|
+
export function setEnabledProviders(tags) {
|
|
134
|
+
enabledProviders = [...tags];
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Checks if a provider tag is currently enabled. Returns true if the tag is enabled, if no filter is active (empty set), or if the tag is "direct".
|
|
138
|
+
* @param tag - The provider tag to check.
|
|
139
|
+
* @returns True if the provider is available.
|
|
140
|
+
*/
|
|
141
|
+
export function isProviderTagEnabled(tag) {
|
|
142
|
+
// No filter active — all providers are enabled.
|
|
143
|
+
if (enabledProviders.length === 0) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
// "direct" is always enabled.
|
|
147
|
+
if (tag === "direct") {
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
return enabledProviders.includes(tag);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Centralized availability check for the provider filter. Returns true if the channel has at least one variant whose provider tag is enabled.
|
|
154
|
+
* @param canonicalKey - The canonical channel key.
|
|
155
|
+
* @returns True if the channel passes the provider filter.
|
|
156
|
+
*/
|
|
157
|
+
export function isChannelAvailableByProvider(canonicalKey) {
|
|
158
|
+
// No filter active — all channels are available.
|
|
159
|
+
if (enabledProviders.length === 0) {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
const tags = getChannelProviderTags(canonicalKey);
|
|
163
|
+
return tags.some((tag) => isProviderTagEnabled(tag));
|
|
164
|
+
}
|
|
29
165
|
/**
|
|
30
166
|
* Checks if a channel in the merged map is a user override of a predefined channel. This uses object reference comparison — getAllChannels() spreads
|
|
31
167
|
* PREDEFINED_CHANNELS directly into the result, so if the reference differs, a user channel has replaced the predefined one.
|
|
@@ -95,7 +231,7 @@ export function buildProviderGroups(channels) {
|
|
|
95
231
|
for (const variantKey of variantKeys) {
|
|
96
232
|
providerGroups.set(variantKey, group);
|
|
97
233
|
}
|
|
98
|
-
LOG.debug("Provider group '%s': variants=%s.", canonicalKey, variants.map((v) => v.key).join(", "));
|
|
234
|
+
LOG.debug("config", "Provider group '%s': variants=%s.", canonicalKey, variants.map((v) => v.key).join(", "));
|
|
99
235
|
}
|
|
100
236
|
// Second pass: Create groups for user overrides that don't have predefined variants. This allows users who override a single-provider channel (like nbc) to still
|
|
101
237
|
// switch between their custom definition and the original predefined version.
|
|
@@ -122,23 +258,18 @@ export function buildProviderGroups(channels) {
|
|
|
122
258
|
];
|
|
123
259
|
const group = { canonicalKey: key, variants };
|
|
124
260
|
providerGroups.set(key, group);
|
|
125
|
-
LOG.debug("Provider group '%s' (override): variants=%s.", key, variants.map((v) => v.key).join(", "));
|
|
261
|
+
LOG.debug("config", "Provider group '%s' (override): variants=%s.", key, variants.map((v) => v.key).join(", "));
|
|
126
262
|
}
|
|
127
263
|
}
|
|
128
264
|
/**
|
|
129
|
-
* Resolves a URL to a friendly provider display name. Checks DOMAIN_CONFIG for a provider name
|
|
130
|
-
*
|
|
131
|
-
* is preferred over a raw domain like "hulu.com".
|
|
265
|
+
* Resolves a URL to a friendly provider display name. Checks DOMAIN_CONFIG via getDomainConfig() for a provider name, trying the full hostname first for
|
|
266
|
+
* subdomain-specific overrides before falling back to the concise domain. Returns the raw domain string if no provider name is configured.
|
|
132
267
|
* @param url - The URL to resolve a provider display name for.
|
|
133
268
|
* @returns The provider display name, or the concise domain if no provider name is configured.
|
|
134
269
|
*/
|
|
135
270
|
export function getProviderDisplayName(url) {
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
// exist at runtime.
|
|
139
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
140
|
-
const provider = DOMAIN_CONFIG[domain]?.provider;
|
|
141
|
-
return provider ?? domain;
|
|
271
|
+
const config = getDomainConfig(url);
|
|
272
|
+
return config?.provider ?? extractDomain(url);
|
|
142
273
|
}
|
|
143
274
|
/**
|
|
144
275
|
* Gets the provider group for a channel key. Works with both canonical and variant keys.
|
|
@@ -183,14 +314,14 @@ export function getCanonicalKey(key) {
|
|
|
183
314
|
* @param selections - Provider selections keyed by canonical channel key.
|
|
184
315
|
*/
|
|
185
316
|
export function setProviderSelections(selections) {
|
|
186
|
-
providerSelections =
|
|
317
|
+
providerSelections = new Map(Object.entries(selections));
|
|
187
318
|
}
|
|
188
319
|
/**
|
|
189
320
|
* Gets all provider selections.
|
|
190
321
|
* @returns Copy of the provider selections object.
|
|
191
322
|
*/
|
|
192
323
|
export function getProviderSelections() {
|
|
193
|
-
return
|
|
324
|
+
return Object.fromEntries(providerSelections);
|
|
194
325
|
}
|
|
195
326
|
/**
|
|
196
327
|
* Gets the provider selection for a specific channel.
|
|
@@ -198,7 +329,7 @@ export function getProviderSelections() {
|
|
|
198
329
|
* @returns The selected provider key, or undefined if using the default.
|
|
199
330
|
*/
|
|
200
331
|
export function getProviderSelection(canonicalKey) {
|
|
201
|
-
return providerSelections
|
|
332
|
+
return providerSelections.get(canonicalKey);
|
|
202
333
|
}
|
|
203
334
|
/**
|
|
204
335
|
* Sets the provider selection for a channel.
|
|
@@ -208,22 +339,27 @@ export function getProviderSelection(canonicalKey) {
|
|
|
208
339
|
export function setProviderSelection(canonicalKey, providerKey) {
|
|
209
340
|
// If selecting the canonical (default), remove the selection instead of storing it.
|
|
210
341
|
if (providerKey === canonicalKey) {
|
|
211
|
-
delete
|
|
342
|
+
providerSelections.delete(canonicalKey);
|
|
212
343
|
}
|
|
213
344
|
else {
|
|
214
|
-
providerSelections
|
|
345
|
+
providerSelections.set(canonicalKey, providerKey);
|
|
215
346
|
}
|
|
216
347
|
}
|
|
217
348
|
/**
|
|
218
349
|
* 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
|
|
219
|
-
* provider's key. Otherwise returns the canonical key (default provider).
|
|
350
|
+
* provider's key. Otherwise returns the canonical key (default provider). When the provider filter is active, falls back to the first enabled variant if the stored
|
|
351
|
+
* selection's provider is filtered out.
|
|
220
352
|
* @param canonicalKey - The canonical channel key.
|
|
221
353
|
* @returns The resolved provider key to use for streaming.
|
|
222
354
|
*/
|
|
223
355
|
export function resolveProviderKey(canonicalKey) {
|
|
224
|
-
const selection = providerSelections
|
|
356
|
+
const selection = providerSelections.get(canonicalKey);
|
|
225
357
|
// No selection stored — use the canonical key (default provider).
|
|
226
358
|
if (!selection) {
|
|
359
|
+
// If the canonical's provider tag is filtered out, find the first enabled variant.
|
|
360
|
+
if ((enabledProviders.length > 0) && !isProviderTagEnabled(getProviderTagForChannel(canonicalKey))) {
|
|
361
|
+
return findFirstEnabledVariant(canonicalKey) ?? canonicalKey;
|
|
362
|
+
}
|
|
227
363
|
return canonicalKey;
|
|
228
364
|
}
|
|
229
365
|
// Handle :predefined suffix — validate that the base key exists in PREDEFINED_CHANNELS.
|
|
@@ -239,14 +375,38 @@ export function resolveProviderKey(canonicalKey) {
|
|
|
239
375
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
240
376
|
}
|
|
241
377
|
else if (channelsRef[selection]) {
|
|
242
|
-
// Normal selection — validate it exists in the merged channels.
|
|
378
|
+
// Normal selection — validate it exists in the merged channels. If its provider tag is filtered out, find the first enabled variant instead.
|
|
379
|
+
if ((enabledProviders.length > 0) && !isProviderTagEnabled(getProviderTagForChannel(selection))) {
|
|
380
|
+
return findFirstEnabledVariant(canonicalKey) ?? selection;
|
|
381
|
+
}
|
|
243
382
|
return selection;
|
|
244
383
|
}
|
|
245
384
|
// Selection is invalid (provider removed). Clear it and log a warning.
|
|
246
385
|
LOG.warn("Provider selection '%s' for channel '%s' no longer exists. Using default.", selection, canonicalKey);
|
|
247
|
-
delete
|
|
386
|
+
providerSelections.delete(canonicalKey);
|
|
248
387
|
return canonicalKey;
|
|
249
388
|
}
|
|
389
|
+
/**
|
|
390
|
+
* Finds the first enabled variant for a channel when the current selection's provider is filtered out. Iterates the group's variants and returns the first whose
|
|
391
|
+
* provider tag is enabled.
|
|
392
|
+
* @param canonicalKey - The canonical channel key.
|
|
393
|
+
* @returns The first enabled variant key, or undefined if none are enabled.
|
|
394
|
+
*/
|
|
395
|
+
function findFirstEnabledVariant(canonicalKey) {
|
|
396
|
+
const group = providerGroups.get(canonicalKey);
|
|
397
|
+
if (!group) {
|
|
398
|
+
return undefined;
|
|
399
|
+
}
|
|
400
|
+
for (const variant of group.variants) {
|
|
401
|
+
if (variant.key.endsWith(PREDEFINED_SUFFIX)) {
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
if (isProviderTagEnabled(getProviderTagForChannel(variant.key))) {
|
|
405
|
+
return variant.key;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return undefined;
|
|
409
|
+
}
|
|
250
410
|
/**
|
|
251
411
|
* Gets a channel with inheritance applied. For provider variants, this merges the variant's properties with inherited properties from the canonical entry.
|
|
252
412
|
* Inherited properties: `name`, `stationId`. Explicit properties on the variant take precedence.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/config/providers.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/config/providers.ts"],"names":[],"mappings":"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"}
|
package/dist/config/sites.d.ts
CHANGED
|
@@ -5,8 +5,18 @@ export declare const SITE_PROFILES: Record<string, SiteProfile>;
|
|
|
5
5
|
* configuration and/or a provider display name for friendly UI labels.
|
|
6
6
|
*/
|
|
7
7
|
export interface DomainConfig {
|
|
8
|
+
loginUrl?: string;
|
|
9
|
+
maxContinuousPlayback?: number;
|
|
8
10
|
profile?: string;
|
|
11
|
+
providerTag?: string;
|
|
9
12
|
provider?: string;
|
|
10
13
|
}
|
|
11
14
|
export declare const DOMAIN_CONFIG: Record<string, DomainConfig>;
|
|
15
|
+
/**
|
|
16
|
+
* Resolves a URL to its DOMAIN_CONFIG entry by trying the full hostname first for subdomain-specific overrides, then falling back to the concise domain (last two
|
|
17
|
+
* hostname parts). This allows entries like "tv.youtube.com" to override the base "youtube.com" entry when the URL matches the more-specific subdomain.
|
|
18
|
+
* @param url - The URL to resolve a domain configuration for.
|
|
19
|
+
* @returns The matching DomainConfig entry, or undefined if no match is found.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getDomainConfig(url: string): DomainConfig | undefined;
|
|
12
22
|
export declare const DEFAULT_SITE_PROFILE: ResolvedSiteProfile;
|
package/dist/config/sites.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { extractDomain } from "../utils/index.js";
|
|
1
2
|
/*
|
|
2
3
|
* Streaming sites implement their video players in wildly different ways. Some use standard HTML5 video with keyboard shortcuts, others embed players in iframes,
|
|
3
4
|
* and many have unique quirks like auto-muting or requiring specific fullscreen methods. Rather than scattering site-specific conditionals throughout the streaming
|
|
@@ -50,6 +51,9 @@
|
|
|
50
51
|
* - huluLive: Hulu Live TV with guide grid channel selection + fullscreen button (extends fullscreenApi)
|
|
51
52
|
* - embeddedDynamicMultiVideo: Embedded + network idle + multi-video selection (extends embeddedPlayer)
|
|
52
53
|
* - embeddedVolumeLock: Embedded + volume property locking (extends embeddedPlayer)
|
|
54
|
+
* - foxLive: Fox.com live guide grid with station code channel selection (extends fullscreenApi)
|
|
55
|
+
* - slingLive: Sling TV with virtualized A-Z guide grid channel selection (extends fullscreenApi)
|
|
56
|
+
* - youtubeTV: YouTube TV with non-virtualized EPG grid channel selection (extends fullscreenApi)
|
|
53
57
|
*
|
|
54
58
|
* Each profile includes a description field documenting its purpose. This is metadata only - it's stripped during profile resolution and exists purely for
|
|
55
59
|
* documentation.
|
|
@@ -61,7 +65,7 @@ export const SITE_PROFILES = {
|
|
|
61
65
|
apiMultiVideo: {
|
|
62
66
|
category: "multiChannel",
|
|
63
67
|
channelSelection: { strategy: "tileClick" },
|
|
64
|
-
description: "Multi-channel sites with tile-based channel grid.
|
|
68
|
+
description: "Multi-channel sites with tile-based channel grid. Set Channel Selector to a unique string from the channel's tile image URL.",
|
|
65
69
|
extends: "fullscreenApi",
|
|
66
70
|
selectReadyVideo: true,
|
|
67
71
|
summary: "Multi-channel (tile selection, needs selector)"
|
|
@@ -132,6 +136,17 @@ export const SITE_PROFILES = {
|
|
|
132
136
|
lockVolumeProperties: true,
|
|
133
137
|
summary: "Embedded players that auto-mute"
|
|
134
138
|
},
|
|
139
|
+
// Profile for Fox.com live channel guide grid. The guide page presents all channels in a non-virtualized grid with station codes in the channel logo button
|
|
140
|
+
// titles (e.g., FOXD2C, FNC, FS1). The channelSelector property matches against these station codes. Clicking the channel logo button is an SPA state
|
|
141
|
+
// transition — the player at the top of the page switches channels without navigation. The grid renders dynamically after page load, so the strategy waits
|
|
142
|
+
// for GuideChannelContainer elements before scanning.
|
|
143
|
+
foxLive: {
|
|
144
|
+
category: "multiChannel",
|
|
145
|
+
channelSelection: { strategy: "foxGrid" },
|
|
146
|
+
description: "Fox.com live channel guide. Set Channel Selector to the station code (e.g., BTN, FOXD2C, FS1).",
|
|
147
|
+
extends: "fullscreenApi",
|
|
148
|
+
summary: "Fox Live (guide grid, needs selector)"
|
|
149
|
+
},
|
|
135
150
|
// Base profile for sites that require the JavaScript fullscreen API (element.requestFullscreen()) instead of keyboard shortcuts. Many modern players intercept
|
|
136
151
|
// keyboard events for their own controls, making the f key unreliable. Calling requestFullscreen() directly on the video element bypasses the player's keyboard
|
|
137
152
|
// handling and reliably enters fullscreen mode.
|
|
@@ -141,6 +156,16 @@ export const SITE_PROFILES = {
|
|
|
141
156
|
summary: "Sites needing JavaScript fullscreen",
|
|
142
157
|
useRequestFullscreen: true
|
|
143
158
|
},
|
|
159
|
+
// Profile for HBO Max live channels (play.hbomax.com). The HBO brand page contains a "Distribution Channels" rail showing all 5 live linear channels (HBO, HBO
|
|
160
|
+
// Hits, HBO Drama, HBO Comedy, HBO Movies) as tiles. The hboGrid strategy discovers the HBO tab URL from the homepage menu bar, navigates to it, then scrapes the
|
|
161
|
+
// channel rail for the watch URL matching the channelSelector name. Extends fullscreenApi for requestFullscreen() behavior inherited by the watch page.
|
|
162
|
+
hboMax: {
|
|
163
|
+
category: "multiChannel",
|
|
164
|
+
channelSelection: { strategy: "hboGrid" },
|
|
165
|
+
description: "HBO Max with live channel rail selection. Set Channel Selector to the channel name (e.g., HBO, HBO Hits).",
|
|
166
|
+
extends: "fullscreenApi",
|
|
167
|
+
summary: "HBO Max (live channels, needs selector)"
|
|
168
|
+
},
|
|
144
169
|
// Profile for Hulu Live TV which presents a guide grid of live channels. The channel list is revealed by clicking a tab (listSelector), then the desired channel
|
|
145
170
|
// is found by matching img.alt text. Uses the fullscreen API (inherited from fullscreenApi) plus a dedicated fullscreen button selector for the player's native
|
|
146
171
|
// maximize control. Requires selectReadyVideo because the page may have multiple video elements (ads, previews, main content). Uses waitForNetworkIdle because
|
|
@@ -149,7 +174,7 @@ export const SITE_PROFILES = {
|
|
|
149
174
|
huluLive: {
|
|
150
175
|
category: "multiChannel",
|
|
151
176
|
channelSelection: { listSelector: "#CHANNELS", playSelector: "[data-testid=\"generic-tile-thumbnail\"]", strategy: "guideGrid" },
|
|
152
|
-
description: "Hulu Live TV with guide grid channel selection.
|
|
177
|
+
description: "Hulu Live TV with guide grid channel selection. Set Channel Selector to the channel's internal guide name (may differ from logo).",
|
|
153
178
|
extends: "fullscreenApi",
|
|
154
179
|
fullscreenSelector: "[aria-label=\"Maximize\"]",
|
|
155
180
|
selectReadyVideo: true,
|
|
@@ -171,7 +196,7 @@ export const SITE_PROFILES = {
|
|
|
171
196
|
keyboardDynamicMultiVideo: {
|
|
172
197
|
category: "multiChannel",
|
|
173
198
|
channelSelection: { strategy: "thumbnailRow" },
|
|
174
|
-
description: "Multi-channel sites with thumbnail row layout.
|
|
199
|
+
description: "Multi-channel sites with thumbnail row layout. Set Channel Selector to a unique string from the channel's thumbnail image URL.",
|
|
175
200
|
extends: "keyboardDynamic",
|
|
176
201
|
selectReadyVideo: true,
|
|
177
202
|
summary: "Multi-channel (thumbnail row, needs selector)"
|
|
@@ -202,6 +227,18 @@ export const SITE_PROFILES = {
|
|
|
202
227
|
selectReadyVideo: true,
|
|
203
228
|
summary: "Multi-video sites ('f' key fullscreen)"
|
|
204
229
|
},
|
|
230
|
+
// Profile for Sling TV (watch.sling.com) live guide grid. The A-Z guide at /dashboard/grid_guide/grid_guide_a_z renders a virtualized grid of ~638 rows
|
|
231
|
+
// (120px each) with channel identification via data-testid="channel-{NAME}" attributes. The slingGrid strategy performs binary search on .guide-cell scrollTop
|
|
232
|
+
// to locate the target channel, then clicks the on-now program cell which navigates to a player page where a single <video> element auto-plays. Extends
|
|
233
|
+
// fullscreenApi for requestFullscreen() behavior. Does not use waitForNetworkIdle — the strategy's own waitForSelector on channel entries is the readiness
|
|
234
|
+
// signal, and the SPA's persistent connections would delay network idle unnecessarily.
|
|
235
|
+
slingLive: {
|
|
236
|
+
category: "multiChannel",
|
|
237
|
+
channelSelection: { strategy: "slingGrid" },
|
|
238
|
+
description: "Sling TV with guide grid channel selection. Set Channel Selector to the channel's internal guide name (may differ from logo).",
|
|
239
|
+
extends: "fullscreenApi",
|
|
240
|
+
summary: "Sling TV (guide grid, needs selector)"
|
|
241
|
+
},
|
|
205
242
|
// Profile for non-video pages that should be captured as static visual content. Examples include weather displays (weatherscan.net), maps (windy.com), and
|
|
206
243
|
// 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.
|
|
207
244
|
staticPage: {
|
|
@@ -209,53 +246,93 @@ export const SITE_PROFILES = {
|
|
|
209
246
|
description: "Base profile for non-video pages captured as static visual content.",
|
|
210
247
|
noVideo: true,
|
|
211
248
|
summary: "Static pages (no video)"
|
|
249
|
+
},
|
|
250
|
+
// Profile for YouTube TV (tv.youtube.com/live). The guide grid renders all ~256 channel rows in the DOM simultaneously (no virtualization), each containing a
|
|
251
|
+
// direct watch URL. The youtubeGrid strategy performs a single querySelector to find the target channel's watch link via aria-label, extracts the URL, and
|
|
252
|
+
// navigates directly — no scrolling, clicking, or timing workarounds needed. Uses selectReadyVideo because the watch page has ~36 video elements (live preview
|
|
253
|
+
// thumbnails from the guide) but only one active stream with readyState >= 3 and videoWidth > 0. Extends fullscreenApi because requestFullscreen() works
|
|
254
|
+
// directly on the active video element without gesture requirements.
|
|
255
|
+
youtubeTV: {
|
|
256
|
+
category: "multiChannel",
|
|
257
|
+
channelSelection: { strategy: "youtubeGrid" },
|
|
258
|
+
description: "YouTube TV with EPG grid channel selection. Set Channel Selector to the channel name as shown in the guide (e.g., CNN, ESPN, NBC).",
|
|
259
|
+
extends: "fullscreenApi",
|
|
260
|
+
selectReadyVideo: true,
|
|
261
|
+
summary: "YouTube TV (guide grid, needs selector)"
|
|
212
262
|
}
|
|
213
263
|
};
|
|
214
|
-
/* This mapping associates
|
|
215
|
-
*
|
|
216
|
-
* the
|
|
264
|
+
/* This mapping associates domain keys with site profiles, provider display names, and provider filter tags. Most keys are concise second-level domains
|
|
265
|
+
* (e.g., "nbc.com", "foodnetwork.com") matching the output of extractDomain(). Keys can also be full hostnames (e.g., "tv.youtube.com") for subdomain-specific
|
|
266
|
+
* overrides — getDomainConfig() tries the full hostname first, then falls back to the concise domain, so "tv.youtube.com" takes precedence over "youtube.com"
|
|
267
|
+
* when the URL matches.
|
|
217
268
|
*
|
|
218
269
|
* Domains without a profile entry will use DEFAULT_SITE_PROFILE, which works for most standard video players. Domains without a provider entry will display the
|
|
219
|
-
* concise domain string (e.g., "hulu.com") in the UI.
|
|
270
|
+
* concise domain string (e.g., "hulu.com") in the UI. Entries with a providerTag participate in the provider filter system — channels whose canonical URL maps to
|
|
271
|
+
* a tagged domain are identified as belonging to that subscription service rather than being tagged as "direct" (free network sites).
|
|
220
272
|
*/
|
|
221
273
|
export const DOMAIN_CONFIG = {
|
|
222
274
|
"abc.com": { profile: "keyboardMultiVideo", provider: "ABC.com" },
|
|
223
|
-
"aetv.com": { provider: "A&E" },
|
|
275
|
+
"aetv.com": { profile: "fullscreenApi", provider: "A&E" },
|
|
224
276
|
"bet.com": { profile: "fullscreenApi", provider: "BET.com" },
|
|
225
277
|
"c-span.org": { profile: "brightcove", provider: "C-SPAN.org" },
|
|
226
278
|
"cbs.com": { profile: "keyboardIframe", provider: "CBS.com" },
|
|
227
279
|
"cnbc.com": { profile: "fullscreenApi", provider: "CNBC.com" },
|
|
228
280
|
"cnn.com": { profile: "fullscreenApi", provider: "CNN.com" },
|
|
229
281
|
"disneynow.com": { profile: "disneyNow", provider: "DisneyNOW" },
|
|
230
|
-
"disneyplus.com": { profile: "apiMultiVideo", provider: "Disney+" },
|
|
282
|
+
"disneyplus.com": { profile: "apiMultiVideo", provider: "Disney+", providerTag: "disneyplus" },
|
|
231
283
|
"espn.com": { profile: "keyboardMultiVideo", provider: "ESPN.com" },
|
|
232
284
|
"foodnetwork.com": { profile: "fullscreenApi", provider: "Food Network" },
|
|
285
|
+
"fox.com": { loginUrl: "https://www.fox.com", profile: "foxLive", provider: "Fox", providerTag: "foxcom" },
|
|
233
286
|
"foxbusiness.com": { profile: "embeddedDynamicMultiVideo", provider: "Fox Business" },
|
|
234
287
|
"foxnews.com": { profile: "embeddedDynamicMultiVideo", provider: "Fox News" },
|
|
235
288
|
"foxsports.com": { profile: "fullscreenApi", provider: "Fox Sports" },
|
|
236
289
|
"france24.com": { profile: "embeddedVolumeLock", provider: "France 24" },
|
|
237
|
-
"fyi.tv": { provider: "FYI" },
|
|
290
|
+
"fyi.tv": { profile: "fullscreenApi", provider: "FYI" },
|
|
238
291
|
"golfchannel.com": { profile: "fullscreenApi", provider: "Golf Channel" },
|
|
239
|
-
"hbomax.com": { profile: "
|
|
240
|
-
"history.com": { provider: "History.com" },
|
|
241
|
-
"hulu.com": { profile: "huluLive", provider: "Hulu" },
|
|
292
|
+
"hbomax.com": { profile: "hboMax", provider: "HBO Max", providerTag: "hbomax" },
|
|
293
|
+
"history.com": { profile: "fullscreenApi", provider: "History.com" },
|
|
294
|
+
"hulu.com": { profile: "huluLive", provider: "Hulu (Live Guide)", providerTag: "hulu" },
|
|
242
295
|
"lakeshorepbs.org": { profile: "embeddedPlayer", provider: "Lakeshore PBS" },
|
|
243
296
|
"ms.now": { profile: "keyboardDynamic", provider: "MSNOW" },
|
|
244
|
-
"mylifetime.com": { provider: "Lifetime" },
|
|
297
|
+
"mylifetime.com": { profile: "fullscreenApi", provider: "Lifetime" },
|
|
245
298
|
"nationalgeographic.com": { profile: "keyboardDynamicMultiVideo", provider: "Nat Geo" },
|
|
246
|
-
"
|
|
247
|
-
"
|
|
299
|
+
"nba.com": { profile: "fullscreenApi", provider: "NBA.com" },
|
|
300
|
+
"nbc.com": { maxContinuousPlayback: 4, profile: "keyboardDynamic", provider: "NBC.com" },
|
|
301
|
+
"paramountplus.com": { profile: "fullscreenApi", provider: "Paramount+", providerTag: "paramountplus" },
|
|
248
302
|
"sling.com": { profile: "embeddedVolumeLock", provider: "Sling TV" },
|
|
249
303
|
"tbs.com": { profile: "fullscreenApi", provider: "TBS.com" },
|
|
250
304
|
"tntdrama.com": { profile: "fullscreenApi", provider: "TNT" },
|
|
251
305
|
"trutv.com": { profile: "fullscreenApi", provider: "truTV" },
|
|
252
|
-
"
|
|
306
|
+
"tv.youtube.com": { profile: "youtubeTV", provider: "YouTube TV", providerTag: "yttv" },
|
|
307
|
+
"usanetwork.com": { profile: "keyboardDynamicMultiVideo", provider: "USA Network", providerTag: "usa" },
|
|
253
308
|
"vh1.com": { profile: "fullscreenApi", provider: "VH1.com" },
|
|
309
|
+
"watch.sling.com": { profile: "slingLive", provider: "Sling TV (Live Guide)", providerTag: "sling" },
|
|
310
|
+
"watchhallmarktv.com": { profile: "fullscreenApi", provider: "Hallmark" },
|
|
254
311
|
"weatherscan.net": { profile: "staticPage", provider: "Weatherscan" },
|
|
255
312
|
"windy.com": { profile: "staticPage", provider: "Windy" },
|
|
256
313
|
"wttw.com": { profile: "fullscreenApi", provider: "WTTW" },
|
|
257
314
|
"youtube.com": { profile: "keyboardDynamic", provider: "YouTube" }
|
|
258
315
|
};
|
|
316
|
+
/**
|
|
317
|
+
* Resolves a URL to its DOMAIN_CONFIG entry by trying the full hostname first for subdomain-specific overrides, then falling back to the concise domain (last two
|
|
318
|
+
* hostname parts). This allows entries like "tv.youtube.com" to override the base "youtube.com" entry when the URL matches the more-specific subdomain.
|
|
319
|
+
* @param url - The URL to resolve a domain configuration for.
|
|
320
|
+
* @returns The matching DomainConfig entry, or undefined if no match is found.
|
|
321
|
+
*/
|
|
322
|
+
export function getDomainConfig(url) {
|
|
323
|
+
try {
|
|
324
|
+
const hostname = new URL(url).hostname;
|
|
325
|
+
// Try the full hostname first for subdomain-specific overrides (e.g., "tv.youtube.com" before "youtube.com").
|
|
326
|
+
const hostnameMatch = DOMAIN_CONFIG[hostname];
|
|
327
|
+
if (hostnameMatch) {
|
|
328
|
+
return hostnameMatch;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
catch {
|
|
332
|
+
// Invalid URL — fall through to concise domain lookup.
|
|
333
|
+
}
|
|
334
|
+
return DOMAIN_CONFIG[extractDomain(url)];
|
|
335
|
+
}
|
|
259
336
|
/* The default profile provides baseline behavior for sites not explicitly listed in the domain mapping or channel definitions. These settings work for most
|
|
260
337
|
* standard HTML5 video players that follow common conventions. Each flag is explicitly set to its default value for documentation purposes and to ensure
|
|
261
338
|
* predictable behavior - we don't rely on implicit defaults.
|
|
@@ -286,6 +363,8 @@ export const DEFAULT_SITE_PROFILE = {
|
|
|
286
363
|
fullscreenSelector: null,
|
|
287
364
|
// Don't lock volume properties - most sites don't aggressively mute.
|
|
288
365
|
lockVolumeProperties: false,
|
|
366
|
+
// No continuous playback limit - most sites allow indefinite streaming.
|
|
367
|
+
maxContinuousPlayback: null,
|
|
289
368
|
// Don't search iframes - assume video is in main page DOM.
|
|
290
369
|
needsIframeHandling: false,
|
|
291
370
|
// Expect video content - wait for video element.
|