prismcast 1.9.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. package/dist/app.d.ts +1 -1
  2. package/dist/app.js +27 -9
  3. package/dist/app.js.map +1 -1
  4. package/dist/browser/cdp.js +7 -7
  5. package/dist/browser/cdp.js.map +1 -1
  6. package/dist/browser/channelSelection.d.ts +41 -11
  7. package/dist/browser/channelSelection.js +75 -24
  8. package/dist/browser/channelSelection.js.map +1 -1
  9. package/dist/browser/display.d.ts +1 -1
  10. package/dist/browser/index.d.ts +8 -8
  11. package/dist/browser/index.js +42 -43
  12. package/dist/browser/index.js.map +1 -1
  13. package/dist/browser/login.d.ts +2 -2
  14. package/dist/browser/login.js +1 -1
  15. package/dist/browser/manifestInterceptor.d.ts +77 -0
  16. package/dist/browser/manifestInterceptor.js +323 -0
  17. package/dist/browser/manifestInterceptor.js.map +1 -0
  18. package/dist/browser/precaching.js +4 -4
  19. package/dist/browser/tuning/comcastPolymer.d.ts +1 -1
  20. package/dist/browser/tuning/cox.d.ts +1 -1
  21. package/dist/browser/tuning/directv.d.ts +1 -1
  22. package/dist/browser/tuning/directv.js +61 -62
  23. package/dist/browser/tuning/directv.js.map +1 -1
  24. package/dist/browser/tuning/fox.d.ts +1 -1
  25. package/dist/browser/tuning/fox.js +171 -14
  26. package/dist/browser/tuning/fox.js.map +1 -1
  27. package/dist/browser/tuning/hbo.d.ts +1 -1
  28. package/dist/browser/tuning/hbo.js +6 -6
  29. package/dist/browser/tuning/hbo.js.map +1 -1
  30. package/dist/browser/tuning/hulu.d.ts +1 -1
  31. package/dist/browser/tuning/hulu.js +117 -110
  32. package/dist/browser/tuning/hulu.js.map +1 -1
  33. package/dist/browser/tuning/shared.d.ts +3 -3
  34. package/dist/browser/tuning/shared.js +5 -5
  35. package/dist/browser/tuning/sling.d.ts +1 -1
  36. package/dist/browser/tuning/sling.js +28 -28
  37. package/dist/browser/tuning/sling.js.map +1 -1
  38. package/dist/browser/tuning/spectrum.d.ts +1 -1
  39. package/dist/browser/tuning/spectrum.js +21 -22
  40. package/dist/browser/tuning/spectrum.js.map +1 -1
  41. package/dist/browser/tuning/thumbnailRow.d.ts +1 -1
  42. package/dist/browser/tuning/thumbnailRow.js +1 -1
  43. package/dist/browser/tuning/tileClick.d.ts +1 -1
  44. package/dist/browser/tuning/tileClick.js +5 -5
  45. package/dist/browser/tuning/xfinity.d.ts +1 -1
  46. package/dist/browser/tuning/youtubeTv.d.ts +1 -1
  47. package/dist/browser/tuning/youtubeTv.js +17 -18
  48. package/dist/browser/tuning/youtubeTv.js.map +1 -1
  49. package/dist/browser/video.d.ts +20 -6
  50. package/dist/browser/video.js +30 -38
  51. package/dist/browser/video.js.map +1 -1
  52. package/dist/channels/index.d.ts +1 -2
  53. package/dist/channels/index.js +73 -40
  54. package/dist/channels/index.js.map +1 -1
  55. package/dist/config/channelForm.d.ts +58 -0
  56. package/dist/config/channelForm.js +129 -0
  57. package/dist/config/channelForm.js.map +1 -0
  58. package/dist/config/consistencyProbe.d.ts +7 -0
  59. package/dist/config/consistencyProbe.js +143 -0
  60. package/dist/config/consistencyProbe.js.map +1 -0
  61. package/dist/config/health.d.ts +4 -3
  62. package/dist/config/health.js +75 -62
  63. package/dist/config/health.js.map +1 -1
  64. package/dist/config/index.d.ts +1 -1
  65. package/dist/config/index.js +19 -12
  66. package/dist/config/index.js.map +1 -1
  67. package/dist/config/paths.d.ts +9 -3
  68. package/dist/config/paths.js +12 -4
  69. package/dist/config/paths.js.map +1 -1
  70. package/dist/config/persistence.context.d.ts +8 -0
  71. package/dist/config/persistence.context.js +30 -0
  72. package/dist/config/persistence.context.js.map +1 -0
  73. package/dist/config/persistence.d.ts +110 -12
  74. package/dist/config/persistence.js +351 -32
  75. package/dist/config/persistence.js.map +1 -1
  76. package/dist/config/presets.d.ts +14 -4
  77. package/dist/config/presets.js +84 -75
  78. package/dist/config/presets.js.map +1 -1
  79. package/dist/config/profiles.d.ts +2 -2
  80. package/dist/config/profiles.js +7 -9
  81. package/dist/config/profiles.js.map +1 -1
  82. package/dist/config/servicePacks.d.ts +2 -2
  83. package/dist/config/servicePacks.js +28 -28
  84. package/dist/config/servicePacks.js.map +1 -1
  85. package/dist/config/services.d.ts +62 -36
  86. package/dist/config/services.js +150 -136
  87. package/dist/config/services.js.map +1 -1
  88. package/dist/config/sites.d.ts +3 -3
  89. package/dist/config/sites.js +16 -16
  90. package/dist/config/sites.js.map +1 -1
  91. package/dist/config/userChannels.d.ts +500 -41
  92. package/dist/config/userChannels.js +1201 -312
  93. package/dist/config/userChannels.js.map +1 -1
  94. package/dist/config/userConfig.d.ts +103 -10
  95. package/dist/config/userConfig.js +277 -117
  96. package/dist/config/userConfig.js.map +1 -1
  97. package/dist/config/userProfiles.d.ts +4 -2
  98. package/dist/config/userProfiles.js +72 -26
  99. package/dist/config/userProfiles.js.map +1 -1
  100. package/dist/hdhr/channelMap.js +8 -11
  101. package/dist/hdhr/channelMap.js.map +1 -1
  102. package/dist/hdhr/deviceId.js +10 -9
  103. package/dist/hdhr/deviceId.js.map +1 -1
  104. package/dist/hdhr/discover.js +4 -5
  105. package/dist/hdhr/discover.js.map +1 -1
  106. package/dist/hdhr/index.js +6 -10
  107. package/dist/hdhr/index.js.map +1 -1
  108. package/dist/index.js +12 -12
  109. package/dist/index.js.map +1 -1
  110. package/dist/native/codecInference.d.ts +44 -0
  111. package/dist/native/codecInference.js +327 -0
  112. package/dist/native/codecInference.js.map +1 -0
  113. package/dist/native/decrypt.d.ts +1 -1
  114. package/dist/native/index.d.ts +5 -5
  115. package/dist/native/index.js +42 -64
  116. package/dist/native/index.js.map +1 -1
  117. package/dist/native/probe.d.ts +27 -9
  118. package/dist/native/probe.js +158 -67
  119. package/dist/native/probe.js.map +1 -1
  120. package/dist/native/proxy.d.ts +4 -2
  121. package/dist/native/proxy.js +52 -49
  122. package/dist/native/proxy.js.map +1 -1
  123. package/dist/native/tokenExpiry.d.ts +22 -0
  124. package/dist/native/tokenExpiry.js +153 -0
  125. package/dist/native/tokenExpiry.js.map +1 -0
  126. package/dist/routes/auth.js +6 -10
  127. package/dist/routes/auth.js.map +1 -1
  128. package/dist/routes/components.js +2 -2
  129. package/dist/routes/components.js.map +1 -1
  130. package/dist/routes/config/channels/endpoints/browse.d.ts +6 -0
  131. package/dist/routes/config/channels/endpoints/browse.js +195 -0
  132. package/dist/routes/config/channels/endpoints/browse.js.map +1 -0
  133. package/dist/routes/config/channels/endpoints/bulk.d.ts +6 -0
  134. package/dist/routes/config/channels/endpoints/bulk.js +128 -0
  135. package/dist/routes/config/channels/endpoints/bulk.js.map +1 -0
  136. package/dist/routes/config/channels/endpoints/crud.d.ts +6 -0
  137. package/dist/routes/config/channels/endpoints/crud.js +504 -0
  138. package/dist/routes/config/channels/endpoints/crud.js.map +1 -0
  139. package/dist/routes/config/channels/endpoints/importExport.d.ts +6 -0
  140. package/dist/routes/config/channels/endpoints/importExport.js +131 -0
  141. package/dist/routes/config/channels/endpoints/importExport.js.map +1 -0
  142. package/dist/routes/config/channels/endpoints/predefined.d.ts +6 -0
  143. package/dist/routes/config/channels/endpoints/predefined.js +78 -0
  144. package/dist/routes/config/channels/endpoints/predefined.js.map +1 -0
  145. package/dist/routes/config/channels/endpoints/prefs.d.ts +6 -0
  146. package/dist/routes/config/channels/endpoints/prefs.js +58 -0
  147. package/dist/routes/config/channels/endpoints/prefs.js.map +1 -0
  148. package/dist/routes/config/channels/endpoints/service.d.ts +6 -0
  149. package/dist/routes/config/channels/endpoints/service.js +149 -0
  150. package/dist/routes/config/channels/endpoints/service.js.map +1 -0
  151. package/dist/routes/config/channels/endpoints/tags.d.ts +6 -0
  152. package/dist/routes/config/channels/endpoints/tags.js +185 -0
  153. package/dist/routes/config/channels/endpoints/tags.js.map +1 -0
  154. package/dist/routes/config/channels/http/handler.d.ts +10 -0
  155. package/dist/routes/config/channels/http/handler.js +20 -0
  156. package/dist/routes/config/channels/http/handler.js.map +1 -0
  157. package/dist/routes/config/channels/http/playlistHint.d.ts +25 -0
  158. package/dist/routes/config/channels/http/playlistHint.js +40 -0
  159. package/dist/routes/config/channels/http/playlistHint.js.map +1 -0
  160. package/dist/routes/config/channels/http/serviceWarning.d.ts +10 -0
  161. package/dist/routes/config/channels/http/serviceWarning.js +28 -0
  162. package/dist/routes/config/channels/http/serviceWarning.js.map +1 -0
  163. package/dist/routes/config/channels/index.d.ts +3 -3
  164. package/dist/routes/config/channels/index.js +1 -1
  165. package/dist/routes/config/channels/index.js.map +1 -1
  166. package/dist/routes/config/channels/{routes.d.ts → setup.d.ts} +1 -1
  167. package/dist/routes/config/channels/setup.js +23 -0
  168. package/dist/routes/config/channels/setup.js.map +1 -0
  169. package/dist/routes/config/channels/table.d.ts +9 -9
  170. package/dist/routes/config/channels/table.js +124 -76
  171. package/dist/routes/config/channels/table.js.map +1 -1
  172. package/dist/routes/config/http/envelope.d.ts +111 -0
  173. package/dist/routes/config/http/envelope.js +103 -0
  174. package/dist/routes/config/http/envelope.js.map +1 -0
  175. package/dist/routes/config/index.d.ts +9 -9
  176. package/dist/routes/config/index.js +2 -2
  177. package/dist/routes/config/index.js.map +1 -1
  178. package/dist/routes/config/services.js +69 -68
  179. package/dist/routes/config/services.js.map +1 -1
  180. package/dist/routes/config/settings.d.ts +1 -1
  181. package/dist/routes/config/settings.js +45 -38
  182. package/dist/routes/config/settings.js.map +1 -1
  183. package/dist/routes/debug.js +12 -11
  184. package/dist/routes/debug.js.map +1 -1
  185. package/dist/routes/icons.js +2 -2
  186. package/dist/routes/icons.js.map +1 -1
  187. package/dist/routes/logs.js +19 -30
  188. package/dist/routes/logs.js.map +1 -1
  189. package/dist/routes/mpegts.js +1 -1
  190. package/dist/routes/playlist.d.ts +1 -1
  191. package/dist/routes/playlist.js +37 -26
  192. package/dist/routes/playlist.js.map +1 -1
  193. package/dist/routes/root/content.js +27 -6
  194. package/dist/routes/root/content.js.map +1 -1
  195. package/dist/routes/root/index.js +2 -5
  196. package/dist/routes/root/index.js.map +1 -1
  197. package/dist/routes/root/scripts/channels.js +16 -16
  198. package/dist/routes/root/scripts/channels.js.map +1 -1
  199. package/dist/routes/root/scripts/config.js +59 -59
  200. package/dist/routes/root/scripts/config.js.map +1 -1
  201. package/dist/routes/root/scripts/index.d.ts +4 -4
  202. package/dist/routes/root/scripts/shared.js +24 -10
  203. package/dist/routes/root/scripts/shared.js.map +1 -1
  204. package/dist/routes/root/scripts/status.d.ts +4 -0
  205. package/dist/routes/root/scripts/status.handlers.d.ts +182 -0
  206. package/dist/routes/root/scripts/status.handlers.js +713 -0
  207. package/dist/routes/root/scripts/status.handlers.js.map +1 -0
  208. package/dist/routes/root/scripts/status.js +86 -488
  209. package/dist/routes/root/scripts/status.js.map +1 -1
  210. package/dist/routes/root/styles.js +5 -5
  211. package/dist/routes/services.js +18 -15
  212. package/dist/routes/services.js.map +1 -1
  213. package/dist/routes/sse.d.ts +16 -0
  214. package/dist/routes/sse.js +29 -0
  215. package/dist/routes/sse.js.map +1 -0
  216. package/dist/routes/streams.js +10 -23
  217. package/dist/routes/streams.js.map +1 -1
  218. package/dist/routes/ui.d.ts +2 -2
  219. package/dist/routes/upgrade.js +6 -7
  220. package/dist/routes/upgrade.js.map +1 -1
  221. package/dist/service/commands.context.d.ts +6 -0
  222. package/dist/service/commands.context.js +47 -0
  223. package/dist/service/commands.context.js.map +1 -0
  224. package/dist/service/commands.d.ts +53 -8
  225. package/dist/service/commands.js +171 -188
  226. package/dist/service/commands.js.map +1 -1
  227. package/dist/service/generators.context.d.ts +6 -0
  228. package/dist/service/generators.context.js +45 -0
  229. package/dist/service/generators.context.js.map +1 -0
  230. package/dist/service/generators.d.ts +56 -16
  231. package/dist/service/generators.js +499 -383
  232. package/dist/service/generators.js.map +1 -1
  233. package/dist/service/index.d.ts +2 -2
  234. package/dist/streaming/clients.d.ts +2 -2
  235. package/dist/streaming/clients.js +2 -2
  236. package/dist/streaming/codec.d.ts +2 -2
  237. package/dist/streaming/codec.js +0 -1
  238. package/dist/streaming/codec.js.map +1 -1
  239. package/dist/streaming/fmp4Segmenter.d.ts +2 -2
  240. package/dist/streaming/fmp4Segmenter.js +12 -12
  241. package/dist/streaming/hls.d.ts +3 -3
  242. package/dist/streaming/hls.js +81 -70
  243. package/dist/streaming/hls.js.map +1 -1
  244. package/dist/streaming/hlsResume.d.ts +3 -3
  245. package/dist/streaming/hlsResume.js +5 -5
  246. package/dist/streaming/hlsSegments.d.ts +5 -2
  247. package/dist/streaming/hlsSegments.js +14 -9
  248. package/dist/streaming/hlsSegments.js.map +1 -1
  249. package/dist/streaming/monitor.d.ts +12 -12
  250. package/dist/streaming/monitor.js +80 -54
  251. package/dist/streaming/monitor.js.map +1 -1
  252. package/dist/streaming/mp4Parser.d.ts +34 -4
  253. package/dist/streaming/mp4Parser.js +111 -29
  254. package/dist/streaming/mp4Parser.js.map +1 -1
  255. package/dist/streaming/mpegts.d.ts +1 -1
  256. package/dist/streaming/mpegts.js +13 -10
  257. package/dist/streaming/mpegts.js.map +1 -1
  258. package/dist/streaming/playlistBuilder.d.ts +1 -1
  259. package/dist/streaming/playlistBuilder.js +2 -2
  260. package/dist/streaming/preroll.d.ts +9 -9
  261. package/dist/streaming/preroll.js +39 -41
  262. package/dist/streaming/preroll.js.map +1 -1
  263. package/dist/streaming/pretune.js +4 -4
  264. package/dist/streaming/pretune.js.map +1 -1
  265. package/dist/streaming/recovery.d.ts +3 -3
  266. package/dist/streaming/recovery.js +4 -4
  267. package/dist/streaming/registry.d.ts +6 -6
  268. package/dist/streaming/setup.d.ts +9 -8
  269. package/dist/streaming/setup.js +97 -49
  270. package/dist/streaming/setup.js.map +1 -1
  271. package/dist/streaming/showInfo.d.ts +9 -3
  272. package/dist/streaming/showInfo.js +26 -18
  273. package/dist/streaming/showInfo.js.map +1 -1
  274. package/dist/streaming/statusEmitter.d.ts +4 -4
  275. package/dist/streaming/statusEmitter.js +2 -2
  276. package/dist/types/channels.d.ts +133 -34
  277. package/dist/types/channels.js +39 -1
  278. package/dist/types/channels.js.map +1 -1
  279. package/dist/types/config.d.ts +20 -1
  280. package/dist/types/index.d.ts +9 -8
  281. package/dist/types/index.js +1 -0
  282. package/dist/types/index.js.map +1 -1
  283. package/dist/types/profiles.d.ts +5 -4
  284. package/dist/types/selection.d.ts +48 -4
  285. package/dist/types/streaming.d.ts +1 -1
  286. package/dist/upgrade/commands.context.d.ts +6 -0
  287. package/dist/upgrade/commands.context.js +29 -0
  288. package/dist/upgrade/commands.context.js.map +1 -0
  289. package/dist/upgrade/commands.d.ts +29 -2
  290. package/dist/upgrade/commands.js +87 -134
  291. package/dist/upgrade/commands.js.map +1 -1
  292. package/dist/upgrade/detection.context.d.ts +6 -0
  293. package/dist/upgrade/detection.context.js +24 -0
  294. package/dist/upgrade/detection.context.js.map +1 -0
  295. package/dist/upgrade/detection.d.ts +140 -10
  296. package/dist/upgrade/detection.js +153 -66
  297. package/dist/upgrade/detection.js.map +1 -1
  298. package/dist/upgrade/index.d.ts +2 -2
  299. package/dist/utils/chromeFetch.d.ts +1 -1
  300. package/dist/utils/chromeFetch.js +1 -1
  301. package/dist/utils/clock.d.ts +14 -0
  302. package/dist/utils/clock.js +28 -0
  303. package/dist/utils/clock.js.map +1 -0
  304. package/dist/utils/debugFilter.d.ts +1 -1
  305. package/dist/utils/debugFilter.js +6 -4
  306. package/dist/utils/debugFilter.js.map +1 -1
  307. package/dist/utils/delay.d.ts +2 -3
  308. package/dist/utils/delay.js +10 -16
  309. package/dist/utils/delay.js.map +1 -1
  310. package/dist/utils/evaluate.js +12 -14
  311. package/dist/utils/evaluate.js.map +1 -1
  312. package/dist/utils/ffmpeg.context.d.ts +6 -0
  313. package/dist/utils/ffmpeg.context.js +31 -0
  314. package/dist/utils/ffmpeg.context.js.map +1 -0
  315. package/dist/utils/ffmpeg.d.ts +85 -29
  316. package/dist/utils/ffmpeg.js +126 -129
  317. package/dist/utils/ffmpeg.js.map +1 -1
  318. package/dist/utils/fileLogger.d.ts +18 -2
  319. package/dist/utils/fileLogger.js +58 -30
  320. package/dist/utils/fileLogger.js.map +1 -1
  321. package/dist/utils/format.d.ts +1 -1
  322. package/dist/utils/format.js +2 -2
  323. package/dist/utils/format.js.map +1 -1
  324. package/dist/utils/html.js +1 -3
  325. package/dist/utils/html.js.map +1 -1
  326. package/dist/utils/index.d.ts +21 -20
  327. package/dist/utils/index.js +1 -0
  328. package/dist/utils/index.js.map +1 -1
  329. package/dist/utils/logger.js +16 -20
  330. package/dist/utils/logger.js.map +1 -1
  331. package/dist/utils/m3u.d.ts +18 -3
  332. package/dist/utils/m3u.js +28 -14
  333. package/dist/utils/m3u.js.map +1 -1
  334. package/dist/utils/memo.d.ts +19 -0
  335. package/dist/utils/memo.js +53 -0
  336. package/dist/utils/memo.js.map +1 -0
  337. package/dist/utils/morganStream.js +2 -2
  338. package/dist/utils/morganStream.js.map +1 -1
  339. package/dist/utils/pid.d.ts +2 -2
  340. package/dist/utils/pid.js +2 -2
  341. package/dist/utils/platform.d.ts +1 -1
  342. package/dist/utils/platform.js +3 -3
  343. package/dist/utils/platform.js.map +1 -1
  344. package/dist/utils/retry.d.ts +2 -0
  345. package/dist/utils/retry.js +9 -7
  346. package/dist/utils/retry.js.map +1 -1
  347. package/dist/utils/sanitize.d.ts +2 -2
  348. package/dist/utils/sanitize.js +4 -4
  349. package/dist/utils/timing.d.ts +6 -3
  350. package/dist/utils/timing.js +10 -6
  351. package/dist/utils/timing.js.map +1 -1
  352. package/dist/utils/version.d.ts +3 -2
  353. package/dist/utils/version.js +14 -27
  354. package/dist/utils/version.js.map +1 -1
  355. package/package.json +13 -7
  356. package/dist/native/intercept.d.ts +0 -35
  357. package/dist/native/intercept.js +0 -181
  358. package/dist/native/intercept.js.map +0 -1
  359. package/dist/routes/config/channels/routes.js +0 -1505
  360. package/dist/routes/config/channels/routes.js.map +0 -1
