()
| 97 | }; |
| 98 | |
| 99 | const StatsPage = () => { |
| 100 | const channelStats = useChannelsStore((s) => s.stats); |
| 101 | const setChannelStats = useChannelsStore((s) => s.setChannelStats); |
| 102 | const vodConnections = useChannelsStore((s) => s.activeVodConnections); |
| 103 | const setVodStats = useChannelsStore((s) => s.setVodStats); |
| 104 | const streamProfiles = useStreamProfilesStore((s) => s.profiles); |
| 105 | |
| 106 | const [clients, setClients] = useState([]); |
| 107 | const [channelHistory, setChannelHistory] = useState({}); |
| 108 | const [isPollingActive, setIsPollingActive] = useState(false); |
| 109 | const [currentPrograms, setCurrentPrograms] = useState({}); |
| 110 | const [channels, setChannels] = useState({}); // id -> channel |
| 111 | const [channelsByUUID, setChannelsByUUID] = useState({}); // uuid -> id |
| 112 | |
| 113 | // Compute needed channel UUIDs from the current active channels. |
| 114 | // Stream previews use a non-UUID hash as channel_id — filter those out. |
| 115 | const UUID_REGEX = |
| 116 | /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; |
| 117 | const neededUUIDs = useMemo( |
| 118 | () => Object.keys(channelHistory || {}).filter((id) => UUID_REGEX.test(id)), |
| 119 | [channelHistory] |
| 120 | ); |
| 121 | |
| 122 | // Keep a ref so the programs poller always has the latest valid UUIDs |
| 123 | const neededUUIDsRef = useRef(neededUUIDs); |
| 124 | useEffect(() => { |
| 125 | neededUUIDsRef.current = neededUUIDs; |
| 126 | }, [neededUUIDs]); |
| 127 | |
| 128 | // Fetch any missing channels by UUID when the needed set changes (for card name/logo) |
| 129 | useEffect(() => { |
| 130 | if (!neededUUIDs || neededUUIDs.length === 0) return; |
| 131 | const missing = neededUUIDs.filter((u) => channelsByUUID[u] === undefined); |
| 132 | if (missing.length === 0) return; |
| 133 | |
| 134 | let cancelled = false; |
| 135 | (async () => { |
| 136 | try { |
| 137 | const res = await API.getChannelsByUUIDs(missing); |
| 138 | if (cancelled) return; |
| 139 | if (Array.isArray(res)) { |
| 140 | setChannels((prev) => { |
| 141 | const next = { ...prev }; |
| 142 | for (const ch of res) next[ch.id] = ch; |
| 143 | return next; |
| 144 | }); |
| 145 | setChannelsByUUID((prev) => { |
| 146 | const next = { ...prev }; |
| 147 | for (const ch of res) next[ch.uuid] = ch.id; |
| 148 | return next; |
| 149 | }); |
| 150 | } |
| 151 | } catch (e) { |
| 152 | console.error('Failed to fetch channels by UUIDs', e); |
| 153 | } |
| 154 | })(); |
| 155 | return () => { |
| 156 | cancelled = true; |
nothing calls this directly
no test coverage detected