@bnhf/prismcast 1.3.4-2026.2.19

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 (234) hide show
  1. package/LICENSE.md +7 -0
  2. package/README.md +347 -0
  3. package/bin/prismcast +6 -0
  4. package/dist/app.d.ts +6 -0
  5. package/dist/app.js +315 -0
  6. package/dist/app.js.map +1 -0
  7. package/dist/browser/cdp.d.ts +38 -0
  8. package/dist/browser/cdp.js +155 -0
  9. package/dist/browser/cdp.js.map +1 -0
  10. package/dist/browser/channelSelection.d.ts +65 -0
  11. package/dist/browser/channelSelection.js +202 -0
  12. package/dist/browser/channelSelection.js.map +1 -0
  13. package/dist/browser/display.d.ts +34 -0
  14. package/dist/browser/display.js +54 -0
  15. package/dist/browser/display.js.map +1 -0
  16. package/dist/browser/index.d.ts +205 -0
  17. package/dist/browser/index.js +1205 -0
  18. package/dist/browser/index.js.map +1 -0
  19. package/dist/browser/tuning/fox.d.ts +2 -0
  20. package/dist/browser/tuning/fox.js +83 -0
  21. package/dist/browser/tuning/fox.js.map +1 -0
  22. package/dist/browser/tuning/hbo.d.ts +2 -0
  23. package/dist/browser/tuning/hbo.js +237 -0
  24. package/dist/browser/tuning/hbo.js.map +1 -0
  25. package/dist/browser/tuning/hulu.d.ts +2 -0
  26. package/dist/browser/tuning/hulu.js +550 -0
  27. package/dist/browser/tuning/hulu.js.map +1 -0
  28. package/dist/browser/tuning/sling.d.ts +2 -0
  29. package/dist/browser/tuning/sling.js +518 -0
  30. package/dist/browser/tuning/sling.js.map +1 -0
  31. package/dist/browser/tuning/thumbnailRow.d.ts +2 -0
  32. package/dist/browser/tuning/thumbnailRow.js +108 -0
  33. package/dist/browser/tuning/thumbnailRow.js.map +1 -0
  34. package/dist/browser/tuning/tileClick.d.ts +2 -0
  35. package/dist/browser/tuning/tileClick.js +103 -0
  36. package/dist/browser/tuning/tileClick.js.map +1 -0
  37. package/dist/browser/tuning/youtubeTv.d.ts +2 -0
  38. package/dist/browser/tuning/youtubeTv.js +182 -0
  39. package/dist/browser/tuning/youtubeTv.js.map +1 -0
  40. package/dist/browser/video.d.ts +289 -0
  41. package/dist/browser/video.js +996 -0
  42. package/dist/browser/video.js.map +1 -0
  43. package/dist/channels/index.d.ts +3 -0
  44. package/dist/channels/index.js +392 -0
  45. package/dist/channels/index.js.map +1 -0
  46. package/dist/config/index.d.ts +53 -0
  47. package/dist/config/index.js +233 -0
  48. package/dist/config/index.js.map +1 -0
  49. package/dist/config/presets.d.ts +98 -0
  50. package/dist/config/presets.js +241 -0
  51. package/dist/config/presets.js.map +1 -0
  52. package/dist/config/profiles.d.ts +79 -0
  53. package/dist/config/profiles.js +245 -0
  54. package/dist/config/profiles.js.map +1 -0
  55. package/dist/config/providers.d.ts +120 -0
  56. package/dist/config/providers.js +450 -0
  57. package/dist/config/providers.js.map +1 -0
  58. package/dist/config/sites.d.ts +22 -0
  59. package/dist/config/sites.js +377 -0
  60. package/dist/config/sites.js.map +1 -0
  61. package/dist/config/userChannels.d.ts +178 -0
  62. package/dist/config/userChannels.js +543 -0
  63. package/dist/config/userChannels.js.map +1 -0
  64. package/dist/config/userConfig.d.ts +235 -0
  65. package/dist/config/userConfig.js +913 -0
  66. package/dist/config/userConfig.js.map +1 -0
  67. package/dist/hdhr/channelMap.d.ts +21 -0
  68. package/dist/hdhr/channelMap.js +82 -0
  69. package/dist/hdhr/channelMap.js.map +1 -0
  70. package/dist/hdhr/deviceId.d.ts +11 -0
  71. package/dist/hdhr/deviceId.js +84 -0
  72. package/dist/hdhr/deviceId.js.map +1 -0
  73. package/dist/hdhr/discover.d.ts +6 -0
  74. package/dist/hdhr/discover.js +155 -0
  75. package/dist/hdhr/discover.js.map +1 -0
  76. package/dist/hdhr/index.d.ts +9 -0
  77. package/dist/hdhr/index.js +87 -0
  78. package/dist/hdhr/index.js.map +1 -0
  79. package/dist/index.d.ts +1 -0
  80. package/dist/index.js +144 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/routes/assets.d.ts +6 -0
  83. package/dist/routes/assets.js +79 -0
  84. package/dist/routes/assets.js.map +1 -0
  85. package/dist/routes/auth.d.ts +6 -0
  86. package/dist/routes/auth.js +77 -0
  87. package/dist/routes/auth.js.map +1 -0
  88. package/dist/routes/channels.d.ts +6 -0
  89. package/dist/routes/channels.js +40 -0
  90. package/dist/routes/channels.js.map +1 -0
  91. package/dist/routes/components.d.ts +138 -0
  92. package/dist/routes/components.js +210 -0
  93. package/dist/routes/components.js.map +1 -0
  94. package/dist/routes/config.d.ts +72 -0
  95. package/dist/routes/config.js +1977 -0
  96. package/dist/routes/config.js.map +1 -0
  97. package/dist/routes/debug.d.ts +6 -0
  98. package/dist/routes/debug.js +274 -0
  99. package/dist/routes/debug.js.map +1 -0
  100. package/dist/routes/health.d.ts +6 -0
  101. package/dist/routes/health.js +85 -0
  102. package/dist/routes/health.js.map +1 -0
  103. package/dist/routes/hls.d.ts +6 -0
  104. package/dist/routes/hls.js +25 -0
  105. package/dist/routes/hls.js.map +1 -0
  106. package/dist/routes/index.d.ts +19 -0
  107. package/dist/routes/index.js +49 -0
  108. package/dist/routes/index.js.map +1 -0
  109. package/dist/routes/logs.d.ts +6 -0
  110. package/dist/routes/logs.js +164 -0
  111. package/dist/routes/logs.js.map +1 -0
  112. package/dist/routes/mpegts.d.ts +6 -0
  113. package/dist/routes/mpegts.js +19 -0
  114. package/dist/routes/mpegts.js.map +1 -0
  115. package/dist/routes/play.d.ts +6 -0
  116. package/dist/routes/play.js +18 -0
  117. package/dist/routes/play.js.map +1 -0
  118. package/dist/routes/playlist.d.ts +36 -0
  119. package/dist/routes/playlist.js +134 -0
  120. package/dist/routes/playlist.js.map +1 -0
  121. package/dist/routes/root.d.ts +6 -0
  122. package/dist/routes/root.js +2920 -0
  123. package/dist/routes/root.js.map +1 -0
  124. package/dist/routes/streams.d.ts +6 -0
  125. package/dist/routes/streams.js +88 -0
  126. package/dist/routes/streams.js.map +1 -0
  127. package/dist/routes/theme.d.ts +15 -0
  128. package/dist/routes/theme.js +275 -0
  129. package/dist/routes/theme.js.map +1 -0
  130. package/dist/routes/ui.d.ts +56 -0
  131. package/dist/routes/ui.js +354 -0
  132. package/dist/routes/ui.js.map +1 -0
  133. package/dist/service/commands.d.ts +41 -0
  134. package/dist/service/commands.js +391 -0
  135. package/dist/service/commands.js.map +1 -0
  136. package/dist/service/generators.d.ts +33 -0
  137. package/dist/service/generators.js +432 -0
  138. package/dist/service/generators.js.map +1 -0
  139. package/dist/service/index.d.ts +2 -0
  140. package/dist/service/index.js +7 -0
  141. package/dist/service/index.js.map +1 -0
  142. package/dist/streaming/clients.d.ts +48 -0
  143. package/dist/streaming/clients.js +114 -0
  144. package/dist/streaming/clients.js.map +1 -0
  145. package/dist/streaming/fmp4Segmenter.d.ts +61 -0
  146. package/dist/streaming/fmp4Segmenter.js +461 -0
  147. package/dist/streaming/fmp4Segmenter.js.map +1 -0
  148. package/dist/streaming/hls.d.ts +120 -0
  149. package/dist/streaming/hls.js +722 -0
  150. package/dist/streaming/hls.js.map +1 -0
  151. package/dist/streaming/hlsSegments.d.ts +54 -0
  152. package/dist/streaming/hlsSegments.js +162 -0
  153. package/dist/streaming/hlsSegments.js.map +1 -0
  154. package/dist/streaming/lifecycle.d.ts +33 -0
  155. package/dist/streaming/lifecycle.js +185 -0
  156. package/dist/streaming/lifecycle.js.map +1 -0
  157. package/dist/streaming/monitor.d.ts +74 -0
  158. package/dist/streaming/monitor.js +1310 -0
  159. package/dist/streaming/monitor.js.map +1 -0
  160. package/dist/streaming/mp4Parser.d.ts +74 -0
  161. package/dist/streaming/mp4Parser.js +566 -0
  162. package/dist/streaming/mp4Parser.js.map +1 -0
  163. package/dist/streaming/mpegts.d.ts +14 -0
  164. package/dist/streaming/mpegts.js +248 -0
  165. package/dist/streaming/mpegts.js.map +1 -0
  166. package/dist/streaming/registry.d.ts +119 -0
  167. package/dist/streaming/registry.js +127 -0
  168. package/dist/streaming/registry.js.map +1 -0
  169. package/dist/streaming/setup.d.ts +135 -0
  170. package/dist/streaming/setup.js +670 -0
  171. package/dist/streaming/setup.js.map +1 -0
  172. package/dist/streaming/showInfo.d.ts +30 -0
  173. package/dist/streaming/showInfo.js +362 -0
  174. package/dist/streaming/showInfo.js.map +1 -0
  175. package/dist/streaming/statusEmitter.d.ts +125 -0
  176. package/dist/streaming/statusEmitter.js +139 -0
  177. package/dist/streaming/statusEmitter.js.map +1 -0
  178. package/dist/types/index.d.ts +403 -0
  179. package/dist/types/index.js +6 -0
  180. package/dist/types/index.js.map +1 -0
  181. package/dist/utils/debugFilter.d.ts +38 -0
  182. package/dist/utils/debugFilter.js +157 -0
  183. package/dist/utils/debugFilter.js.map +1 -0
  184. package/dist/utils/delay.d.ts +6 -0
  185. package/dist/utils/delay.js +15 -0
  186. package/dist/utils/delay.js.map +1 -0
  187. package/dist/utils/errors.d.ts +15 -0
  188. package/dist/utils/errors.js +40 -0
  189. package/dist/utils/errors.js.map +1 -0
  190. package/dist/utils/evaluate.d.ts +51 -0
  191. package/dist/utils/evaluate.js +124 -0
  192. package/dist/utils/evaluate.js.map +1 -0
  193. package/dist/utils/ffmpeg.d.ts +65 -0
  194. package/dist/utils/ffmpeg.js +317 -0
  195. package/dist/utils/ffmpeg.js.map +1 -0
  196. package/dist/utils/fileLogger.d.ts +25 -0
  197. package/dist/utils/fileLogger.js +248 -0
  198. package/dist/utils/fileLogger.js.map +1 -0
  199. package/dist/utils/format.d.ts +16 -0
  200. package/dist/utils/format.js +46 -0
  201. package/dist/utils/format.js.map +1 -0
  202. package/dist/utils/html.d.ts +6 -0
  203. package/dist/utils/html.js +24 -0
  204. package/dist/utils/html.js.map +1 -0
  205. package/dist/utils/index.d.ts +15 -0
  206. package/dist/utils/index.js +20 -0
  207. package/dist/utils/index.js.map +1 -0
  208. package/dist/utils/logEmitter.d.ts +17 -0
  209. package/dist/utils/logEmitter.js +30 -0
  210. package/dist/utils/logEmitter.js.map +1 -0
  211. package/dist/utils/logger.d.ts +82 -0
  212. package/dist/utils/logger.js +219 -0
  213. package/dist/utils/logger.js.map +1 -0
  214. package/dist/utils/m3u.d.ts +32 -0
  215. package/dist/utils/m3u.js +148 -0
  216. package/dist/utils/m3u.js.map +1 -0
  217. package/dist/utils/morganStream.d.ts +7 -0
  218. package/dist/utils/morganStream.js +33 -0
  219. package/dist/utils/morganStream.js.map +1 -0
  220. package/dist/utils/platform.d.ts +64 -0
  221. package/dist/utils/platform.js +157 -0
  222. package/dist/utils/platform.js.map +1 -0
  223. package/dist/utils/retry.d.ts +15 -0
  224. package/dist/utils/retry.js +82 -0
  225. package/dist/utils/retry.js.map +1 -0
  226. package/dist/utils/streamContext.d.ts +28 -0
  227. package/dist/utils/streamContext.js +33 -0
  228. package/dist/utils/streamContext.js.map +1 -0
  229. package/dist/utils/version.d.ts +37 -0
  230. package/dist/utils/version.js +228 -0
  231. package/dist/utils/version.js.map +1 -0
  232. package/package.json +92 -0
  233. package/prismcast.png +0 -0
  234. package/prismcast.svg +74 -0
