TRip changes/AudioPlayer hls setting tweaks

This commit is contained in:
2025-08-11 15:52:38 -04:00
parent fe6a45bc1d
commit ccea5db9e9
3 changed files with 40 additions and 10 deletions

View File

@@ -84,8 +84,8 @@ export default function Player() {
const hls = new Hls({ const hls = new Hls({
lowLatencyMode: true, lowLatencyMode: true,
abrEnabled: false, abrEnabled: false,
liveSyncDuration: 3, // seconds behind live edge target liveSyncDuration: 2.5, // seconds behind live edge target
liveMaxLatencyDuration: 10, // max allowed latency before catchup liveMaxLatencyDuration: 3.5, // max allowed latency before catchup
liveCatchUpPlaybackRate: 1.05, // playback speed when catching up liveCatchUpPlaybackRate: 1.05, // playback speed when catching up
}); });

View File

@@ -38,6 +38,14 @@ export default function LoginPage() {
setLoading(true); setLoading(true);
try { 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(); const formData = new URLSearchParams();
formData.append("username", username); formData.append("username", username);
formData.append("password", password); formData.append("password", password);
@@ -113,7 +121,7 @@ export default function LoginPage() {
type="text" type="text"
id="username" id="username"
name="username" name="username"
autoComplete="username" autoComplete="off"
value={username} value={username}
onChange={(e) => setUsername(e.target.value)} onChange={(e) => setUsername(e.target.value)}
required required
@@ -134,7 +142,7 @@ export default function LoginPage() {
type="password" type="password"
id="password" id="password"
name="password" name="password"
autoComplete="current-password" autoComplete="off"
value={password} value={password}
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
required required

View File

@@ -19,6 +19,8 @@ export default function MediaRequestForm() {
const [artistSuggestions, setArtistSuggestions] = useState([]); const [artistSuggestions, setArtistSuggestions] = useState([]);
const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false);
const [isSearching, setIsSearching] = useState(false); const [isSearching, setIsSearching] = useState(false);
const [loadingAlbumId, setLoadingAlbumId] = useState(null);
const [expandedAlbums, setExpandedAlbums] = useState([]);
const debounceTimeout = useRef(null); const debounceTimeout = useRef(null);
const autoCompleteRef = useRef(null); const autoCompleteRef = useRef(null);
@@ -33,6 +35,13 @@ export default function MediaRequestForm() {
}; };
const Spinner = () => (
<span
className="inline-block ml-2 h-4 w-4 border-2 border-t-2 border-gray-300 border-t-blue-600 rounded-full animate-spin"
aria-label="Loading"
/>
);
// Fetch artist suggestions for autocomplete // Fetch artist suggestions for autocomplete
const searchArtists = (e) => { const searchArtists = (e) => {
const query = e.query.trim(); const query = e.query.trim();
@@ -114,6 +123,7 @@ export default function MediaRequestForm() {
setAlbums(data); setAlbums(data);
setTracksByAlbum({}); setTracksByAlbum({});
setExpandedAlbums([]);
// Set selectedTracks for all albums as null (means tracks loading/not loaded) // Set selectedTracks for all albums as null (means tracks loading/not loaded)
setSelectedTracks( setSelectedTracks(
@@ -197,16 +207,17 @@ export default function MediaRequestForm() {
let isCancelled = false; let isCancelled = false;
const albumsToFetch = albums.filter((a) => !tracksByAlbum[a.id]); const albumsToFetch = albums.filter((a) => !tracksByAlbum[a.id]);
if (albumsToFetch.length === 0) return; if (albumsToFetch.length === 0) return;
const fetchTracksSequentially = async () => { const fetchTracksSequentially = async () => {
for (const album of albumsToFetch) { for (const album of albumsToFetch) {
if (isCancelled) break; if (isCancelled) break;
setLoadingAlbumId(album.id);
try { try {
const res = await authFetch( const res = await authFetch(`${API_URL}/trip/get_tracks_by_album_id/${album.id}`);
`${API_URL}/trip/get_tracks_by_album_id/${album.id}`
);
if (!res.ok) throw new Error("API error"); if (!res.ok) throw new Error("API error");
const data = await res.json(); const data = await res.json();
@@ -223,6 +234,7 @@ export default function MediaRequestForm() {
setSelectedTracks((prev) => ({ ...prev, [album.id]: [] })); setSelectedTracks((prev) => ({ ...prev, [album.id]: [] }));
} }
} }
setLoadingAlbumId(null);
}; };
fetchTracksSequentially(); fetchTracksSequentially();
@@ -232,6 +244,7 @@ export default function MediaRequestForm() {
}; };
}, [albums, type]); }, [albums, type]);
// Toggle individual track checkbox // Toggle individual track checkbox
const toggleTrack = (albumId, trackId) => { const toggleTrack = (albumId, trackId) => {
setSelectedTracks((prev) => { setSelectedTracks((prev) => {
@@ -390,7 +403,12 @@ export default function MediaRequestForm() {
{type === "artist" && albums.length > 0 && ( {type === "artist" && albums.length > 0 && (
<> <>
<Accordion multiple className="mt-4"> <Accordion
multiple
className="mt-4"
activeIndex={expandedAlbums}
onTabChange={(e) => setExpandedAlbums(e.index)}
>
{albums.map(({ album, id, release_date }) => { {albums.map(({ album, id, release_date }) => {
const allTracks = tracksByAlbum[id] || []; const allTracks = tracksByAlbum[id] || [];
const selected = selectedTracks[id]; const selected = selectedTracks[id];
@@ -418,10 +436,14 @@ export default function MediaRequestForm() {
className="cursor-pointer" className="cursor-pointer"
aria-label={`Select all tracks for album ${album}`} aria-label={`Select all tracks for album ${album}`}
/> />
<span>{album}</span> <span className="flex items-center">
{album}
{loadingAlbumId === id && <Spinner />}
</span>
<small className="ml-2 text-neutral-500 dark:text-neutral-400">({release_date})</small> <small className="ml-2 text-neutral-500 dark:text-neutral-400">({release_date})</small>
</div> </div>
} }
> >
{allTracks.length > 0 ? ( {allTracks.length > 0 ? (
<ul className="text-sm"> <ul className="text-sm">