dev #6

Merged
codey merged 6 commits from dev into master 2026-02-27 10:43:39 -05:00
Showing only changes of commit 8263d582a6 - Show all commits

View File

@@ -140,7 +140,6 @@ export default function Player({ user }: PlayerProps) {
// Accept bare array or { options: [...] } // Accept bare array or { options: [...] }
setTypeaheadOptions(Array.isArray(data) ? data : data.options || []); setTypeaheadOptions(Array.isArray(data) ? data : data.options || []);
} catch (error) { } catch (error) {
console.error('Typeahead: error', error);
setTypeaheadOptions([]); setTypeaheadOptions([]);
} }
}; };
@@ -208,7 +207,6 @@ export default function Player({ user }: PlayerProps) {
const [liveDownloadRate, setLiveDownloadRate] = useState<number | null>(null); // Actual download speed const [liveDownloadRate, setLiveDownloadRate] = useState<number | null>(null); // Actual download speed
const [actualPlayingLevel, setActualPlayingLevel] = useState<number>(-1); // Actual HLS.js level being played const [actualPlayingLevel, setActualPlayingLevel] = useState<number>(-1); // Actual HLS.js level being played
// Basic mount diagnostics so we can see logs even if HLS never initializes
useEffect(() => { useEffect(() => {
return () => {}; return () => {};
}, []); }, []);
@@ -312,7 +310,6 @@ export default function Player({ user }: PlayerProps) {
if (!audioElement.current) return; if (!audioElement.current) return;
if (!Hls.isSupported()) { if (!Hls.isSupported()) {
console.error("HLS not supported");
return; return;
} }
@@ -420,12 +417,9 @@ export default function Player({ user }: PlayerProps) {
let networkRecoveryTimeout: ReturnType<typeof setTimeout> | null = null; let networkRecoveryTimeout: ReturnType<typeof setTimeout> | null = null;
hls.on(Hls.Events.ERROR, (_event, data) => { hls.on(Hls.Events.ERROR, (_event, data) => {
// Chromium sometimes stutters then fires a fatal error; recover aggressively
const details = data?.details || 'unknown'; const details = data?.details || 'unknown';
console.warn('[Radio] HLS error', data?.type, details, 'fatal:', data?.fatal);
if (!data.fatal) { if (!data.fatal) {
// Try to keep playback alive on buffer stalls
if (details === Hls.ErrorDetails.BUFFER_STALLED_ERROR) { if (details === Hls.ErrorDetails.BUFFER_STALLED_ERROR) {
try { hls.startLoad(); } catch (_) { /* ignore */ } try { hls.startLoad(); } catch (_) { /* ignore */ }
} }
@@ -434,7 +428,6 @@ export default function Player({ user }: PlayerProps) {
switch (data.type) { switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR: { case Hls.ErrorTypes.NETWORK_ERROR: {
console.warn('[Radio] network error, reinitializing stream');
hls.destroy(); hls.destroy();
hlsInstance.current = null; hlsInstance.current = null;
setIsPlaying(false); setIsPlaying(false);
@@ -443,11 +436,9 @@ export default function Player({ user }: PlayerProps) {
break; break;
} }
case Hls.ErrorTypes.MEDIA_ERROR: { case Hls.ErrorTypes.MEDIA_ERROR: {
console.warn('[Radio] media error, attempting recovery');
try { try {
hls.recoverMediaError(); hls.recoverMediaError();
} catch (err) { } catch (err) {
console.error('[Radio] media recovery failed, restarting', err);
hls.destroy(); hls.destroy();
hlsInstance.current = null; hlsInstance.current = null;
initializeStream(activeStationRef.current); initializeStream(activeStationRef.current);
@@ -455,7 +446,6 @@ export default function Player({ user }: PlayerProps) {
break; break;
} }
default: { default: {
console.error('[Radio] unrecoverable error, restarting');
hls.destroy(); hls.destroy();
hlsInstance.current = null; hlsInstance.current = null;
setIsPlaying(false); setIsPlaying(false);
@@ -536,7 +526,6 @@ export default function Player({ user }: PlayerProps) {
// Handle station changes: reset and start new stream // Handle station changes: reset and start new stream
useEffect(() => { useEffect(() => {
console.info('[Radio] station effect', activeStation);
// Batch all state resets to minimize re-renders // Batch all state resets to minimize re-renders
// Use startTransition to mark this as a non-urgent update // Use startTransition to mark this as a non-urgent update
const resetState = () => { const resetState = () => {
@@ -562,7 +551,6 @@ export default function Player({ user }: PlayerProps) {
resetState(); resetState();
// Defer stream initialization to next frame to keep UI responsive // Defer stream initialization to next frame to keep UI responsive
requestAnimationFrame(() => { requestAnimationFrame(() => {
console.info('[Radio] initializeStream from station effect', activeStation);
initializeStream(activeStation); initializeStream(activeStation);
}); });
}); });
@@ -694,7 +682,6 @@ export default function Player({ user }: PlayerProps) {
// Check if connection appears dead // Check if connection appears dead
if (ws.readyState !== WebSocket.OPEN || isStale) { if (ws.readyState !== WebSocket.OPEN || isStale) {
console.warn('WebSocket connection appears stale, reconnecting...');
// Force close and let onclose handle reconnection // Force close and let onclose handle reconnection
ws.close(); ws.close();
} }
@@ -730,7 +717,7 @@ export default function Player({ user }: PlayerProps) {
} }
// Ignore any other message types that don't contain track data // Ignore any other message types that don't contain track data
} catch (error) { } catch (error) {
console.error('Error parsing WebSocket message:', error); // ignore malformed messages
} }
}; };
@@ -753,9 +740,8 @@ export default function Player({ user }: PlayerProps) {
}, delay); }, delay);
}; };
ws.onerror = function (error) { ws.onerror = function () {
console.error('Radio WebSocket error:', error); // Let onclose handle reconnection
// Don't set error state here - let onclose handle reconnection
}; };
wsInstance.current = ws; wsInstance.current = ws;
@@ -876,7 +862,7 @@ export default function Player({ user }: PlayerProps) {
toast.error("Skip failed."); toast.error("Skip failed.");
} }
} catch (error) { } catch (error) {
console.error("Error skipping track:", error); // ignore errors
toast.error("Skip failed."); toast.error("Skip failed.");
} }
}; };
@@ -898,7 +884,7 @@ export default function Player({ user }: PlayerProps) {
toast.error("Reshuffle failed."); toast.error("Reshuffle failed.");
} }
} catch (error) { } catch (error) {
console.error("Error reshuffling queue:", error); // ignore errors
toast.error("Reshuffle failed."); toast.error("Reshuffle failed.");
} }
}; };
@@ -922,7 +908,7 @@ export default function Player({ user }: PlayerProps) {
toast.error("Queue shift failed."); toast.error("Queue shift failed.");
} }
} catch (error) { } catch (error) {
console.error("Error shifting queue:", error); // ignore errors
toast.error("Queue shift failed."); toast.error("Queue shift failed.");
} }
}; };
@@ -951,7 +937,7 @@ export default function Player({ user }: PlayerProps) {
toast.update(toastId, { render: "Play Now failed.", type: "error", autoClose: 3000 }); toast.update(toastId, { render: "Play Now failed.", type: "error", autoClose: 3000 });
} }
} catch (error) { } catch (error) {
console.error("Error playing song immediately:", error); // ignore errors
toast.update(toastId, { render: "Play Now failed.", type: "error", autoClose: 3000 }); toast.update(toastId, { render: "Play Now failed.", type: "error", autoClose: 3000 });
} }
}; };
@@ -980,7 +966,7 @@ export default function Player({ user }: PlayerProps) {
toast.update(toastId, { render: "Song request failed.", type: "error", autoClose: 3000 }); toast.update(toastId, { render: "Song request failed.", type: "error", autoClose: 3000 });
} }
} catch (error) { } catch (error) {
console.error("Error requesting song:", error); // ignore errors
toast.update(toastId, { render: "Song request failed.", type: "error", autoClose: 3000 }); toast.update(toastId, { render: "Song request failed.", type: "error", autoClose: 3000 });
} }
}; };
@@ -1004,7 +990,7 @@ export default function Player({ user }: PlayerProps) {
toast.error("Remove from queue failed."); toast.error("Remove from queue failed.");
} }
} catch (error) { } catch (error) {
console.error("Error removing from queue:", error); // ignore errors
toast.error("Remove from queue failed."); toast.error("Remove from queue failed.");
} }
}; };
@@ -1030,7 +1016,7 @@ export default function Player({ user }: PlayerProps) {
fetchQueue(); // Refresh to get correct state fetchQueue(); // Refresh to get correct state
} }
} catch (error) { } catch (error) {
console.error("Error reordering queue:", error); // ignore errors
toast.error("Reorder failed."); toast.error("Reorder failed.");
fetchQueue(); fetchQueue();
} }
@@ -1114,7 +1100,7 @@ export default function Player({ user }: PlayerProps) {
setNextTrack(null); setNextTrack(null);
} }
} catch (error) { } catch (error) {
console.error("Error fetching next track:", error); // ignore errors
setNextTrack(null); setNextTrack(null);
} }
}; };
@@ -1125,7 +1111,7 @@ export default function Player({ user }: PlayerProps) {
const actualRows = rows ?? queueRowsRef.current; const actualRows = rows ?? queueRowsRef.current;
const actualSearch = search ?? queueSearchRef.current; const actualSearch = search ?? queueSearchRef.current;
const start = actualPage * actualRows; const start = actualPage * actualRows;
// console.log("Fetching queue for station (ref):", activeStationRef.current); //
try { try {
const response = await authFetch(`${API_URL}/radio/get_queue`, { const response = await authFetch(`${API_URL}/radio/get_queue`, {
method: "POST", method: "POST",
@@ -1145,19 +1131,19 @@ export default function Player({ user }: PlayerProps) {
: data.recordsTotal ?? 0 : data.recordsTotal ?? 0
); );
} catch (error) { } catch (error) {
console.error("Error fetching queue:", error); // ignore errors
} }
}; };
useEffect(() => { useEffect(() => {
if (isQueueVisible) { if (isQueueVisible) {
// console.log("Fetching queue for station:", activeStation); //
fetchQueue(queuePage, queueRows, queueSearch); fetchQueue(queuePage, queueRows, queueSearch);
} }
}, [isQueueVisible, queuePage, queueRows, queueSearch, activeStation]); }, [isQueueVisible, queuePage, queueRows, queueSearch, activeStation]);
useEffect(() => { useEffect(() => {
// console.log("Active station changed to:", activeStation); //
if (isQueueVisible) { if (isQueueVisible) {
fetchQueue(queuePage, queueRows, queueSearch); fetchQueue(queuePage, queueRows, queueSearch);
} }
@@ -1174,7 +1160,7 @@ export default function Player({ user }: PlayerProps) {
useEffect(() => { useEffect(() => {
if (isQueueVisible) { if (isQueueVisible) {
// console.log("Track changed, refreshing queue for station:", activeStation); //
fetchQueue(queuePage, queueRows, queueSearch); fetchQueue(queuePage, queueRows, queueSearch);
} }
}, [currentTrackUuid]); }, [currentTrackUuid]);
@@ -1405,7 +1391,6 @@ export default function Player({ user }: PlayerProps) {
await audio.play(); await audio.play();
setIsPlaying(true); setIsPlaying(true);
} catch (err) { } catch (err) {
console.warn('Playback failed, reinitializing stream:', err);
// Reinitialize stream on playback failure // Reinitialize stream on playback failure
initializeStream(activeStation); initializeStream(activeStation);
} }