prismcast 1.5.2 → 1.7.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 +44 -28
- package/dist/app.d.ts +5 -0
- package/dist/app.js +63 -5
- 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 +10 -34
- package/dist/browser/channelSelection.js +31 -96
- package/dist/browser/channelSelection.js.map +1 -1
- package/dist/browser/display.d.ts +19 -0
- package/dist/browser/display.js +16 -11
- package/dist/browser/display.js.map +1 -1
- package/dist/browser/index.d.ts +31 -54
- package/dist/browser/index.js +334 -272
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/login.d.ts +65 -0
- package/dist/browser/login.js +193 -0
- package/dist/browser/login.js.map +1 -0
- package/dist/browser/precaching.js +15 -3
- package/dist/browser/precaching.js.map +1 -1
- package/dist/browser/tuning/comcastPolymer.d.ts +23 -0
- package/dist/browser/tuning/comcastPolymer.js +655 -0
- package/dist/browser/tuning/comcastPolymer.js.map +1 -0
- package/dist/browser/tuning/cox.d.ts +2 -0
- package/dist/browser/tuning/cox.js +14 -0
- package/dist/browser/tuning/cox.js.map +1 -0
- package/dist/browser/tuning/directv.js +14 -1
- package/dist/browser/tuning/directv.js.map +1 -1
- package/dist/browser/tuning/fox.js +14 -2
- package/dist/browser/tuning/fox.js.map +1 -1
- package/dist/browser/tuning/hbo.js +12 -1
- package/dist/browser/tuning/hbo.js.map +1 -1
- package/dist/browser/tuning/hulu.js +24 -1
- package/dist/browser/tuning/hulu.js.map +1 -1
- package/dist/browser/tuning/shared.d.ts +46 -0
- package/dist/browser/tuning/shared.js +100 -0
- package/dist/browser/tuning/shared.js.map +1 -0
- package/dist/browser/tuning/sling.js +35 -5
- package/dist/browser/tuning/sling.js.map +1 -1
- package/dist/browser/tuning/spectrum.js +13 -1
- package/dist/browser/tuning/spectrum.js.map +1 -1
- package/dist/browser/tuning/thumbnailRow.js +1 -1
- package/dist/browser/tuning/thumbnailRow.js.map +1 -1
- package/dist/browser/tuning/tileClick.js +1 -1
- package/dist/browser/tuning/tileClick.js.map +1 -1
- package/dist/browser/tuning/xfinity.d.ts +2 -0
- package/dist/browser/tuning/xfinity.js +14 -0
- package/dist/browser/tuning/xfinity.js.map +1 -0
- package/dist/browser/tuning/youtubeTv.js +15 -1
- package/dist/browser/tuning/youtubeTv.js.map +1 -1
- package/dist/browser/video.d.ts +20 -0
- package/dist/browser/video.js +168 -124
- package/dist/browser/video.js.map +1 -1
- package/dist/channels/index.d.ts +2 -2
- package/dist/channels/index.js +2075 -683
- package/dist/channels/index.js.map +1 -1
- package/dist/config/health.d.ts +28 -28
- package/dist/config/health.js +72 -54
- package/dist/config/health.js.map +1 -1
- package/dist/config/index.js +29 -64
- package/dist/config/index.js.map +1 -1
- package/dist/config/paths.d.ts +12 -0
- package/dist/config/paths.js +16 -0
- package/dist/config/paths.js.map +1 -1
- package/dist/config/profiles.d.ts +3 -2
- package/dist/config/profiles.js +45 -34
- package/dist/config/profiles.js.map +1 -1
- package/dist/config/providerPacks.js +4 -1
- package/dist/config/providerPacks.js.map +1 -1
- package/dist/config/providers.d.ts +19 -5
- package/dist/config/providers.js +123 -93
- package/dist/config/providers.js.map +1 -1
- package/dist/config/sites.d.ts +28 -0
- package/dist/config/sites.js +104 -127
- package/dist/config/sites.js.map +1 -1
- package/dist/config/userChannels.d.ts +53 -2
- package/dist/config/userChannels.js +222 -13
- package/dist/config/userChannels.js.map +1 -1
- package/dist/config/userConfig.d.ts +2 -1
- package/dist/config/userConfig.js +6 -15
- package/dist/config/userConfig.js.map +1 -1
- package/dist/config/userProfiles.d.ts +0 -1
- package/dist/config/userProfiles.js +18 -10
- package/dist/config/userProfiles.js.map +1 -1
- package/dist/hdhr/channelMap.d.ts +1 -1
- package/dist/hdhr/channelMap.js +4 -4
- package/dist/hdhr/channelMap.js.map +1 -1
- package/dist/index.js +25 -22
- package/dist/index.js.map +1 -1
- package/dist/native/decrypt.d.ts +32 -0
- package/dist/native/decrypt.js +85 -0
- package/dist/native/decrypt.js.map +1 -0
- package/dist/native/index.d.ts +61 -0
- package/dist/native/index.js +342 -0
- package/dist/native/index.js.map +1 -0
- package/dist/native/intercept.d.ts +35 -0
- package/dist/native/intercept.js +184 -0
- package/dist/native/intercept.js.map +1 -0
- package/dist/native/probe.d.ts +49 -0
- package/dist/native/probe.js +294 -0
- package/dist/native/probe.js.map +1 -0
- package/dist/native/proxy.d.ts +54 -0
- package/dist/native/proxy.js +947 -0
- package/dist/native/proxy.js.map +1 -0
- package/dist/routes/components.d.ts +43 -0
- package/dist/routes/components.js +122 -0
- package/dist/routes/components.js.map +1 -1
- package/dist/routes/config/channels/index.d.ts +2 -2
- package/dist/routes/config/channels/index.js +1 -1
- package/dist/routes/config/channels/index.js.map +1 -1
- package/dist/routes/config/channels/routes.js +443 -65
- package/dist/routes/config/channels/routes.js.map +1 -1
- package/dist/routes/config/channels/table.d.ts +76 -0
- package/dist/routes/config/channels/table.js +369 -89
- package/dist/routes/config/channels/table.js.map +1 -1
- package/dist/routes/config/index.d.ts +1 -1
- package/dist/routes/config/index.js +1 -1
- package/dist/routes/config/index.js.map +1 -1
- package/dist/routes/config/providers.d.ts +6 -6
- package/dist/routes/config/providers.js +73 -99
- package/dist/routes/config/providers.js.map +1 -1
- package/dist/routes/debug.js +5 -5
- package/dist/routes/debug.js.map +1 -1
- package/dist/routes/hls.js +12 -2
- package/dist/routes/hls.js.map +1 -1
- package/dist/routes/index.d.ts +0 -15
- package/dist/routes/index.js +2 -16
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/providers.js +106 -3
- package/dist/routes/providers.js.map +1 -1
- package/dist/routes/root/content.js +124 -47
- package/dist/routes/root/content.js.map +1 -1
- package/dist/routes/root/index.js +2 -1
- package/dist/routes/root/index.js.map +1 -1
- package/dist/routes/root/scripts/channels.js +772 -312
- package/dist/routes/root/scripts/channels.js.map +1 -1
- package/dist/routes/root/scripts/config.js +596 -544
- package/dist/routes/root/scripts/config.js.map +1 -1
- package/dist/routes/root/scripts/index.d.ts +1 -0
- package/dist/routes/root/scripts/index.js +1 -0
- package/dist/routes/root/scripts/index.js.map +1 -1
- package/dist/routes/root/scripts/shared.d.ts +6 -0
- package/dist/routes/root/scripts/shared.js +391 -0
- package/dist/routes/root/scripts/shared.js.map +1 -0
- package/dist/routes/root/scripts/status.js +49 -33
- package/dist/routes/root/scripts/status.js.map +1 -1
- package/dist/routes/root/styles.js +117 -10
- package/dist/routes/root/styles.js.map +1 -1
- package/dist/service/commands.js +2 -1
- package/dist/service/commands.js.map +1 -1
- package/dist/streaming/fmp4Segmenter.d.ts +5 -0
- package/dist/streaming/fmp4Segmenter.js +146 -42
- package/dist/streaming/fmp4Segmenter.js.map +1 -1
- package/dist/streaming/hls.d.ts +24 -19
- package/dist/streaming/hls.js +603 -297
- package/dist/streaming/hls.js.map +1 -1
- package/dist/streaming/hlsResume.d.ts +16 -3
- package/dist/streaming/hlsResume.js +35 -8
- package/dist/streaming/hlsResume.js.map +1 -1
- package/dist/streaming/hlsSegments.d.ts +41 -2
- package/dist/streaming/hlsSegments.js +131 -28
- package/dist/streaming/hlsSegments.js.map +1 -1
- package/dist/streaming/lifecycle.js +27 -13
- package/dist/streaming/lifecycle.js.map +1 -1
- package/dist/streaming/monitor.d.ts +1 -0
- package/dist/streaming/monitor.js +862 -474
- package/dist/streaming/monitor.js.map +1 -1
- package/dist/streaming/mp4Parser.d.ts +52 -6
- package/dist/streaming/mp4Parser.js +156 -30
- package/dist/streaming/mp4Parser.js.map +1 -1
- package/dist/streaming/mpegts.d.ts +2 -2
- package/dist/streaming/mpegts.js +156 -109
- package/dist/streaming/mpegts.js.map +1 -1
- package/dist/streaming/playlistBuilder.d.ts +38 -0
- package/dist/streaming/playlistBuilder.js +66 -0
- package/dist/streaming/playlistBuilder.js.map +1 -0
- package/dist/streaming/preroll.d.ts +126 -0
- package/dist/streaming/preroll.js +434 -0
- package/dist/streaming/preroll.js.map +1 -0
- package/dist/streaming/pretune.d.ts +8 -0
- package/dist/streaming/pretune.js +226 -0
- package/dist/streaming/pretune.js.map +1 -0
- package/dist/streaming/recovery.d.ts +0 -6
- package/dist/streaming/recovery.js +0 -8
- package/dist/streaming/recovery.js.map +1 -1
- package/dist/streaming/registry.d.ts +57 -9
- package/dist/streaming/registry.js +26 -7
- package/dist/streaming/registry.js.map +1 -1
- package/dist/streaming/setup.d.ts +8 -1
- package/dist/streaming/setup.js +71 -27
- package/dist/streaming/setup.js.map +1 -1
- package/dist/streaming/showInfo.d.ts +29 -4
- package/dist/streaming/showInfo.js +210 -38
- package/dist/streaming/showInfo.js.map +1 -1
- package/dist/streaming/statusEmitter.d.ts +20 -6
- package/dist/streaming/statusEmitter.js +31 -7
- package/dist/streaming/statusEmitter.js.map +1 -1
- package/dist/types/channels.d.ts +32 -0
- package/dist/types/config.d.ts +2 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.js.map +1 -1
- package/dist/types/profiles.d.ts +13 -1
- package/dist/types/selection.d.ts +5 -1
- package/dist/types/shared.d.ts +1 -1
- package/dist/types/streaming.d.ts +7 -0
- package/dist/utils/chromeFetch.d.ts +20 -0
- package/dist/utils/chromeFetch.js +43 -0
- package/dist/utils/chromeFetch.js.map +1 -0
- package/dist/utils/debugFilter.d.ts +0 -5
- package/dist/utils/debugFilter.js +20 -11
- package/dist/utils/debugFilter.js.map +1 -1
- package/dist/utils/delay.d.ts +28 -0
- package/dist/utils/delay.js +35 -1
- package/dist/utils/delay.js.map +1 -1
- package/dist/utils/evaluate.js +6 -11
- package/dist/utils/evaluate.js.map +1 -1
- package/dist/utils/ffmpeg.d.ts +14 -12
- package/dist/utils/ffmpeg.js +114 -134
- package/dist/utils/ffmpeg.js.map +1 -1
- package/dist/utils/format.d.ts +6 -0
- package/dist/utils/format.js +8 -0
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/logEmitter.js +1 -1
- package/dist/utils/logEmitter.js.map +1 -1
- package/dist/utils/pid.d.ts +40 -0
- package/dist/utils/pid.js +83 -0
- package/dist/utils/pid.js.map +1 -0
- package/dist/utils/retry.d.ts +15 -9
- package/dist/utils/retry.js +7 -23
- package/dist/utils/retry.js.map +1 -1
- package/dist/utils/timing.d.ts +5 -0
- package/dist/utils/timing.js +13 -0
- package/dist/utils/timing.js.map +1 -0
- package/dist/utils/version.js +2 -2
- package/dist/utils/version.js.map +1 -1
- package/package.json +7 -7
|
@@ -1,30 +1,46 @@
|
|
|
1
1
|
/* Copyright(C) 2024-2026, HJD (https://github.com/hjdhjd). All rights reserved.
|
|
2
2
|
*
|
|
3
|
-
* showInfo.ts: Channels DVR API integration for show name lookup.
|
|
3
|
+
* showInfo.ts: Channels DVR API integration for show name and channel logo lookup.
|
|
4
4
|
*/
|
|
5
5
|
import { LOG, formatError } from "../utils/index.js";
|
|
6
|
-
import { getAllChannels } from "../config/userChannels.js";
|
|
6
|
+
import { clearChannelLogos, getAllChannels, getChannelListing, getChannelLogo, getChannelStationId, setChannelLogo, setChannelLogos } from "../config/userChannels.js";
|
|
7
|
+
import { loadUserConfig, saveUserConfig } from "../config/userConfig.js";
|
|
8
|
+
import { emitChannelUpdate } from "./statusEmitter.js";
|
|
7
9
|
import { getAllStreams } from "./registry.js";
|
|
8
|
-
/* This module integrates with the Channels DVR API
|
|
10
|
+
/* This module integrates with the Channels DVR API for two purposes: show name lookup and channel logo population.
|
|
9
11
|
*
|
|
10
|
-
*
|
|
11
|
-
* 2. Program guide (/devices/{id}/guide/now) - For live viewing without recording, we fall back to the current program from the guide
|
|
12
|
+
* Show names are determined from two sources:
|
|
12
13
|
*
|
|
13
|
-
*
|
|
14
|
+
* 1. Active recordings (/dvr/jobs) - if Channels DVR is recording a channel, we get the show name from the recording job.
|
|
15
|
+
* 2. Program guide (/devices/{id}/guide/now) - for live viewing without recording, we fall back to the current program from the guide.
|
|
16
|
+
*
|
|
17
|
+
* The show name polling mechanism uses a two-phase approach - discovery and lookup:
|
|
14
18
|
*
|
|
15
19
|
* 1. Discovery: Every 30 seconds, try each unique client address as a potential Channels DVR server by calling getDeviceMappings(). If a host has matching M3U
|
|
16
20
|
* devices, cache it as the last known DVR host. Device mappings are cached for 5 minutes, so non-DVR hosts (e.g., Plex IPs) only incur a network timeout on the
|
|
17
21
|
* first attempt and every 5 minutes thereafter.
|
|
18
22
|
*
|
|
19
|
-
* 2. Lookup: Use the cached DVR host for show name
|
|
20
|
-
* streams to display show names
|
|
23
|
+
* 2. Lookup: Use the cached DVR host for show name lookups across ALL active streams, regardless of which client initiated them. This enables Plex-initiated
|
|
24
|
+
* streams to display show names from the Channels DVR guide, as long as any Channels DVR connection has been seen at some point.
|
|
25
|
+
*
|
|
26
|
+
* Channel logos are populated in two tiers when a DVR host is known:
|
|
27
|
+
*
|
|
28
|
+
* 1. Tier 1 (/devices): Logo URLs are extracted from the matched M3U device's channel list during getDeviceMappings(). This covers all channels in the M3U
|
|
29
|
+
* playlist with authoritative, current logo URLs from the DVR.
|
|
30
|
+
*
|
|
31
|
+
* 2. Tier 2 (/tms/stations/{name}): For channels with station IDs not covered by tier 1 (disabled channels, channels without an enabled provider), a TMS station
|
|
32
|
+
* name search finds the best matching logo. Results are matched by station ID when possible, otherwise the first result with a valid logo is used.
|
|
33
|
+
*
|
|
34
|
+
* Logo population runs on DVR host discovery (startup or first stream connection) and refreshes every 24 hours. Individual channel add/edit operations trigger a
|
|
35
|
+
* single-entry TMS search for immediate logo availability.
|
|
21
36
|
*
|
|
22
37
|
* Caching strategy:
|
|
23
38
|
* - Last known DVR host: Persists across poll cycles, resets on shutdown
|
|
24
39
|
* - Device channel mappings: Cached for 5 minutes per host (rarely change)
|
|
25
40
|
* - Recording jobs and guide data: Fetched fresh each poll cycle (30 seconds)
|
|
41
|
+
* - Channel logos: Cached by station ID in userChannels.ts, refreshed every 24 hours
|
|
26
42
|
*
|
|
27
|
-
* Failure handling is graceful: if the API is unreachable or returns no match,
|
|
43
|
+
* Failure handling is graceful: if the API is unreachable or returns no match, show names and logos simply stay empty. This never affects streaming functionality.
|
|
28
44
|
*/
|
|
29
45
|
// Constants.
|
|
30
46
|
// Default Channels DVR port.
|
|
@@ -37,7 +53,9 @@ const MAPPINGS_REFRESH_INTERVAL_MS = 300000;
|
|
|
37
53
|
const API_TIMEOUT_MS = 5000;
|
|
38
54
|
// Debounce delay for triggered updates (2 seconds).
|
|
39
55
|
const TRIGGER_DEBOUNCE_MS = 2000;
|
|
40
|
-
// Logo
|
|
56
|
+
// Logo refresh interval (24 hours). Logos change when networks rebrand, which is a handful of times per year.
|
|
57
|
+
const LOGO_REFRESH_INTERVAL_MS = 86400000;
|
|
58
|
+
// Logo image height in pixels for URL normalization (2x for retina displays). Applied to CDN URLs to request smaller images for UI rendering.
|
|
41
59
|
const LOGO_HEIGHT_PX = 48;
|
|
42
60
|
// State.
|
|
43
61
|
// Interval handle for periodic polling.
|
|
@@ -46,14 +64,35 @@ let pollInterval = null;
|
|
|
46
64
|
const showNameCache = new Map();
|
|
47
65
|
// Cache of device channel mappings by DVR host.
|
|
48
66
|
const deviceMappingsByHost = new Map();
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
// Last known Channels DVR host that had matching M3U devices. Used to look up show names
|
|
67
|
+
// Interval handle for 24-hour logo refresh.
|
|
68
|
+
let logoRefreshInterval = null;
|
|
69
|
+
// Last known Channels DVR host that had matching M3U devices. Used to look up show names for all streams, including those initiated by non-DVR clients
|
|
52
70
|
// (e.g., Plex). Persists across poll cycles but resets on shutdown. Updated whenever getDeviceMappings() finds matching devices on a host.
|
|
53
71
|
let lastKnownDvrHost = null;
|
|
54
72
|
// Pending debounced trigger for immediate show name updates.
|
|
55
73
|
let pendingTrigger = null;
|
|
56
74
|
// Public API.
|
|
75
|
+
/**
|
|
76
|
+
* Returns the last known Channels DVR host address. Used by the pretune module to poll for upcoming scheduled recordings.
|
|
77
|
+
* @returns The DVR host address, or null if no DVR host has been discovered.
|
|
78
|
+
*/
|
|
79
|
+
export function getDvrHost() {
|
|
80
|
+
return lastKnownDvrHost;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Sets the DVR host address and persists it to the config file if it changed. Called by the discovery loop when a matching M3U device is found on a host.
|
|
84
|
+
* @param host - The DVR server hostname or IP address.
|
|
85
|
+
*/
|
|
86
|
+
export function setDvrHost(host) {
|
|
87
|
+
if (lastKnownDvrHost === host) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
lastKnownDvrHost = host;
|
|
91
|
+
void persistDvrHost(host);
|
|
92
|
+
// Populate logos whenever the DVR host changes. The early return above (host === lastKnownDvrHost) prevents redundant calls during show name polling's
|
|
93
|
+
// repeated confirmations of the same host. A genuine host change (e.g., DVR migration) triggers a full re-population with the new host's data.
|
|
94
|
+
void populateChannelLogos();
|
|
95
|
+
}
|
|
57
96
|
/**
|
|
58
97
|
* Starts the show info polling interval. Should be called on server startup.
|
|
59
98
|
*/
|
|
@@ -61,11 +100,17 @@ export function startShowInfoPolling() {
|
|
|
61
100
|
if (pollInterval) {
|
|
62
101
|
return;
|
|
63
102
|
}
|
|
103
|
+
// Load the persisted DVR host from the config file so the pretune module can begin polling immediately on startup.
|
|
104
|
+
void loadPersistedDvrHost();
|
|
64
105
|
// Run immediately on startup, then every 30 seconds.
|
|
65
106
|
void updateShowNames();
|
|
66
107
|
pollInterval = setInterval(() => {
|
|
67
108
|
void updateShowNames();
|
|
68
109
|
}, POLL_INTERVAL_MS);
|
|
110
|
+
// Start the 24-hour logo refresh. The initial population is triggered by loadPersistedDvrHost() or setDvrHost() when a DVR host becomes known.
|
|
111
|
+
logoRefreshInterval = setInterval(() => {
|
|
112
|
+
void populateChannelLogos();
|
|
113
|
+
}, LOGO_REFRESH_INTERVAL_MS);
|
|
69
114
|
}
|
|
70
115
|
/**
|
|
71
116
|
* Stops the show info polling interval. Should be called on server shutdown.
|
|
@@ -75,6 +120,11 @@ export function stopShowInfoPolling() {
|
|
|
75
120
|
clearInterval(pollInterval);
|
|
76
121
|
pollInterval = null;
|
|
77
122
|
}
|
|
123
|
+
// Clear the logo refresh interval.
|
|
124
|
+
if (logoRefreshInterval) {
|
|
125
|
+
clearInterval(logoRefreshInterval);
|
|
126
|
+
logoRefreshInterval = null;
|
|
127
|
+
}
|
|
78
128
|
// Clear pending trigger.
|
|
79
129
|
if (pendingTrigger) {
|
|
80
130
|
clearTimeout(pendingTrigger);
|
|
@@ -83,7 +133,7 @@ export function stopShowInfoPolling() {
|
|
|
83
133
|
// Clear caches and cached DVR host on shutdown.
|
|
84
134
|
showNameCache.clear();
|
|
85
135
|
deviceMappingsByHost.clear();
|
|
86
|
-
|
|
136
|
+
clearChannelLogos();
|
|
87
137
|
lastKnownDvrHost = null;
|
|
88
138
|
}
|
|
89
139
|
/**
|
|
@@ -116,18 +166,10 @@ export function getShowName(streamId) {
|
|
|
116
166
|
export function clearShowName(streamId) {
|
|
117
167
|
showNameCache.delete(streamId);
|
|
118
168
|
}
|
|
119
|
-
/**
|
|
120
|
-
* Gets the cached logo URL for a channel.
|
|
121
|
-
* @param channelKey - The channel key to look up (e.g., "cnn").
|
|
122
|
-
* @returns The logo URL if known, undefined otherwise.
|
|
123
|
-
*/
|
|
124
|
-
export function getChannelLogo(channelKey) {
|
|
125
|
-
return channelLogoCache.get(channelKey);
|
|
126
|
-
}
|
|
127
169
|
// Internal Functions.
|
|
128
170
|
/**
|
|
129
171
|
* Updates show names for all active streams. Discovery phase tries each unique client address as a potential Channels DVR server. Lookup phase uses the cached DVR
|
|
130
|
-
* host for all streams, enabling non-DVR clients (e.g., Plex) to display show names
|
|
172
|
+
* host for all streams, enabling non-DVR clients (e.g., Plex) to display show names.
|
|
131
173
|
*/
|
|
132
174
|
async function updateShowNames() {
|
|
133
175
|
const streams = getAllStreams();
|
|
@@ -150,10 +192,10 @@ async function updateShowNames() {
|
|
|
150
192
|
await Promise.all(Array.from(discoveryHosts).map(async (host) => {
|
|
151
193
|
const mappings = await getDeviceMappings(host);
|
|
152
194
|
if (mappings.size > 0) {
|
|
153
|
-
|
|
195
|
+
setDvrHost(host);
|
|
154
196
|
}
|
|
155
197
|
}));
|
|
156
|
-
// Lookup phase: use the cached DVR host for show name
|
|
198
|
+
// Lookup phase: use the cached DVR host for show name lookups across all streams.
|
|
157
199
|
if (lastKnownDvrHost) {
|
|
158
200
|
await updateShowNamesForHost(lastKnownDvrHost, allStreamEntries);
|
|
159
201
|
return;
|
|
@@ -221,7 +263,7 @@ async function updateShowNamesForHost(host, hostStreams) {
|
|
|
221
263
|
* @param host - The DVR server hostname or IP address.
|
|
222
264
|
* @returns Map of DeviceID → (Map of GuideNumber → channel ID).
|
|
223
265
|
*/
|
|
224
|
-
async function getDeviceMappings(host) {
|
|
266
|
+
export async function getDeviceMappings(host) {
|
|
225
267
|
const cached = deviceMappingsByHost.get(host);
|
|
226
268
|
const now = Date.now();
|
|
227
269
|
// Return cached mappings if they're fresh enough.
|
|
@@ -261,18 +303,23 @@ async function getDeviceMappings(host) {
|
|
|
261
303
|
continue;
|
|
262
304
|
}
|
|
263
305
|
LOG.debug("streaming:showinfo", "Matched M3U device %s as PrismCast source (%d channels, %d%% overlap).", device.DeviceID, device.Channels.length, Math.round(overlapRatio * 100));
|
|
264
|
-
// Build guide number → channel ID map for this device and
|
|
306
|
+
// Build guide number → channel ID map for this device and extract logo URLs. Logo URLs are cached by station ID (resolved from the channel key via
|
|
307
|
+
// getChannelStationId) so that Pacific channels and provider variants all share the same logo entry.
|
|
265
308
|
const guideToChannelId = new Map();
|
|
309
|
+
const logos = new Map();
|
|
266
310
|
for (const channel of device.Channels) {
|
|
267
311
|
guideToChannelId.set(channel.GuideNumber, channel.ID);
|
|
268
|
-
// Cache the logo URL if available.
|
|
269
312
|
if (channel.Logo) {
|
|
270
|
-
const
|
|
271
|
-
if (
|
|
272
|
-
|
|
313
|
+
const stationId = getChannelStationId(channel.ID);
|
|
314
|
+
if (stationId) {
|
|
315
|
+
logos.set(stationId, normalizeLogoUrl(channel.Logo));
|
|
273
316
|
}
|
|
274
317
|
}
|
|
275
318
|
}
|
|
319
|
+
// Populate the logo cache with URLs from this device (tier 1).
|
|
320
|
+
if (logos.size > 0) {
|
|
321
|
+
setChannelLogos(logos);
|
|
322
|
+
}
|
|
276
323
|
mappings.set(device.DeviceID, guideToChannelId);
|
|
277
324
|
deviceIds.push(device.DeviceID);
|
|
278
325
|
totalChannels += device.Channels.length;
|
|
@@ -315,7 +362,7 @@ async function getGuideShowNames(host) {
|
|
|
315
362
|
* @param path - The API path (e.g., "/devices" or "/dvr/jobs").
|
|
316
363
|
* @returns Array of results, empty array on any error.
|
|
317
364
|
*/
|
|
318
|
-
async function fetchFromDvr(host, path) {
|
|
365
|
+
export async function fetchFromDvr(host, path) {
|
|
319
366
|
const url = "http://" + host + ":" + String(CHANNELS_DVR_PORT) + path;
|
|
320
367
|
try {
|
|
321
368
|
const controller = new AbortController();
|
|
@@ -341,20 +388,145 @@ async function fetchFromDvr(host, path) {
|
|
|
341
388
|
}
|
|
342
389
|
}
|
|
343
390
|
/**
|
|
344
|
-
*
|
|
345
|
-
|
|
346
|
-
|
|
391
|
+
* Loads the persisted DVR host from the config file. Called on startup so the pretune module can begin polling immediately.
|
|
392
|
+
*/
|
|
393
|
+
async function loadPersistedDvrHost() {
|
|
394
|
+
try {
|
|
395
|
+
const result = await loadUserConfig();
|
|
396
|
+
if (!result.parseError && result.config.dvrHost) {
|
|
397
|
+
lastKnownDvrHost = result.config.dvrHost;
|
|
398
|
+
LOG.debug("streaming:showinfo", "Loaded persisted DVR host: %s.", lastKnownDvrHost);
|
|
399
|
+
// Populate logos immediately from the persisted host so they're available on the first page load.
|
|
400
|
+
void populateChannelLogos();
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
// Ignore errors - the host will be discovered from the first stream's client address.
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Persists the DVR host to the config file so it survives restarts.
|
|
409
|
+
* @param host - The DVR server hostname or IP address.
|
|
410
|
+
*/
|
|
411
|
+
async function persistDvrHost(host) {
|
|
412
|
+
try {
|
|
413
|
+
const result = await loadUserConfig();
|
|
414
|
+
if (!result.parseError) {
|
|
415
|
+
result.config.dvrHost = host;
|
|
416
|
+
await saveUserConfig(result.config);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
catch (error) {
|
|
420
|
+
LOG.debug("streaming:showinfo", "Failed to persist DVR host: %s.", formatError(error));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
// Logo population.
|
|
424
|
+
/**
|
|
425
|
+
* Populates the channel logo cache in two tiers. Tier 1 fetches logo URLs from the DVR's /devices endpoint (covers all channels in the M3U playlist). Tier 2 runs
|
|
426
|
+
* TMS station name searches for any remaining channels with station IDs not covered by tier 1. Called on DVR host discovery (startup or first stream) and every 24
|
|
427
|
+
* hours to pick up network rebrands.
|
|
428
|
+
*/
|
|
429
|
+
async function populateChannelLogos() {
|
|
430
|
+
if (!lastKnownDvrHost) {
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
// Tier 1: fetch device data and extract logos. getDeviceMappings() handles the /devices fetch, device matching, and logo extraction into the cache as a side
|
|
434
|
+
// effect. The 5-minute mapping cache means we don't re-fetch if show name polling already called this recently.
|
|
435
|
+
await getDeviceMappings(lastKnownDvrHost);
|
|
436
|
+
// Tier 2: search TMS by channel name for channels with station IDs not covered by tier 1. This covers disabled channels, channels without an enabled provider,
|
|
437
|
+
// and any channels the DVR device didn't include logos for.
|
|
438
|
+
const listing = getChannelListing();
|
|
439
|
+
let cachedCount = 0;
|
|
440
|
+
let tier2Count = 0;
|
|
441
|
+
for (const entry of listing) {
|
|
442
|
+
// Skip channels that already have a logo in the cache (from tier 1 or a previous population cycle).
|
|
443
|
+
if (getChannelLogo(entry.key)) {
|
|
444
|
+
cachedCount++;
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
const stationId = getChannelStationId(entry.key);
|
|
448
|
+
if (!stationId) {
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
const channelName = entry.channel.name ?? entry.key;
|
|
452
|
+
// eslint-disable-next-line no-await-in-loop -- Intentional: sequential to avoid flooding the DVR's TMS proxy with concurrent requests.
|
|
453
|
+
const found = await searchTmsStationLogo(lastKnownDvrHost, channelName, stationId);
|
|
454
|
+
if (found) {
|
|
455
|
+
tier2Count++;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
LOG.debug("streaming:logos", "Logo population complete: %d cached, %d from TMS search, %d total.", cachedCount, tier2Count, cachedCount + tier2Count);
|
|
459
|
+
// Emit a channel-update SSE event with all resolved logos so any open channels tab can populate logo images without a page reload.
|
|
460
|
+
const logos = {};
|
|
461
|
+
for (const entry of listing) {
|
|
462
|
+
const logoUrl = getChannelLogo(entry.key);
|
|
463
|
+
if (logoUrl) {
|
|
464
|
+
logos[entry.key] = logoUrl;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
if (Object.keys(logos).length > 0) {
|
|
468
|
+
emitChannelUpdate({ logos });
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Searches the TMS stations endpoint for a channel's logo by name. If a result matches the target station ID, uses that logo. Otherwise uses the first result
|
|
473
|
+
* with a valid logo URL (same brand, different regional feed). Caches the result if found.
|
|
474
|
+
* @param host - The DVR server hostname or IP address.
|
|
475
|
+
* @param channelName - The channel display name to search for (e.g., "AMC", "Animal Planet").
|
|
476
|
+
* @param targetStationId - The Gracenote station ID to match against results.
|
|
477
|
+
* @returns True if a logo was found and cached, false otherwise.
|
|
478
|
+
*/
|
|
479
|
+
async function searchTmsStationLogo(host, channelName, targetStationId) {
|
|
480
|
+
const results = await fetchFromDvr(host, "/tms/stations/" + encodeURIComponent(channelName));
|
|
481
|
+
if (results.length === 0) {
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
// Prefer an exact station ID match. If none, use the first result with a valid logo URL (same brand, different regional variant).
|
|
485
|
+
let logoUrl;
|
|
486
|
+
for (const result of results) {
|
|
487
|
+
const uri = result.preferredImage?.uri;
|
|
488
|
+
if (!uri) {
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
if (result.stationId === targetStationId) {
|
|
492
|
+
logoUrl = uri;
|
|
493
|
+
break;
|
|
494
|
+
}
|
|
495
|
+
logoUrl ??= uri;
|
|
496
|
+
}
|
|
497
|
+
if (!logoUrl) {
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
setChannelLogo(targetStationId, normalizeLogoUrl(logoUrl));
|
|
501
|
+
LOG.debug("streaming:logos", "TMS search for '%s': found logo for station %s.", channelName, targetStationId);
|
|
502
|
+
return true;
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Triggers a single-channel logo lookup via TMS station name search. Called when a channel is added or edited with a station ID. Fire-and-forget - the logo
|
|
506
|
+
* appears on the next page load after the search completes.
|
|
507
|
+
* @param channelName - The channel display name to search for.
|
|
508
|
+
* @param stationId - The Gracenote station ID for the channel.
|
|
509
|
+
*/
|
|
510
|
+
export function updateChannelLogo(channelName, stationId) {
|
|
511
|
+
if (!lastKnownDvrHost) {
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
void searchTmsStationLogo(lastKnownDvrHost, channelName, stationId);
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Normalizes a logo URL by replacing query parameters with a height-only sizing parameter. The TMS CDN accepts ?h= for image height. This reduces bandwidth by
|
|
518
|
+
* requesting smaller images for UI rendering (48px height for retina) instead of the default 360x270 that the DVR API returns.
|
|
519
|
+
* @param url - The original logo URL from the DVR or TMS API.
|
|
520
|
+
* @returns The URL with query parameters replaced by the height sizing parameter.
|
|
347
521
|
*/
|
|
348
522
|
function normalizeLogoUrl(url) {
|
|
349
523
|
try {
|
|
350
524
|
const parsed = new URL(url);
|
|
351
|
-
// Strip existing query parameters and add our sizing.
|
|
352
525
|
parsed.search = "?h=" + String(LOGO_HEIGHT_PX);
|
|
353
526
|
return parsed.toString();
|
|
354
527
|
}
|
|
355
528
|
catch {
|
|
356
|
-
|
|
357
|
-
return undefined;
|
|
529
|
+
return url;
|
|
358
530
|
}
|
|
359
531
|
}
|
|
360
532
|
//# sourceMappingURL=showInfo.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"showInfo.js","sourceRoot":"","sources":["../../src/streaming/showInfo.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"showInfo.js","sourceRoot":"","sources":["../../src/streaming/showInfo.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { HealthEvent, HealthSnapshot } from "../config/health.js";
|
|
2
|
+
import type { Nullable, StreamingMode } from "../types/index.js";
|
|
2
3
|
import type { ClientTypeCount } from "./clients.js";
|
|
3
|
-
import type { Nullable } from "../types/index.js";
|
|
4
4
|
/**
|
|
5
5
|
* Health classification for a stream based on its current state.
|
|
6
6
|
*/
|
|
@@ -10,12 +10,14 @@ export type StreamHealthStatus = "buffering" | "error" | "healthy" | "recovering
|
|
|
10
10
|
*/
|
|
11
11
|
export interface StreamStatus {
|
|
12
12
|
bufferingDuration: Nullable<number>;
|
|
13
|
+
captureCodec: Nullable<string>;
|
|
13
14
|
channel: Nullable<string>;
|
|
14
15
|
clientCount: number;
|
|
15
16
|
clients: ClientTypeCount[];
|
|
16
17
|
currentTime: number;
|
|
17
18
|
duration: number;
|
|
18
19
|
escalationLevel: number;
|
|
20
|
+
hardwareAccelerated: boolean;
|
|
19
21
|
health: StreamHealthStatus;
|
|
20
22
|
id: number;
|
|
21
23
|
lastIssueTime: Nullable<number>;
|
|
@@ -23,6 +25,8 @@ export interface StreamStatus {
|
|
|
23
25
|
lastRecoveryTime: Nullable<number>;
|
|
24
26
|
logoUrl: string;
|
|
25
27
|
memoryBytes: number;
|
|
28
|
+
nativeBandwidth: number;
|
|
29
|
+
nativeResolution: Nullable<string>;
|
|
26
30
|
networkState: number;
|
|
27
31
|
pageReloadsInWindow: number;
|
|
28
32
|
providerName: string;
|
|
@@ -30,6 +34,7 @@ export interface StreamStatus {
|
|
|
30
34
|
recoveryAttempts: number;
|
|
31
35
|
showName: string;
|
|
32
36
|
startTime: string;
|
|
37
|
+
streamingMode: StreamingMode;
|
|
33
38
|
url: string;
|
|
34
39
|
}
|
|
35
40
|
/**
|
|
@@ -61,17 +66,20 @@ export interface StatusSnapshot {
|
|
|
61
66
|
/**
|
|
62
67
|
* Event types emitted by the status emitter.
|
|
63
68
|
*/
|
|
64
|
-
export type StatusEventType = "healthChanged" | "snapshot" | "streamAdded" | "streamHealthChanged" | "streamRemoved" | "systemStatusChanged";
|
|
69
|
+
export type StatusEventType = "channelUpdate" | "healthChanged" | "snapshot" | "streamAdded" | "streamHealthChanged" | "streamRemoved" | "systemStatusChanged";
|
|
65
70
|
/**
|
|
66
71
|
* Creates the initial StreamStatus object for a new stream. This provides a consistent starting state with all health metrics at their default values.
|
|
67
72
|
* @param options - The stream initialization options.
|
|
68
73
|
* @returns The initial stream status.
|
|
69
74
|
*/
|
|
70
75
|
export declare function createInitialStreamStatus(options: {
|
|
76
|
+
captureCodec?: Nullable<string>;
|
|
71
77
|
channelName: Nullable<string>;
|
|
78
|
+
hardwareAccelerated?: boolean;
|
|
72
79
|
numericStreamId: number;
|
|
73
80
|
providerName: string;
|
|
74
81
|
startTime: Date;
|
|
82
|
+
streamingMode?: StreamingMode;
|
|
75
83
|
url: string;
|
|
76
84
|
}): StreamStatus;
|
|
77
85
|
/**
|
|
@@ -85,9 +93,9 @@ export declare function emitStreamAdded(status: StreamStatus): void;
|
|
|
85
93
|
*/
|
|
86
94
|
export declare function emitStreamRemoved(streamId: number): void;
|
|
87
95
|
/**
|
|
88
|
-
* Emits a stream health changed event with the current stream status.
|
|
89
|
-
*
|
|
90
|
-
* while eliminating staleness during recovery/buffering periods.
|
|
96
|
+
* Emits a stream health changed event with the current stream status. Stores and emits the status to ensure SSE clients and snapshots have current data. Silently
|
|
97
|
+
* drops updates for streams that have already been removed by emitStreamRemoved() to prevent zombie entries. During healthy playback the monitor calls this every
|
|
98
|
+
* ~2 seconds anyway, so removing the previous selective filter has negligible bandwidth impact while eliminating staleness during recovery/buffering periods.
|
|
91
99
|
* @param status - The updated stream status.
|
|
92
100
|
*/
|
|
93
101
|
export declare function emitStreamHealthChanged(status: StreamStatus): void;
|
|
@@ -117,11 +125,17 @@ export declare function getStreamStatus(streamId: number): StreamStatus | undefi
|
|
|
117
125
|
* @param streamId - The ID of the stream to remove.
|
|
118
126
|
*/
|
|
119
127
|
export declare function removeStreamStatus(streamId: number): void;
|
|
128
|
+
/**
|
|
129
|
+
* Emits a channel table update event. The payload is a partial patch — any combination of rows, counts, scopeCounts, and logos. SSE clients that have the
|
|
130
|
+
* channels tab open apply the patch via applyChannelPatch. Used for server-initiated updates like logo population that have no associated client request.
|
|
131
|
+
* @param patch - The partial channel table patch to emit.
|
|
132
|
+
*/
|
|
133
|
+
export declare function emitChannelUpdate(patch: Record<string, unknown>): void;
|
|
120
134
|
/**
|
|
121
135
|
* Subscribes a callback to receive all status events. Returns an unsubscribe function.
|
|
122
136
|
* @param callback - Function to call when a status event is emitted.
|
|
123
137
|
* @returns A function to unsubscribe the callback.
|
|
124
138
|
*/
|
|
125
|
-
export declare function subscribeToStatus(callback: (event: StatusEventType, data: HealthEvent | StreamStatus | SystemStatus | StatusSnapshot | {
|
|
139
|
+
export declare function subscribeToStatus(callback: (event: StatusEventType, data: HealthEvent | Record<string, unknown> | StreamStatus | SystemStatus | StatusSnapshot | {
|
|
126
140
|
id: number;
|
|
127
141
|
}) => void): () => void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getHealthSnapshot, subscribeToHealth } from "../config/health.js";
|
|
2
|
-
import {
|
|
2
|
+
import { CONFIG } from "../config/index.js";
|
|
3
|
+
import { EventEmitter } from "node:events";
|
|
3
4
|
/* A singleton EventEmitter that broadcasts status updates to all subscribed SSE clients. The emitter maintains current state for all streams, allowing new clients
|
|
4
5
|
* to receive a snapshot of current status immediately upon connecting.
|
|
5
6
|
*/
|
|
@@ -14,12 +15,14 @@ statusEmitter.setMaxListeners(100);
|
|
|
14
15
|
export function createInitialStreamStatus(options) {
|
|
15
16
|
return {
|
|
16
17
|
bufferingDuration: null,
|
|
18
|
+
captureCodec: options.captureCodec ?? null,
|
|
17
19
|
channel: options.channelName,
|
|
18
20
|
clientCount: 0,
|
|
19
21
|
clients: [],
|
|
20
22
|
currentTime: 0,
|
|
21
23
|
duration: 0,
|
|
22
24
|
escalationLevel: 0,
|
|
25
|
+
hardwareAccelerated: options.hardwareAccelerated ?? false,
|
|
23
26
|
health: "healthy",
|
|
24
27
|
id: options.numericStreamId,
|
|
25
28
|
lastIssueTime: null,
|
|
@@ -27,6 +30,8 @@ export function createInitialStreamStatus(options) {
|
|
|
27
30
|
lastRecoveryTime: null,
|
|
28
31
|
logoUrl: "",
|
|
29
32
|
memoryBytes: 0,
|
|
33
|
+
nativeBandwidth: 0,
|
|
34
|
+
nativeResolution: null,
|
|
30
35
|
networkState: 0,
|
|
31
36
|
pageReloadsInWindow: 0,
|
|
32
37
|
providerName: options.providerName,
|
|
@@ -34,6 +39,7 @@ export function createInitialStreamStatus(options) {
|
|
|
34
39
|
recoveryAttempts: 0,
|
|
35
40
|
showName: "",
|
|
36
41
|
startTime: options.startTime.toISOString(),
|
|
42
|
+
streamingMode: options.streamingMode ?? "capture",
|
|
37
43
|
url: options.url
|
|
38
44
|
};
|
|
39
45
|
}
|
|
@@ -58,12 +64,17 @@ export function emitStreamRemoved(streamId) {
|
|
|
58
64
|
statusEmitter.emit("streamRemoved", { id: streamId });
|
|
59
65
|
}
|
|
60
66
|
/**
|
|
61
|
-
* Emits a stream health changed event with the current stream status.
|
|
62
|
-
*
|
|
63
|
-
* while eliminating staleness during recovery/buffering periods.
|
|
67
|
+
* Emits a stream health changed event with the current stream status. Stores and emits the status to ensure SSE clients and snapshots have current data. Silently
|
|
68
|
+
* drops updates for streams that have already been removed by emitStreamRemoved() to prevent zombie entries. During healthy playback the monitor calls this every
|
|
69
|
+
* ~2 seconds anyway, so removing the previous selective filter has negligible bandwidth impact while eliminating staleness during recovery/buffering periods.
|
|
64
70
|
* @param status - The updated stream status.
|
|
65
71
|
*/
|
|
66
72
|
export function emitStreamHealthChanged(status) {
|
|
73
|
+
// Defense-in-depth: do not re-add a stream that has already been removed by emitStreamRemoved(). This guards against any future code path that might attempt to
|
|
74
|
+
// update a terminated stream's status.
|
|
75
|
+
if (!streamStatuses.has(status.id)) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
67
78
|
streamStatuses.set(status.id, status);
|
|
68
79
|
statusEmitter.emit("streamHealthChanged", status);
|
|
69
80
|
}
|
|
@@ -72,9 +83,11 @@ export function emitStreamHealthChanged(status) {
|
|
|
72
83
|
* @param status - The updated system status.
|
|
73
84
|
*/
|
|
74
85
|
export function emitSystemStatusChanged(status) {
|
|
75
|
-
// Only emit if something meaningful changed.
|
|
86
|
+
// Only emit if something meaningful changed. The optional chain on the second condition is defensive — TypeScript narrows cachedSystemStatus as non-null after
|
|
87
|
+
// the first comparison, but at runtime the first condition can be truthy with cachedSystemStatus === null (undefined !== true).
|
|
76
88
|
if ((cachedSystemStatus?.browser.connected !== status.browser.connected) ||
|
|
77
|
-
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
90
|
+
(cachedSystemStatus?.streams.active !== status.streams.active)) {
|
|
78
91
|
cachedSystemStatus = status;
|
|
79
92
|
statusEmitter.emit("systemStatusChanged", status);
|
|
80
93
|
}
|
|
@@ -97,7 +110,7 @@ export function getStatusSnapshot() {
|
|
|
97
110
|
system: cachedSystemStatus ?? {
|
|
98
111
|
browser: { connected: false, pageCount: 0 },
|
|
99
112
|
memory: { heapUsed: 0, rss: 0 },
|
|
100
|
-
streams: { active: 0, limit:
|
|
113
|
+
streams: { active: 0, limit: CONFIG.streaming.maxConcurrentStreams },
|
|
101
114
|
uptime: 0
|
|
102
115
|
}
|
|
103
116
|
};
|
|
@@ -117,16 +130,26 @@ export function getStreamStatus(streamId) {
|
|
|
117
130
|
export function removeStreamStatus(streamId) {
|
|
118
131
|
streamStatuses.delete(streamId);
|
|
119
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Emits a channel table update event. The payload is a partial patch — any combination of rows, counts, scopeCounts, and logos. SSE clients that have the
|
|
135
|
+
* channels tab open apply the patch via applyChannelPatch. Used for server-initiated updates like logo population that have no associated client request.
|
|
136
|
+
* @param patch - The partial channel table patch to emit.
|
|
137
|
+
*/
|
|
138
|
+
export function emitChannelUpdate(patch) {
|
|
139
|
+
statusEmitter.emit("channelUpdate", patch);
|
|
140
|
+
}
|
|
120
141
|
/**
|
|
121
142
|
* Subscribes a callback to receive all status events. Returns an unsubscribe function.
|
|
122
143
|
* @param callback - Function to call when a status event is emitted.
|
|
123
144
|
* @returns A function to unsubscribe the callback.
|
|
124
145
|
*/
|
|
125
146
|
export function subscribeToStatus(callback) {
|
|
147
|
+
const channelUpdateHandler = (data) => { callback("channelUpdate", data); };
|
|
126
148
|
const streamAddedHandler = (data) => { callback("streamAdded", data); };
|
|
127
149
|
const streamRemovedHandler = (data) => { callback("streamRemoved", data); };
|
|
128
150
|
const streamHealthChangedHandler = (data) => { callback("streamHealthChanged", data); };
|
|
129
151
|
const systemStatusChangedHandler = (data) => { callback("systemStatusChanged", data); };
|
|
152
|
+
statusEmitter.on("channelUpdate", channelUpdateHandler);
|
|
130
153
|
statusEmitter.on("streamAdded", streamAddedHandler);
|
|
131
154
|
statusEmitter.on("streamRemoved", streamRemovedHandler);
|
|
132
155
|
statusEmitter.on("streamHealthChanged", streamHealthChangedHandler);
|
|
@@ -134,6 +157,7 @@ export function subscribeToStatus(callback) {
|
|
|
134
157
|
// Forward health events from the health emitter through the same SSE connection. This avoids a separate SSE endpoint for health updates.
|
|
135
158
|
const unsubscribeHealth = subscribeToHealth((event) => { callback("healthChanged", event); });
|
|
136
159
|
return () => {
|
|
160
|
+
statusEmitter.off("channelUpdate", channelUpdateHandler);
|
|
137
161
|
statusEmitter.off("streamAdded", streamAddedHandler);
|
|
138
162
|
statusEmitter.off("streamRemoved", streamRemovedHandler);
|
|
139
163
|
statusEmitter.off("streamHealthChanged", streamHealthChangedHandler);
|