@@ -0,0 +1,450 @@
1
+ import { DOMAIN_CONFIG, getDomainConfig } from "./sites.js";
2
+ import { LOG, extractDomain } from "../utils/index.js";
3
+ import { PREDEFINED_CHANNELS } from "../channels/index.js";
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
+ *
6
+ * Grouping convention: Channels are grouped by key pattern. A key like "espn-disneyplus" is a variant of "espn" because it starts with "espn-" and "espn" exists as a
7
+ * channel. The canonical key (the base key without suffix) is the default provider.
8
+ *
9
+ * IMPORTANT: When adding channels, avoid hyphenated keys that would unintentionally match an existing channel. For example, if "cnn" exists, don't add
10
+ * "cnn-international" as a separate channel — it would become a CNN variant. Use a non-hyphenated key like "cnni" instead.
11
+ *
12
+ * Inheritance: Provider variants inherit `name` and `stationId` from the canonical entry (variant's own value takes precedence). `channelSelector` is NOT inherited
13
+ * — it is provider-specific (e.g., fox.com uses station codes like "FOXD2C" while Sling uses guide names like "FOX"), so each variant must define its own.
14
+ *
15
+ * User overrides: When a user defines a channel with the same key as a predefined channel, both versions appear in the provider dropdown. The user's custom version
16
+ * is shown first (labeled "Custom") and is the default. The original predefined version uses a special key suffix (PREDEFINED_SUFFIX) to distinguish it from the
17
+ * user's version. This allows users to switch between their custom definition and the original at any time.
18
+ *
19
+ * User selections are stored in ~/.prismcast/channels.json under the `providerSelections` key and persist across restarts.
20
+ */
21
+ // Suffix appended to channel keys to reference the original predefined channel when a user has overridden it. For example, "espn:predefined" references the original
22
+ // predefined ESPN channel when the user has created a custom "espn" entry.
23
+ const PREDEFINED_SUFFIX = ":predefined";
24
+ // Module-level storage for provider groups, keyed by canonical channel key.
25
+ const providerGroups = new Map();
26
+ // Reference to the channels map for inheritance resolution.
27
+ let channelsRef = {};
28
+ // User's provider selections, keyed by canonical channel key. Values are the selected provider key (e.g., "espn-disneyplus").
29
+ let providerSelections = new Map();
30
+ // Provider Tag System.
31
+ // Module-level state for the provider filter. Empty array means "no filter" (all providers shown). Non-empty means only these tags are active.
32
+ let enabledProviders = [];
33
+ /**
34
+ * 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,
35
+ * looks up the URL domain via getDomainConfig() and reads the providerTag field, falling back to "direct" if not found.
36
+ * @param key - The channel key.
37
+ * @returns The provider tag string.
38
+ */
39
+ export function getProviderTagForChannel(key) {
40
+ const group = providerGroups.get(key);
41
+ // For variant keys, the suffix after the canonical key (minus the hyphen) IS the tag.
42
+ if (group && (group.canonicalKey !== key)) {
43
+ const suffix = key.slice(group.canonicalKey.length + 1);
44
+ return suffix;
45
+ }
46
+ // For canonical keys, derive from the URL domain via DOMAIN_CONFIG.
47
+ const channel = channelsRef[key] ?? PREDEFINED_CHANNELS[key];
48
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
49
+ if (!channel) {
50
+ return "direct";
51
+ }
52
+ const config = getDomainConfig(channel.url);
53
+ return config?.providerTag ?? "direct";
54
+ }
55
+ /**
56
+ * Returns all provider tags for a channel (canonical tag + all variant suffix tags). Used to determine which providers offer this channel.
57
+ * @param canonicalKey - The canonical channel key.
58
+ * @returns Array of provider tag strings.
59
+ */
60
+ export function getChannelProviderTags(canonicalKey) {
61
+ const tags = new Set();
62
+ // Add the canonical entry's tag.
63
+ tags.add(getProviderTagForChannel(canonicalKey));
64
+ // Add tags for all variants.
65
+ const group = providerGroups.get(canonicalKey);
66
+ if (group) {
67
+ for (const variant of group.variants) {
68
+ // Skip predefined suffix variants — they share the canonical's tag.
69
+ if (variant.key.endsWith(PREDEFINED_SUFFIX)) {
70
+ continue;
71
+ }
72
+ tags.add(getProviderTagForChannel(variant.key));
73
+ }
74
+ }
75
+ return [...tags];
76
+ }
77
+ /**
78
+ * 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
79
+ * have a providerTag, with any trailing parenthetical stripped (e.g., "Hulu (Live Guide)" becomes "Hulu").
80
+ * @returns Array of { displayName, tag } objects sorted alphabetically by display name, with "direct" always first.
81
+ */
82
+ export function getAllProviderTags() {
83
+ const tags = new Set();
84
+ // Scan all channels (not just grouped ones) to find all provider tags.
85
+ const allKeys = new Set([...Object.keys(channelsRef), ...Object.keys(PREDEFINED_CHANNELS)]);
86
+ for (const key of allKeys) {
87
+ // Skip variant keys — they are covered by getChannelProviderTags() on the canonical.
88
+ const group = providerGroups.get(key);
89
+ if (group && (group.canonicalKey !== key)) {
90
+ continue;
91
+ }
92
+ const channelTags = getChannelProviderTags(key);
93
+ for (const tag of channelTags) {
94
+ tags.add(tag);
95
+ }
96
+ }
97
+ // 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
98
+ // for each tag.
99
+ const tagDisplayNames = new Map();
100
+ tagDisplayNames.set("direct", "Direct");
101
+ for (const config of Object.values(DOMAIN_CONFIG)) {
102
+ if (config.providerTag && config.provider && !tagDisplayNames.has(config.providerTag)) {
103
+ tagDisplayNames.set(config.providerTag, config.provider.replace(/\s*\(.*\)$/, ""));
104
+ }
105
+ }
106
+ // Build result with display names.
107
+ const result = [];
108
+ for (const tag of tags) {
109
+ result.push({ displayName: tagDisplayNames.get(tag) ?? tag, tag });
110
+ }
111
+ // Sort alphabetically by display name, but keep "direct" first.
112
+ result.sort((a, b) => {
113
+ if (a.tag === "direct") {
114
+ return -1;
115
+ }
116
+ if (b.tag === "direct") {
117
+ return 1;
118
+ }
119
+ return a.displayName.localeCompare(b.displayName);
120
+ });
121
+ return result;
122
+ }
123
+ /**
124
+ * Gets the current enabled provider tags.
125
+ * @returns Copy of the enabled providers array. Empty means no filter (all shown).
126
+ */
127
+ export function getEnabledProviders() {
128
+ return [...enabledProviders];
129
+ }
130
+ /**
131
+ * Sets the enabled provider tags. Empty array means "no filter" (all providers shown).
132
+ * @param tags - The provider tags to enable.
133
+ */
134
+ export function setEnabledProviders(tags) {
135
+ enabledProviders = [...tags];
136
+ }
137
+ /**
138
+ * 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".
139
+ * @param tag - The provider tag to check.
140
+ * @returns True if the provider is available.
141
+ */
142
+ export function isProviderTagEnabled(tag) {
143
+ // No filter active — all providers are enabled.
144
+ if (enabledProviders.length === 0) {
145
+ return true;
146
+ }
147
+ // "direct" is always enabled.
148
+ if (tag === "direct") {
149
+ return true;
150
+ }
151
+ return enabledProviders.includes(tag);
152
+ }
153
+ /**
154
+ * Centralized availability check for the provider filter. Returns true if the channel has at least one variant whose provider tag is enabled.
155
+ * @param canonicalKey - The canonical channel key.
156
+ * @returns True if the channel passes the provider filter.
157
+ */
158
+ export function isChannelAvailableByProvider(canonicalKey) {
159
+ // No filter active — all channels are available.
160
+ if (enabledProviders.length === 0) {
161
+ return true;
162
+ }
163
+ const tags = getChannelProviderTags(canonicalKey);
164
+ return tags.some((tag) => isProviderTagEnabled(tag));
165
+ }
166
+ /**
167
+ * Checks if a channel in the merged map is a user override of a predefined channel. This uses object reference comparison — getAllChannels() spreads
168
+ * PREDEFINED_CHANNELS directly into the result, so if the reference differs, a user channel has replaced the predefined one.
169
+ * @param key - The channel key to check.
170
+ * @param channels - The merged channel map.
171
+ * @returns True if the channel is a user override of a predefined channel.
172
+ */
173
+ function isUserOverride(key, channels) {
174
+ const predefined = PREDEFINED_CHANNELS[key];
175
+ // A channel is an override if: (1) a predefined version exists, and (2) the merged map has a different object reference.
176
+ return Boolean(predefined) && (channels[key] !== predefined);
177
+ }
178
+ /**
179
+ * 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
180
+ * "espn-". Should be called at startup after channels are loaded.
181
+ * @param channels - The merged channel map (predefined + user channels).
182
+ */
183
+ export function buildProviderGroups(channels) {
184
+ channelsRef = channels;
185
+ providerGroups.clear();
186
+ // Build a set of all channel keys for quick lookup.
187
+ const allKeys = new Set(Object.keys(channels));
188
+ // Group variant keys by their canonical key (prefix before first hyphen).
189
+ const variantsByCanonical = new Map();
190
+ for (const key of allKeys) {
191
+ const hyphenIndex = key.indexOf("-");
192
+ // Keys without hyphens are potential canonicals, not variants.
193
+ if (hyphenIndex === -1) {
194
+ continue;
195
+ }
196
+ const potentialCanonical = key.slice(0, hyphenIndex);
197
+ // Only group if the canonical key exists as a channel.
198
+ if (!allKeys.has(potentialCanonical)) {
199
+ continue;
200
+ }
201
+ // This key is a variant of potentialCanonical.
202
+ const existing = variantsByCanonical.get(potentialCanonical);
203
+ if (existing) {
204
+ existing.push(key);
205
+ }
206
+ else {
207
+ variantsByCanonical.set(potentialCanonical, [key]);
208
+ }
209
+ }
210
+ // Build provider groups from the grouped keys.
211
+ for (const [canonicalKey, variantKeys] of variantsByCanonical) {
212
+ const canonical = channels[canonicalKey];
213
+ const variants = [];
214
+ if (isUserOverride(canonicalKey, channels)) {
215
+ // User has overridden the canonical channel. Show their custom version first with "Custom" label, then the original predefined version.
216
+ const predefined = PREDEFINED_CHANNELS[canonicalKey];
217
+ variants.push({ key: canonicalKey, label: "Custom (" + extractDomain(canonical.url) + ")" });
218
+ variants.push({ key: canonicalKey + PREDEFINED_SUFFIX, label: predefined.provider ?? getProviderDisplayName(predefined.url) });
219
+ }
220
+ else {
221
+ // Normal case: canonical is the predefined version (or a new user-defined channel with no predefined equivalent).
222
+ variants.push({ key: canonicalKey, label: canonical.provider ?? getProviderDisplayName(canonical.url) });
223
+ }
224
+ variantKeys.sort();
225
+ for (const variantKey of variantKeys) {
226
+ const variant = channels[variantKey];
227
+ variants.push({ key: variantKey, label: variant.provider ?? getProviderDisplayName(variant.url) });
228
+ }
229
+ const group = { canonicalKey, variants };
230
+ // Map canonical and all variants to this group for easy lookup.
231
+ providerGroups.set(canonicalKey, group);
232
+ for (const variantKey of variantKeys) {
233
+ providerGroups.set(variantKey, group);
234
+ }
235
+ LOG.debug("config", "Provider group '%s': variants=%s.", canonicalKey, variants.map((v) => v.key).join(", "));
236
+ }
237
+ // 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
238
+ // switch between their custom definition and the original predefined version.
239
+ for (const key of allKeys) {
240
+ // Skip if already in a group (handled in first pass).
241
+ if (providerGroups.has(key)) {
242
+ continue;
243
+ }
244
+ // Skip variant keys (keys with hyphens where the prefix exists as a channel).
245
+ const hyphenIndex = key.indexOf("-");
246
+ if ((hyphenIndex !== -1) && allKeys.has(key.slice(0, hyphenIndex))) {
247
+ continue;
248
+ }
249
+ // Check if this is a user override of a predefined channel.
250
+ if (!isUserOverride(key, channels)) {
251
+ continue;
252
+ }
253
+ // This is a user override without variants. Create a group with custom and predefined options.
254
+ const userChannel = channels[key];
255
+ const predefined = PREDEFINED_CHANNELS[key];
256
+ const variants = [
257
+ { key, label: "Custom (" + extractDomain(userChannel.url) + ")" },
258
+ { key: key + PREDEFINED_SUFFIX, label: predefined.provider ?? getProviderDisplayName(predefined.url) }
259
+ ];
260
+ const group = { canonicalKey: key, variants };
261
+ providerGroups.set(key, group);
262
+ LOG.debug("config", "Provider group '%s' (override): variants=%s.", key, variants.map((v) => v.key).join(", "));
263
+ }
264
+ }
265
+ /**
266
+ * Resolves a URL to a friendly provider display name. Checks DOMAIN_CONFIG via getDomainConfig() for a provider name, trying the full hostname first for
267
+ * subdomain-specific overrides before falling back to the concise domain. Returns the raw domain string if no provider name is configured.
268
+ * @param url - The URL to resolve a provider display name for.
269
+ * @returns The provider display name, or the concise domain if no provider name is configured.
270
+ */
271
+ export function getProviderDisplayName(url) {
272
+ const config = getDomainConfig(url);
273
+ return config?.provider ?? extractDomain(url);
274
+ }
275
+ /**
276
+ * Gets the provider group for a channel key. Works with both canonical and variant keys.
277
+ * @param key - Any channel key in the group.
278
+ * @returns The provider group if the channel is part of a multi-provider group, undefined otherwise.
279
+ */
280
+ export function getProviderGroup(key) {
281
+ return providerGroups.get(key);
282
+ }
283
+ /**
284
+ * Checks if a channel key is a non-canonical provider variant. Used to filter variants from channel listings.
285
+ * @param key - The channel key to check.
286
+ * @returns True if the key is a variant (not canonical) in a provider group.
287
+ */
288
+ export function isProviderVariant(key) {
289
+ const group = providerGroups.get(key);
290
+ return (group !== undefined) && (group.canonicalKey !== key);
291
+ }
292
+ /**
293
+ * Checks if a channel has multiple provider options. Used to determine whether to show a provider dropdown in the UI.
294
+ * @param key - The channel key to check.
295
+ * @returns True if the channel has more than one provider variant.
296
+ */
297
+ export function hasMultipleProviders(key) {
298
+ const group = providerGroups.get(key);
299
+ return (group !== undefined) && (group.variants.length > 1);
300
+ }
301
+ /**
302
+ * 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.
303
+ * Handles the PREDEFINED_SUFFIX used when a user has overridden a predefined channel.
304
+ * @param key - Any channel key.
305
+ * @returns The canonical key for the channel's provider group, or the input key if not part of a group.
306
+ */
307
+ export function getCanonicalKey(key) {
308
+ // Strip predefined suffix if present before looking up the group.
309
+ const baseKey = key.endsWith(PREDEFINED_SUFFIX) ? key.slice(0, -PREDEFINED_SUFFIX.length) : key;
310
+ const group = providerGroups.get(baseKey);
311
+ return group?.canonicalKey ?? baseKey;
312
+ }
313
+ /**
314
+ * Sets the user's provider selections. Called when loading from channels.json.
315
+ * @param selections - Provider selections keyed by canonical channel key.
316
+ */
317
+ export function setProviderSelections(selections) {
318
+ providerSelections = new Map(Object.entries(selections));
319
+ }
320
+ /**
321
+ * Gets all provider selections.
322
+ * @returns Copy of the provider selections object.
323
+ */
324
+ export function getProviderSelections() {
325
+ return Object.fromEntries(providerSelections);
326
+ }
327
+ /**
328
+ * Gets the provider selection for a specific channel.
329
+ * @param canonicalKey - The canonical channel key.
330
+ * @returns The selected provider key, or undefined if using the default.
331
+ */
332
+ export function getProviderSelection(canonicalKey) {
333
+ return providerSelections.get(canonicalKey);
334
+ }
335
+ /**
336
+ * Sets the provider selection for a channel.
337
+ * @param canonicalKey - The canonical channel key.
338
+ * @param providerKey - The selected provider key.
339
+ */
340
+ export function setProviderSelection(canonicalKey, providerKey) {
341
+ // If selecting the canonical (default), remove the selection instead of storing it.
342
+ if (providerKey === canonicalKey) {
343
+ providerSelections.delete(canonicalKey);
344
+ }
345
+ else {
346
+ providerSelections.set(canonicalKey, providerKey);
347
+ }
348
+ }
349
+ /**
350
+ * 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
351
+ * 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
352
+ * selection's provider is filtered out.
353
+ * @param canonicalKey - The canonical channel key.
354
+ * @returns The resolved provider key to use for streaming.
355
+ */
356
+ export function resolveProviderKey(canonicalKey) {
357
+ const selection = providerSelections.get(canonicalKey);
358
+ // No selection stored — use the canonical key (default provider).
359
+ if (!selection) {
360
+ // If the canonical's provider tag is filtered out, find the first enabled variant.
361
+ if ((enabledProviders.length > 0) && !isProviderTagEnabled(getProviderTagForChannel(canonicalKey))) {
362
+ return findFirstEnabledVariant(canonicalKey) ?? canonicalKey;
363
+ }
364
+ return canonicalKey;
365
+ }
366
+ // Handle :predefined suffix — validate that the base key exists in PREDEFINED_CHANNELS.
367
+ if (selection.endsWith(PREDEFINED_SUFFIX)) {
368
+ const baseKey = selection.slice(0, -PREDEFINED_SUFFIX.length);
369
+ // Runtime check needed — TypeScript thinks Record indexing always returns a value, but the key may not exist.
370
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
371
+ if (PREDEFINED_CHANNELS[baseKey]) {
372
+ return selection;
373
+ }
374
+ // Predefined channel was removed. Fall through to the invalid selection warning.
375
+ // Runtime check needed — TypeScript thinks Record indexing always returns a value, but the key may not exist.
376
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
377
+ }
378
+ else if (channelsRef[selection]) {
379
+ // Normal selection — validate it exists in the merged channels. If its provider tag is filtered out, find the first enabled variant instead.
380
+ if ((enabledProviders.length > 0) && !isProviderTagEnabled(getProviderTagForChannel(selection))) {
381
+ return findFirstEnabledVariant(canonicalKey) ?? selection;
382
+ }
383
+ return selection;
384
+ }
385
+ // Selection is invalid (provider removed). Clear it and log a warning.
386
+ LOG.warn("Provider selection '%s' for channel '%s' no longer exists. Using default.", selection, canonicalKey);
387
+ providerSelections.delete(canonicalKey);
388
+ return canonicalKey;
389
+ }
390
+ /**
391
+ * 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
392
+ * provider tag is enabled.
393
+ * @param canonicalKey - The canonical channel key.
394
+ * @returns The first enabled variant key, or undefined if none are enabled.
395
+ */
396
+ function findFirstEnabledVariant(canonicalKey) {
397
+ const group = providerGroups.get(canonicalKey);
398
+ if (!group) {
399
+ return undefined;
400
+ }
401
+ for (const variant of group.variants) {
402
+ if (variant.key.endsWith(PREDEFINED_SUFFIX)) {
403
+ continue;
404
+ }
405
+ if (isProviderTagEnabled(getProviderTagForChannel(variant.key))) {
406
+ return variant.key;
407
+ }
408
+ }
409
+ return undefined;
410
+ }
411
+ /**
412
+ * Gets a channel with inheritance applied. For provider variants, this merges the variant's properties with inherited properties from the canonical entry.
413
+ * Inherited properties: `name`, `stationId` (variant takes precedence). `channelSelector` is not inherited — it is provider-specific.
414
+ * @param key - The channel key (canonical or variant).
415
+ * @returns The complete channel with inheritance applied, or undefined if the channel doesn't exist.
416
+ */
417
+ export function getResolvedChannel(key) {
418
+ // Handle predefined suffix — return the original predefined channel when user has overridden the canonical but selects the predefined provider.
419
+ if (key.endsWith(PREDEFINED_SUFFIX)) {
420
+ const baseKey = key.slice(0, -PREDEFINED_SUFFIX.length);
421
+ return PREDEFINED_CHANNELS[baseKey];
422
+ }
423
+ const channel = channelsRef[key];
424
+ // Runtime check needed even though TypeScript thinks channel is always defined (Record indexing quirk).
425
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
426
+ if (!channel) {
427
+ return undefined;
428
+ }
429
+ const group = providerGroups.get(key);
430
+ // If not part of a group or is the canonical entry, return as-is.
431
+ if (!group || (group.canonicalKey === key)) {
432
+ return channel;
433
+ }
434
+ // This is a variant — merge with canonical entry.
435
+ const canonical = channelsRef[group.canonicalKey];
436
+ // Runtime check — canonical entry should exist if the group exists, but we check defensively.
437
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
438
+ if (!canonical) {
439
+ // Canonical entry missing (shouldn't happen), return variant as-is.
440
+ return channel;
441
+ }
442
+ // Build the merged channel. Variant properties override canonical, but inherit name and stationId if not set. channelSelector is NOT inherited — it is
443
+ // provider-specific (e.g., fox.com uses station codes like "FOXD2C" while Sling uses guide names like "FOX"), so each variant must define its own.
444
+ return {
445
+ ...channel,
446
+ name: channel.name ?? canonical.name,
447
+ stationId: channel.stationId ?? canonical.stationId
448
+ };
449
+ }
450
+ //# sourceMappingURL=providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/config/providers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { ResolvedSiteProfile, SiteProfile } from "../types/index.js";
2
+ export declare const SITE_PROFILES: Record<string, SiteProfile>;
3
+ /**
4
+ * Domain-level configuration associating domain patterns with site profiles and provider display names. Each entry can specify a site profile for behavior
5
+ * configuration and/or a provider display name for friendly UI labels.
6
+ */
7
+ export interface DomainConfig {
8
+ loginUrl?: string;
9
+ maxContinuousPlayback?: number;
10
+ profile?: string;
11
+ providerTag?: string;
12
+ provider?: string;
13
+ }
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;
22
+ export declare const DEFAULT_SITE_PROFILE: ResolvedSiteProfile;