Enhance authentication flow with improved error handling and logging in requireAuthHook. Refine HLS stream initialization and metadata fetching in AudioPlayer to handle station changes gracefully. Improve toast notifications and autocomplete behavior in LyricSearch. Simplify RandomMsg logic and remove unused imports. Add track and album count display in MediaRequestForm and enhance artist selection. Introduce dark mode styles for tables and dialogs in RequestManagement.css. Adjust imports and ensure proper usage of requireAuthHook in index.astro and requests.astro.

This commit is contained in:
2025-09-22 11:15:24 -04:00
parent 3afc944a67
commit f177315231
8 changed files with 273 additions and 54 deletions

View File

@@ -34,6 +34,7 @@ export default function Player({ user }) {
const currentTrackUuid = useRef(null);
const baseTrackElapsed = useRef(0);
const lastUpdateTimestamp = useRef(Date.now());
const activeStationRef = useRef(activeStation);
const formatTime = (seconds) => {
const mins = String(Math.floor(seconds / 60)).padStart(2, "0");
@@ -85,9 +86,14 @@ export default function Player({ user }) {
const hls = new Hls({
lowLatencyMode: true,
abrEnabled: false,
liveSyncDuration: 1.0, // seconds behind live edge target
liveMaxLatencyDuration: 2.0, // max allowed latency before catchup
liveCatchUpPlaybackRate: 1.05, // playback speed when catching up
liveSyncDuration: 0.5, // seconds behind live edge target
liveMaxLatencyDuration: 3.0, // max allowed latency before catchup
liveCatchUpPlaybackRate: 1.02,
maxBufferLength: 30,
maxMaxBufferLength: 60,
maxBufferHole: 0.5,
manifestLoadingTimeOut: 4000,
fragLoadingTimeOut: 10000, // playback speed when catching up
});
hlsInstance.current = hls;
@@ -176,10 +182,15 @@ export default function Player({ user }) {
// Fetch metadata and lyrics periodically
useEffect(() => {
const fetchMetadataAndLyrics = async () => {
// capture the station id at request time; ignore results if station changed
const requestStation = activeStationRef.current;
try {
const response = await fetch(`${API_URL}/radio/np?station=${activeStation}`, { method: 'POST' });
const response = await fetch(`${API_URL}/radio/np?station=${requestStation}`, { method: 'POST' });
const trackData = await response.json();
// If station changed while request was in-flight, ignore the response
if (requestStation !== activeStationRef.current) return;
if (trackData.artist === 'N/A') {
setTrackTitle('Offline');
setLyrics([]);
@@ -193,7 +204,7 @@ export default function Player({ user }) {
setTrackArtist(trackData.artist);
setTrackGenre(trackData.genre || '');
setTrackAlbum(trackData.album);
setCoverArt(`${API_URL}/radio/album_art?station=${activeStation}&_=${Date.now()}`);
setCoverArt(`${API_URL}/radio/album_art?station=${requestStation}&_=${Date.now()}`);
baseTrackElapsed.current = trackData.elapsed;
lastUpdateTimestamp.current = Date.now();
@@ -205,7 +216,7 @@ export default function Player({ user }) {
setCurrentLyricIndex(0);
setPageTitle(trackData.artist, trackData.song);
// Fetch lyrics as before
// Fetch lyrics as before, but guard against station switches
const lyricsResponse = await fetch(`${API_URL}/lyric/search`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
@@ -219,6 +230,7 @@ export default function Player({ user }) {
}),
});
const lyricsData = await lyricsResponse.json();
if (requestStation !== activeStationRef.current) return;
if (!lyricsData.err && Array.isArray(lyricsData.lrc)) {
const parsedLyrics = lyricsData.lrc.map(({ timeTag, words }) => {
const [mins, rest] = timeTag.split(':');
@@ -238,6 +250,8 @@ export default function Player({ user }) {
setLyrics([]);
}
};
// ensure the ref points to the current activeStation for in-flight guards
activeStationRef.current = activeStation;
fetchMetadataAndLyrics();
const metadataInterval = setInterval(fetchMetadataAndLyrics, 700);
return () => clearInterval(metadataInterval);
@@ -272,7 +286,7 @@ export default function Player({ user }) {
))}
</div>
<div className="c-containter">
{user ? <span>Hello, {user.user}</span> : <span>Not logged in</span>}
{user && <span>Hello, {user.user}</span>}
< div className="music-container mt-8">
<section className="album-cover">
<div className="music-player__album" title="Album">