diff --git a/src/components/AudioPlayer.jsx b/src/components/AudioPlayer.jsx
index fe78c50..54541f7 100644
--- a/src/components/AudioPlayer.jsx
+++ b/src/components/AudioPlayer.jsx
@@ -84,8 +84,8 @@ export default function Player() {
const hls = new Hls({
lowLatencyMode: true,
abrEnabled: false,
- liveSyncDuration: 3, // seconds behind live edge target
- liveMaxLatencyDuration: 10, // max allowed latency before catchup
+ liveSyncDuration: 2.5, // seconds behind live edge target
+ liveMaxLatencyDuration: 3.5, // max allowed latency before catchup
liveCatchUpPlaybackRate: 1.05, // playback speed when catching up
});
diff --git a/src/components/Login.jsx b/src/components/Login.jsx
index ed605e9..8815f19 100644
--- a/src/components/Login.jsx
+++ b/src/components/Login.jsx
@@ -38,6 +38,14 @@ export default function LoginPage() {
setLoading(true);
try {
+ if (!username) {
+ setLoading(false);
+ return toast.error("Username is required");
+ }
+ if (!password) {
+ setLoading(false);
+ return toast.error("Password is required");
+ }
const formData = new URLSearchParams();
formData.append("username", username);
formData.append("password", password);
@@ -113,7 +121,7 @@ export default function LoginPage() {
type="text"
id="username"
name="username"
- autoComplete="username"
+ autoComplete="off"
value={username}
onChange={(e) => setUsername(e.target.value)}
required
@@ -134,7 +142,7 @@ export default function LoginPage() {
type="password"
id="password"
name="password"
- autoComplete="current-password"
+ autoComplete="off"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
diff --git a/src/components/TRip/MediaRequestForm.jsx b/src/components/TRip/MediaRequestForm.jsx
index 291638a..d24ea33 100644
--- a/src/components/TRip/MediaRequestForm.jsx
+++ b/src/components/TRip/MediaRequestForm.jsx
@@ -19,6 +19,8 @@ export default function MediaRequestForm() {
const [artistSuggestions, setArtistSuggestions] = useState([]);
const [isSubmitting, setIsSubmitting] = useState(false);
const [isSearching, setIsSearching] = useState(false);
+ const [loadingAlbumId, setLoadingAlbumId] = useState(null);
+ const [expandedAlbums, setExpandedAlbums] = useState([]);
const debounceTimeout = useRef(null);
const autoCompleteRef = useRef(null);
@@ -33,6 +35,13 @@ export default function MediaRequestForm() {
};
+ const Spinner = () => (
+
+ );
+
// Fetch artist suggestions for autocomplete
const searchArtists = (e) => {
const query = e.query.trim();
@@ -114,6 +123,7 @@ export default function MediaRequestForm() {
setAlbums(data);
setTracksByAlbum({});
+ setExpandedAlbums([]);
// Set selectedTracks for all albums as null (means tracks loading/not loaded)
setSelectedTracks(
@@ -197,16 +207,17 @@ export default function MediaRequestForm() {
let isCancelled = false;
const albumsToFetch = albums.filter((a) => !tracksByAlbum[a.id]);
+
if (albumsToFetch.length === 0) return;
const fetchTracksSequentially = async () => {
for (const album of albumsToFetch) {
if (isCancelled) break;
+ setLoadingAlbumId(album.id);
+
try {
- const res = await authFetch(
- `${API_URL}/trip/get_tracks_by_album_id/${album.id}`
- );
+ const res = await authFetch(`${API_URL}/trip/get_tracks_by_album_id/${album.id}`);
if (!res.ok) throw new Error("API error");
const data = await res.json();
@@ -223,6 +234,7 @@ export default function MediaRequestForm() {
setSelectedTracks((prev) => ({ ...prev, [album.id]: [] }));
}
}
+ setLoadingAlbumId(null);
};
fetchTracksSequentially();
@@ -232,6 +244,7 @@ export default function MediaRequestForm() {
};
}, [albums, type]);
+
// Toggle individual track checkbox
const toggleTrack = (albumId, trackId) => {
setSelectedTracks((prev) => {
@@ -390,7 +403,12 @@ export default function MediaRequestForm() {
{type === "artist" && albums.length > 0 && (
<>
-
+ setExpandedAlbums(e.index)}
+ >
{albums.map(({ album, id, release_date }) => {
const allTracks = tracksByAlbum[id] || [];
const selected = selectedTracks[id];
@@ -418,10 +436,14 @@ export default function MediaRequestForm() {
className="cursor-pointer"
aria-label={`Select all tracks for album ${album}`}
/>
- {album}
+
+ {album}
+ {loadingAlbumId === id && }
+
({release_date})
}
+
>
{allTracks.length > 0 ? (
@@ -478,6 +500,6 @@ export default function MediaRequestForm() {
>
)}
-
+
);
}