TRip changes/AudioPlayer hls setting tweaks
This commit is contained in:
@@ -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
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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">
|
||||||
|
Reference in New Issue
Block a user