@@ -0,0 +1,131 @@
1
+ import { LOG, generateChannelKey, parseM3U, sanitizeString, stringifySorted } from "../../../../utils/index.js";
2
+ import { getChannelListing, getUserChannels, mutateChannels, resolveStoredChannel, validateChannelName, validateChannelUrl, validateImportedChannels } from "../../../../config/userChannels.js";
3
+ import { sendSuccess, sendValidationError } from "../../http/envelope.js";
4
+ import { buildChannelTablePatch } from "../table.js";
5
+ import { getProfiles } from "../../../../config/profiles.js";
6
+ import { route } from "../http/handler.js";
7
+ /**
8
+ * Registers the import/export endpoints on the Express application.
9
+ * @param app - The Express application.
10
+ */
11
+ export function registerImportExportRoutes(app) {
12
+ // GET /config/channels/export - Export user channels as JSON. Deltas are resolved to full definitions for backward compatibility with the import validator which
13
+ // requires url as a required field.
14
+ app.get("/config/channels/export", route("export channels", (_req, res) => {
15
+ const storedChannels = getUserChannels();
16
+ const resolved = {};
17
+ for (const [key, stored] of Object.entries(storedChannels)) {
18
+ resolved[key] = resolveStoredChannel(key, stored);
19
+ }
20
+ res.setHeader("Content-Type", "application/json");
21
+ res.setHeader("Content-Disposition", "attachment; filename=\"prismcast-channels.json\"");
22
+ res.send(stringifySorted(resolved) + "\n");
23
+ }));
24
+ // POST /config/channels/import - Import channels from JSON, replacing all existing user channels.
25
+ app.post("/config/channels/import", route("import channels", async (req, res) => {
26
+ const rawData = req.body;
27
+ const validProfiles = getProfiles().map((p) => p.name);
28
+ const validationResult = validateImportedChannels(rawData, validProfiles);
29
+ if (!validationResult.valid) {
30
+ sendValidationError(res, "Validation errors:\n" + validationResult.errors.join("\n"));
31
+ return;
32
+ }
33
+ // Replace the channels map outright. Reassigning preserves the surrounding metadata fields (migrationsApplied, schemaVersion, serviceSelections,
34
+ // tagRegistry); the framework's post-mutate normalize step requires data.channels to remain defined.
35
+ await mutateChannels((data) => {
36
+ data.channels = { ...validationResult.channels };
37
+ });
38
+ const channelCount = Object.keys(validationResult.channels).length;
39
+ // A bulk JSON import replaces every user channel - return a patch covering every key in the listing.
40
+ const allKeys = getChannelListing().map((entry) => entry.key);
41
+ const message = "Imported " + String(channelCount) + " channel" + (channelCount === 1 ? "" : "s") + " successfully.";
42
+ sendSuccess(res, { affectedKeys: allKeys, message });
43
+ }));
44
+ // POST /config/channels/import-m3u - Import channels from an M3U playlist file.
45
+ app.post("/config/channels/import-m3u", route("import channels", async (req, res) => {
46
+ const body = req.body;
47
+ const content = body.content;
48
+ const conflictMode = (body.conflictMode === "replace") ? "replace" : "skip";
49
+ if (!content || (typeof content !== "string") || (content.trim() === "")) {
50
+ sendValidationError(res, "No M3U content provided.");
51
+ return;
52
+ }
53
+ if ((body.conflictMode !== undefined) && (body.conflictMode !== "skip") && (body.conflictMode !== "replace")) {
54
+ sendValidationError(res, "Invalid conflict mode. Must be 'skip' or 'replace'.");
55
+ return;
56
+ }
57
+ const parseResult = parseM3U(content);
58
+ if (parseResult.channels.length === 0) {
59
+ sendValidationError(res, "No channels found in M3U file." + (parseResult.errors.length > 0 ? " Parse errors: " + parseResult.errors.join("; ") : ""));
60
+ return;
61
+ }
62
+ const affectedKeys = [];
63
+ const conflicts = [];
64
+ const importErrors = [];
65
+ const seenKeys = new Set();
66
+ let imported = 0;
67
+ let replaced = 0;
68
+ let skipped = 0;
69
+ // Pre-validate and sanitize each parsed channel before entering the mutation. This keeps pure validation outside the serialized write lock.
70
+ const validEntries = [];
71
+ for (const m3uChannel of parseResult.channels) {
72
+ m3uChannel.name = sanitizeString(m3uChannel.name);
73
+ m3uChannel.url = sanitizeString(m3uChannel.url);
74
+ m3uChannel.stationId &&= sanitizeString(m3uChannel.stationId);
75
+ const key = generateChannelKey(m3uChannel.name);
76
+ if (!key || (key.length === 0)) {
77
+ importErrors.push("Could not generate key for channel '" + m3uChannel.name + "'.");
78
+ continue;
79
+ }
80
+ // Skip duplicate keys within the same M3U file (first occurrence wins).
81
+ if (seenKeys.has(key)) {
82
+ continue;
83
+ }
84
+ seenKeys.add(key);
85
+ const urlError = validateChannelUrl(m3uChannel.url);
86
+ if (urlError) {
87
+ importErrors.push("Channel '" + m3uChannel.name + "': " + urlError);
88
+ continue;
89
+ }
90
+ const nameError = validateChannelName(m3uChannel.name);
91
+ if (nameError) {
92
+ importErrors.push("Channel '" + m3uChannel.name + "': " + nameError);
93
+ continue;
94
+ }
95
+ const channel = {
96
+ name: m3uChannel.name,
97
+ url: m3uChannel.url
98
+ };
99
+ if (m3uChannel.stationId) {
100
+ channel.stationId = m3uChannel.stationId;
101
+ }
102
+ validEntries.push({ channel, key });
103
+ }
104
+ // Apply the validated entries inside the transactional mutation. Conflict detection happens against the current stored channels.
105
+ await mutateChannels((data) => {
106
+ for (const { channel, key } of validEntries) {
107
+ if (key in data.channels) {
108
+ conflicts.push(key);
109
+ if (conflictMode === "skip") {
110
+ skipped++;
111
+ continue;
112
+ }
113
+ // Replace mode - count as replaced instead of imported.
114
+ replaced++;
115
+ }
116
+ else {
117
+ imported++;
118
+ }
119
+ data.channels[key] = channel;
120
+ affectedKeys.push(key);
121
+ }
122
+ });
123
+ LOG.info("M3U import completed: %d imported, %d replaced, %d skipped.", imported, replaced, skipped);
124
+ const patch = ((imported > 0) || (replaced > 0)) ? buildChannelTablePatch(affectedKeys, getProfiles()) : undefined;
125
+ sendSuccess(res, {
126
+ data: { conflicts, errors: [...parseResult.errors, ...importErrors], imported, replaced, skipped },
127
+ patch
128
+ });
129
+ }));
130
+ }
131
+ //# sourceMappingURL=importExport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"importExport.js","sourceRoot":"","sources":["../../../../../src/routes/config/channels/endpoints/importExport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Express } from "express";
2
+ /**
3
+ * Registers the predefined-toggle endpoints on the Express application.
4
+ * @param app - The Express application.
5
+ */
6
+ export declare function registerPredefinedRoutes(app: Express): void;
@@ -0,0 +1,78 @@
1
+ import { disablePredefinedChannels, enablePredefinedChannels, getEastWithPacificPredefinedKeys, getPacificPredefinedKeys, getPredefinedChannels, isPredefinedChannel } from "../../../../config/userChannels.js";
2
+ import { sendSuccess, sendValidationError } from "../../http/envelope.js";
3
+ import { LOG } from "../../../../utils/index.js";
4
+ import { route } from "../http/handler.js";
5
+ /**
6
+ * Registers the predefined-toggle endpoints on the Express application.
7
+ * @param app - The Express application.
8
+ */
9
+ export function registerPredefinedRoutes(app) {
10
+ // POST /config/channels/toggle-predefined - Toggle a single predefined channel's enabled/disabled state.
11
+ app.post("/config/channels/toggle-predefined", route("toggle channel", async (req, res) => {
12
+ const body = req.body;
13
+ const key = body.key?.trim();
14
+ const enabled = body.enabled;
15
+ if (!key) {
16
+ sendValidationError(res, "Channel key is required.");
17
+ return;
18
+ }
19
+ if (typeof enabled !== "boolean") {
20
+ sendValidationError(res, "Enabled state (true/false) is required.");
21
+ return;
22
+ }
23
+ if (!isPredefinedChannel(key)) {
24
+ sendValidationError(res, "Channel '" + key + "' is not a predefined channel.");
25
+ return;
26
+ }
27
+ if (enabled) {
28
+ await enablePredefinedChannels([key]);
29
+ }
30
+ else {
31
+ await disablePredefinedChannels([key]);
32
+ }
33
+ LOG.info("Predefined channel '%s' %s.", key, enabled ? "enabled" : "disabled");
34
+ sendSuccess(res, { affectedKeys: [key] });
35
+ }));
36
+ // POST /config/channels/bulk-toggle-predefined - Toggle predefined channels by scope (all, pacific, east).
37
+ app.post("/config/channels/bulk-toggle-predefined", route("toggle channels", async (req, res) => {
38
+ const body = req.body;
39
+ const enabled = body.enabled;
40
+ const scope = body.scope;
41
+ if (typeof enabled !== "boolean") {
42
+ sendValidationError(res, "Enabled state (true/false) is required.");
43
+ return;
44
+ }
45
+ if ((scope !== "all") && (scope !== "pacific") && (scope !== "east")) {
46
+ sendValidationError(res, "Scope must be 'all', 'pacific', or 'east'.");
47
+ return;
48
+ }
49
+ // Compute the target key set based on scope.
50
+ let targetKeys;
51
+ switch (scope) {
52
+ case "pacific": {
53
+ targetKeys = getPacificPredefinedKeys();
54
+ break;
55
+ }
56
+ case "east": {
57
+ targetKeys = getEastWithPacificPredefinedKeys();
58
+ break;
59
+ }
60
+ default: {
61
+ targetKeys = Object.keys(getPredefinedChannels());
62
+ break;
63
+ }
64
+ }
65
+ // Route through the shared enable/disable helpers so every path that mutates the disabled-predefined list goes through the same implementation. No separate
66
+ // inline branches - the helpers handle the subtractive/additive set manipulation and the CONFIG sync.
67
+ if (enabled) {
68
+ await enablePredefinedChannels(targetKeys);
69
+ }
70
+ else {
71
+ await disablePredefinedChannels(targetKeys);
72
+ }
73
+ const scopeLabel = (scope === "all") ? "All" : (scope === "pacific") ? "Pacific" : "East";
74
+ LOG.info("%s predefined channels %s (%d affected).", scopeLabel, enabled ? "enabled" : "disabled", targetKeys.length);
75
+ sendSuccess(res, { affectedKeys: targetKeys });
76
+ }));
77
+ }
78
+ //# sourceMappingURL=predefined.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"predefined.js","sourceRoot":"","sources":["../../../../../src/routes/config/channels/endpoints/predefined.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,gCAAgC,EAAE,wBAAwB,EAAE,qBAAqB,EAC7I,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,GAAG,EAAE,MAAM,4BAA4B,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAI3C;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CAAC,GAAY;IAEnD,yGAAyG;IACzG,GAAG,CAAC,IAAI,CAAC,oCAAoC,EAAE,KAAK,CAAC,gBAAgB,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QAE3G,MAAM,IAAI,GAAG,GAAG,CAAC,IAA2C,CAAC;QAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAE7B,IAAG,CAAC,GAAG,EAAE,CAAC;YAER,mBAAmB,CAAC,GAAG,EAAE,0BAA0B,CAAC,CAAC;YAErD,OAAO;QACT,CAAC;QAED,IAAG,OAAO,OAAO,KAAK,SAAS,EAAE,CAAC;YAEhC,mBAAmB,CAAC,GAAG,EAAE,yCAAyC,CAAC,CAAC;YAEpE,OAAO;QACT,CAAC;QAED,IAAG,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC;YAE7B,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,GAAG,GAAG,gCAAgC,CAAC,CAAC;YAE/E,OAAO;QACT,CAAC;QAED,IAAG,OAAO,EAAE,CAAC;YAEX,MAAM,wBAAwB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACxC,CAAC;aAAM,CAAC;YAEN,MAAM,yBAAyB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACzC,CAAC;QAED,GAAG,CAAC,IAAI,CAAC,6BAA6B,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QAE/E,WAAW,CAAC,GAAG,EAAE,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC,CAAC;IAEJ,2GAA2G;IAC3G,GAAG,CAAC,IAAI,CAAC,yCAAyC,EAAE,KAAK,CAAC,iBAAiB,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QAEjH,MAAM,IAAI,GAAG,GAAG,CAAC,IAA6C,CAAC;QAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,KAA8B,CAAC;QAElD,IAAG,OAAO,OAAO,KAAK,SAAS,EAAE,CAAC;YAEhC,mBAAmB,CAAC,GAAG,EAAE,yCAAyC,CAAC,CAAC;YAEpE,OAAO;QACT,CAAC;QAED,IAAG,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,IAAI,CAAC,KAAK,KAAK,MAAM,CAAC,EAAE,CAAC;YAEpE,mBAAmB,CAAC,GAAG,EAAE,4CAA4C,CAAC,CAAC;YAEvE,OAAO;QACT,CAAC;QAED,6CAA6C;QAC7C,IAAI,UAAoB,CAAC;QAEzB,QAAO,KAAK,EAAE,CAAC;YAEb,KAAK,SAAS,CAAC,CAAC,CAAC;gBAEf,UAAU,GAAG,wBAAwB,EAAE,CAAC;gBAExC,MAAM;YACR,CAAC;YAED,KAAK,MAAM,CAAC,CAAC,CAAC;gBAEZ,UAAU,GAAG,gCAAgC,EAAE,CAAC;gBAEhD,MAAM;YACR,CAAC;YAED,OAAO,CAAC,CAAC,CAAC;gBAER,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE,CAAC,CAAC;gBAElD,MAAM;YACR,CAAC;QACH,CAAC;QAED,4JAA4J;QAC5J,sGAAsG;QACtG,IAAG,OAAO,EAAE,CAAC;YAEX,MAAM,wBAAwB,CAAC,UAAU,CAAC,CAAC;QAC7C,CAAC;aAAM,CAAC;YAEN,MAAM,yBAAyB,CAAC,UAAU,CAAC,CAAC;QAC9C,CAAC;QAED,MAAM,UAAU,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;QAE1F,GAAG,CAAC,IAAI,CAAC,0CAA0C,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;QAEtH,WAAW,CAAC,GAAG,EAAE,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { Express } from "express";
2
+ /**
3
+ * Registers the display-preferences and setup-completed endpoints on the Express application.
4
+ * @param app - The Express application.
5
+ */
6
+ export declare function registerPrefsRoutes(app: Express): void;
@@ -0,0 +1,58 @@
1
+ import { VALID_OPTIONAL_COLUMNS, buildChannelTableState } from "../table.js";
2
+ import { markSetupCompleted, mutateChannelDisplayPrefs } from "../../../../config/userChannels.js";
3
+ import { sendSuccess, sendValidationError } from "../../http/envelope.js";
4
+ import { VALID_SORT_FIELDS } from "../../../../config/services.js";
5
+ import { route } from "../http/handler.js";
6
+ /**
7
+ * Registers the display-preferences and setup-completed endpoints on the Express application.
8
+ * @param app - The Express application.
9
+ */
10
+ export function registerPrefsRoutes(app) {
11
+ // POST /config/channels/display-prefs - Update channel table display preferences (visible columns, sort field, sort direction). Every field is optional;
12
+ // only supplied fields are updated. mutateChannelDisplayPrefs persists the change and updates the runtime CONFIG cache atomically.
13
+ app.post("/config/channels/display-prefs", route("update display preferences", async (req, res) => {
14
+ const body = req.body;
15
+ if (body.visibleColumns !== undefined) {
16
+ if (!Array.isArray(body.visibleColumns)) {
17
+ sendValidationError(res, "visibleColumns must be an array.");
18
+ return;
19
+ }
20
+ for (const col of body.visibleColumns) {
21
+ if (!VALID_OPTIONAL_COLUMNS.has(col)) {
22
+ sendValidationError(res, "Unknown column: " + col);
23
+ return;
24
+ }
25
+ }
26
+ }
27
+ if ((body.sortField !== undefined) && !VALID_SORT_FIELDS.has(body.sortField)) {
28
+ sendValidationError(res, "Unknown sort field: " + body.sortField);
29
+ return;
30
+ }
31
+ if ((body.sortDirection !== undefined) && (body.sortDirection !== "asc") && (body.sortDirection !== "desc")) {
32
+ sendValidationError(res, "sortDirection must be \"asc\" or \"desc\".");
33
+ return;
34
+ }
35
+ // After the validation guards above, sortDirection narrows to "asc" | "desc" via TypeScript's control-flow analysis. sortField stays string-typed because
36
+ // Set.has does not carry a type predicate, so the cast bridges that gap.
37
+ const update = {};
38
+ if (body.sortDirection !== undefined) {
39
+ update.channelSortDirection = body.sortDirection;
40
+ }
41
+ if (body.sortField !== undefined) {
42
+ update.channelSortField = body.sortField;
43
+ }
44
+ if (body.visibleColumns !== undefined) {
45
+ update.visibleColumns = body.visibleColumns;
46
+ }
47
+ await mutateChannelDisplayPrefs(update);
48
+ sendSuccess(res);
49
+ }));
50
+ // POST /config/channels/setup-completed - Mark the Service Setup flow as completed. Called when the wizard finishes or the user explicitly skips. Returns a
51
+ // counts-only patch so the client can refresh summary counters after the wizard's browse step may have added channels and changed the service filter.
52
+ app.post("/config/channels/setup-completed", route("save setup state", async (_req, res) => {
53
+ await markSetupCompleted();
54
+ const { counts, scopeCounts } = buildChannelTableState();
55
+ sendSuccess(res, { patch: { counts, rows: [], scopeCounts } });
56
+ }));
57
+ }
58
+ //# sourceMappingURL=prefs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prefs.js","sourceRoot":"","sources":["../../../../../src/routes/config/channels/endpoints/prefs.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACnG,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAY;IAE9C,yJAAyJ;IACzJ,mIAAmI;IACnI,GAAG,CAAC,IAAI,CAAC,gCAAgC,EAAE,KAAK,CAAC,4BAA4B,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QAEnH,MAAM,IAAI,GAAG,GAAG,CAAC,IAAiF,CAAC;QAEnG,IAAG,IAAI,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;YAErC,IAAG,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;gBAEvC,mBAAmB,CAAC,GAAG,EAAE,kCAAkC,CAAC,CAAC;gBAE7D,OAAO;YACT,CAAC;YAED,KAAI,MAAM,GAAG,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBAErC,IAAG,CAAC,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBAEpC,mBAAmB,CAAC,GAAG,EAAE,kBAAkB,GAAG,GAAG,CAAC,CAAC;oBAEnD,OAAO;gBACT,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAG,CAAC,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,SAA6B,CAAC,EAAE,CAAC;YAEhG,mBAAmB,CAAC,GAAG,EAAE,sBAAsB,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;YAElE,OAAO;QACT,CAAC;QAED,IAAG,CAAC,IAAI,CAAC,aAAa,KAAK,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,KAAK,MAAM,CAAC,EAAE,CAAC;YAE3G,mBAAmB,CAAC,GAAG,EAAE,4CAA4C,CAAC,CAAC;YAEvE,OAAO;QACT,CAAC;QAED,0JAA0J;QAC1J,yEAAyE;QACzE,MAAM,MAAM,GAAoD,EAAE,CAAC;QAEnE,IAAG,IAAI,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;YAEpC,MAAM,CAAC,oBAAoB,GAAG,IAAI,CAAC,aAAa,CAAC;QACnD,CAAC;QAED,IAAG,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YAEhC,MAAM,CAAC,gBAAgB,GAAG,IAAI,CAAC,SAA6B,CAAC;QAC/D,CAAC;QAED,IAAG,IAAI,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;YAErC,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC;QAC9C,CAAC;QAED,MAAM,yBAAyB,CAAC,MAAM,CAAC,CAAC;QAExC,WAAW,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC,CAAC;IAEJ,4JAA4J;IAC5J,sJAAsJ;IACtJ,GAAG,CAAC,IAAI,CAAC,kCAAkC,EAAE,KAAK,CAAC,kBAAkB,EAAE,KAAK,EAAE,IAAa,EAAE,GAAa,EAAE,EAAE;QAE5G,MAAM,kBAAkB,EAAE,CAAC;QAE3B,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,sBAAsB,EAAE,CAAC;QAEzD,WAAW,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { Express } from "express";
2
+ /**
3
+ * Registers the service-selection and service-filter endpoints on the Express application.
4
+ * @param app - The Express application.
5
+ */
6
+ export declare function registerServiceRoutes(app: Express): void;
@@ -0,0 +1,149 @@
1
+ import { getAllServiceTags, getCanonicalKey, getChannelServiceLabel, getEnabledServices, getResolvedChannel, getServiceGroup, getServiceSelection, getServiceTagForChannel, mutateEnabledServices, mutateServiceSelections, setServiceSelection } from "../../../../config/services.js";
2
+ import { sendSuccess, sendValidationError } from "../../http/envelope.js";
3
+ import { LOG } from "../../../../utils/index.js";
4
+ import { buildChannelTableState } from "../table.js";
5
+ import { getChannelListing } from "../../../../config/userChannels.js";
6
+ import { route } from "../http/handler.js";
7
+ /**
8
+ * Registers the service-selection and service-filter endpoints on the Express application.
9
+ * @param app - The Express application.
10
+ */
11
+ export function registerServiceRoutes(app) {
12
+ // PUT /config/channels/:key/service - Update service selection for a multi-service channel.
13
+ app.put("/config/channels/:key/service", route("update service", async (req, res) => {
14
+ const params = req.params;
15
+ const body = req.body;
16
+ const channelKey = params.key?.trim();
17
+ const serviceKey = body.service?.trim();
18
+ if (!channelKey) {
19
+ sendValidationError(res, "Channel key is required.");
20
+ return;
21
+ }
22
+ if (!serviceKey) {
23
+ sendValidationError(res, "Service key is required.");
24
+ return;
25
+ }
26
+ // Canonicalize the channel key so selections are stored under the canonical, not variant keys.
27
+ const canonicalKey = getCanonicalKey(channelKey);
28
+ const serviceGroup = getServiceGroup(canonicalKey);
29
+ if (!serviceGroup) {
30
+ sendValidationError(res, "Channel '" + canonicalKey + "' does not have multiple services.");
31
+ return;
32
+ }
33
+ const validServiceKeys = serviceGroup.variants.map((v) => v.key);
34
+ if (!validServiceKeys.includes(serviceKey)) {
35
+ sendValidationError(res, "Invalid service '" + serviceKey + "' for channel '" + canonicalKey + "'.");
36
+ return;
37
+ }
38
+ await setServiceSelection(canonicalKey, serviceKey);
39
+ const canonicalChannel = getResolvedChannel(canonicalKey);
40
+ const variantChannel = getResolvedChannel(serviceKey);
41
+ const channelName = canonicalChannel?.name ?? canonicalKey;
42
+ const serviceLabel = variantChannel ? getChannelServiceLabel(variantChannel) : serviceKey;
43
+ LOG.info("Service for %s changed to %s.", channelName, serviceLabel);
44
+ sendSuccess(res, { affectedKeys: [canonicalKey] });
45
+ }));
46
+ // POST /config/service-filter - Update the service filter (enabled service tags). Empty array means no filter (all services visible).
47
+ app.post("/config/service-filter", route("update service filter", async (req, res) => {
48
+ const body = req.body;
49
+ const tags = body.enabledServices;
50
+ if (!Array.isArray(tags)) {
51
+ sendValidationError(res, "enabledServices must be an array.");
52
+ return;
53
+ }
54
+ // Validate all tags are known. Tags already in enabledServices are accepted even if no current channel or profile produces them - this allows stale tags to be
55
+ // removed via the UI without blocking the request.
56
+ const knownTags = new Set(getAllServiceTags().map((t) => t.tag));
57
+ const currentTags = new Set(getEnabledServices());
58
+ for (const tag of tags) {
59
+ if (!knownTags.has(tag) && !currentTags.has(tag)) {
60
+ sendValidationError(res, "Unknown service tag: " + tag);
61
+ return;
62
+ }
63
+ }
64
+ await mutateEnabledServices(tags);
65
+ LOG.info("Service filter updated: %s.", tags.length > 0 ? tags.join(", ") : "all services");
66
+ // Counts-only patch - the client applies CSS visibility changes itself and only needs updated summary counters.
67
+ const { counts, scopeCounts } = buildChannelTableState();
68
+ sendSuccess(res, { patch: { counts, rows: [], scopeCounts } });
69
+ }));
70
+ // POST /config/service-bulk-assign - Set all multi-service channels to a specific service tag, where available.
71
+ app.post("/config/service-bulk-assign", route("bulk assign service", async (req, res) => {
72
+ const body = req.body;
73
+ const serviceTag = body.service?.trim();
74
+ if (!serviceTag) {
75
+ sendValidationError(res, "Service tag is required.");
76
+ return;
77
+ }
78
+ let affected = 0;
79
+ const previousSelections = {};
80
+ const selections = {};
81
+ const updates = {};
82
+ const listing = getChannelListing();
83
+ for (const entry of listing) {
84
+ const group = getServiceGroup(entry.key);
85
+ if (!group || (group.variants.length <= 1)) {
86
+ continue;
87
+ }
88
+ const matchingVariant = group.variants.find((v) => (getServiceTagForChannel(v.key) === serviceTag));
89
+ if (matchingVariant) {
90
+ // Snapshot the current selection before overwriting so the client can offer undo.
91
+ const currentVariant = getServiceSelection(entry.key);
92
+ previousSelections[entry.key] = currentVariant ?? null;
93
+ updates[entry.key] = matchingVariant.key;
94
+ affected++;
95
+ const resolvedChannel = getResolvedChannel(matchingVariant.key);
96
+ selections[entry.key] = { profile: resolvedChannel?.profile ?? null, variant: matchingVariant.key };
97
+ }
98
+ }
99
+ // Single atomic write for all selection changes.
100
+ if (Object.keys(updates).length > 0) {
101
+ await mutateServiceSelections(updates);
102
+ }
103
+ LOG.info("Bulk assign to '%s': %d of %d channels affected.", serviceTag, affected, listing.length);
104
+ sendSuccess(res, { data: { affected, previousSelections, selections, total: listing.length } });
105
+ }));
106
+ // POST /config/service-bulk-restore - Restore previous service selections (undo bulk assign).
107
+ app.post("/config/service-bulk-restore", route("bulk restore services", async (req, res) => {
108
+ const body = req.body;
109
+ const previousSelections = body.selections;
110
+ if (!previousSelections || (typeof previousSelections !== "object")) {
111
+ sendValidationError(res, "Selections map is required.");
112
+ return;
113
+ }
114
+ let restored = 0;
115
+ const selections = {};
116
+ const updates = {};
117
+ for (const [key, variantKey] of Object.entries(previousSelections)) {
118
+ const group = getServiceGroup(key);
119
+ if (!group) {
120
+ continue;
121
+ }
122
+ // A null value means the channel was using the default (canonical) selection. Restoring by setting the selection to the canonical key clears the
123
+ // override (mutateServiceSelections treats serviceKey === canonicalKey as delete).
124
+ if (variantKey === null) {
125
+ updates[key] = key;
126
+ }
127
+ else {
128
+ // Validate the variant belongs to this channel's service group before restoring.
129
+ const isValid = group.variants.some((v) => (v.key === variantKey));
130
+ if (!isValid) {
131
+ continue;
132
+ }
133
+ updates[key] = variantKey;
134
+ }
135
+ restored++;
136
+ // Build the same selection response format as bulk assign for client-side UI updates.
137
+ const effectiveKey = variantKey ?? key;
138
+ const resolvedChannel = getResolvedChannel(effectiveKey);
139
+ selections[key] = { profile: resolvedChannel?.profile ?? null, variant: effectiveKey };
140
+ }
141
+ // Single atomic write for all restored selections.
142
+ if (Object.keys(updates).length > 0) {
143
+ await mutateServiceSelections(updates);
144
+ }
145
+ LOG.info("Bulk restore: %d channel(s) reverted.", restored);
146
+ sendSuccess(res, { data: { restored, selections } });
147
+ }));
148
+ }
149
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../../../../src/routes/config/channels/endpoints/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Express } from "express";
2
+ /**
3
+ * Registers the tag management endpoints on the Express application.
4
+ * @param app - The Express application.
5
+ */
6
+ export declare function registerTagRoutes(app: Express): void;