feat: implement auto-play functionality in AudioPlayer and update playTrack method in AudioPlayerContext
This commit is contained in:
0
app/api/test-navidrome/route.ts
Normal file
0
app/api/test-navidrome/route.ts
Normal file
@@ -84,8 +84,17 @@ export const AudioPlayer: React.FC = () => {
|
||||
localStorage.removeItem('navidrome-current-track-time');
|
||||
}
|
||||
|
||||
audioCurrent.play();
|
||||
setIsPlaying(true);
|
||||
// Auto-play only if the track has the autoPlay flag
|
||||
if (currentTrack.autoPlay) {
|
||||
audioCurrent.play().then(() => {
|
||||
setIsPlaying(true);
|
||||
}).catch((error) => {
|
||||
console.error('Failed to auto-play:', error);
|
||||
setIsPlaying(false);
|
||||
});
|
||||
} else {
|
||||
setIsPlaying(false);
|
||||
}
|
||||
}
|
||||
}, [currentTrack]);
|
||||
|
||||
@@ -121,11 +130,21 @@ export const AudioPlayer: React.FC = () => {
|
||||
lastSavedTime = audioCurrent.currentTime;
|
||||
}
|
||||
};
|
||||
|
||||
const handlePlay = () => {
|
||||
setIsPlaying(true);
|
||||
};
|
||||
|
||||
const handlePause = () => {
|
||||
setIsPlaying(false);
|
||||
};
|
||||
|
||||
if (audioCurrent) {
|
||||
audioCurrent.addEventListener('timeupdate', updateProgress);
|
||||
audioCurrent.addEventListener('ended', handleTrackEnd);
|
||||
audioCurrent.addEventListener('seeked', handleSeeked);
|
||||
audioCurrent.addEventListener('play', handlePlay);
|
||||
audioCurrent.addEventListener('pause', handlePause);
|
||||
}
|
||||
|
||||
return () => {
|
||||
@@ -133,6 +152,8 @@ export const AudioPlayer: React.FC = () => {
|
||||
audioCurrent.removeEventListener('timeupdate', updateProgress);
|
||||
audioCurrent.removeEventListener('ended', handleTrackEnd);
|
||||
audioCurrent.removeEventListener('seeked', handleSeeked);
|
||||
audioCurrent.removeEventListener('play', handlePlay);
|
||||
audioCurrent.removeEventListener('pause', handlePause);
|
||||
}
|
||||
};
|
||||
}, [playNextTrack, currentTrack]);
|
||||
@@ -213,10 +234,15 @@ export const AudioPlayer: React.FC = () => {
|
||||
if (audioCurrent) {
|
||||
if (isPlaying) {
|
||||
audioCurrent.pause();
|
||||
setIsPlaying(false);
|
||||
} else {
|
||||
audioCurrent.play();
|
||||
audioCurrent.play().then(() => {
|
||||
setIsPlaying(true);
|
||||
}).catch((error) => {
|
||||
console.error('Failed to play audio:', error);
|
||||
setIsPlaying(false);
|
||||
});
|
||||
}
|
||||
setIsPlaying(!isPlaying);
|
||||
}
|
||||
};
|
||||
const handleVolumeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
|
||||
@@ -15,11 +15,12 @@ interface Track {
|
||||
coverArt?: string;
|
||||
albumId: string;
|
||||
artistId: string;
|
||||
autoPlay?: boolean; // Flag to control auto-play
|
||||
}
|
||||
|
||||
interface AudioPlayerContextProps {
|
||||
currentTrack: Track | null;
|
||||
playTrack: (track: Track) => void;
|
||||
playTrack: (track: Track, autoPlay?: boolean) => void;
|
||||
queue: Track[];
|
||||
addToQueue: (track: Track) => void;
|
||||
playNextTrack: () => void;
|
||||
@@ -92,14 +93,17 @@ export const AudioPlayerProvider: React.FC<{ children: React.ReactNode }> = ({ c
|
||||
};
|
||||
}, [api]);
|
||||
|
||||
const playTrack = useCallback((track: Track) => {
|
||||
const playTrack = useCallback((track: Track, autoPlay: boolean = false) => {
|
||||
// Clear saved timestamp when manually playing a track
|
||||
localStorage.removeItem('navidrome-current-track-time');
|
||||
|
||||
if (currentTrack) {
|
||||
setPlayedTracks((prev) => [...prev, currentTrack]);
|
||||
}
|
||||
setCurrentTrack(track);
|
||||
|
||||
// Set autoPlay flag on the track
|
||||
const trackWithAutoPlay = { ...track, autoPlay };
|
||||
setCurrentTrack(trackWithAutoPlay);
|
||||
|
||||
// Scrobble the track
|
||||
api.scrobble(track.id).catch(error => {
|
||||
@@ -126,7 +130,7 @@ export const AudioPlayerProvider: React.FC<{ children: React.ReactNode }> = ({ c
|
||||
if (queue.length > 0) {
|
||||
const nextTrack = queue[0];
|
||||
setQueue((prevQueue) => prevQueue.slice(1));
|
||||
playTrack(nextTrack);
|
||||
playTrack(nextTrack, true); // Auto-play next track
|
||||
}
|
||||
}, [queue, playTrack]);
|
||||
|
||||
@@ -143,9 +147,9 @@ export const AudioPlayerProvider: React.FC<{ children: React.ReactNode }> = ({ c
|
||||
setQueue((prevQueue) => [currentTrack, ...prevQueue]);
|
||||
}
|
||||
|
||||
setCurrentTrack(previousTrack);
|
||||
playTrack(previousTrack, true); // Auto-play previous track
|
||||
}
|
||||
}, [playedTracks, currentTrack]);
|
||||
}, [playedTracks, currentTrack, playTrack]);
|
||||
|
||||
const addAlbumToQueue = useCallback(async (albumId: string) => {
|
||||
setIsLoading(true);
|
||||
|
||||
@@ -139,53 +139,35 @@ export const FullScreenPlayer: React.FC<FullScreenPlayerProps> = ({ isOpen, onCl
|
||||
|
||||
// Sync with main audio player (improved responsiveness)
|
||||
useEffect(() => {
|
||||
let lastUpdate = 0;
|
||||
const throttleMs = 100; // Update at most every 100ms for better responsiveness
|
||||
|
||||
const syncWithMainPlayer = () => {
|
||||
const now = Date.now();
|
||||
if (now - lastUpdate < throttleMs) return;
|
||||
lastUpdate = now;
|
||||
|
||||
const mainAudio = document.querySelector('audio') as HTMLAudioElement;
|
||||
if (mainAudio && currentTrack) {
|
||||
const newCurrentTime = mainAudio.currentTime;
|
||||
const newDuration = mainAudio.duration || 0;
|
||||
const newIsPlaying = !mainAudio.paused;
|
||||
|
||||
// Always update playing state for better responsiveness
|
||||
if (newIsPlaying !== isPlaying) {
|
||||
setIsPlaying(newIsPlaying);
|
||||
}
|
||||
// Always update playing state immediately
|
||||
setIsPlaying(newIsPlaying);
|
||||
setCurrentTime(newCurrentTime);
|
||||
setDuration(newDuration);
|
||||
setVolume(mainAudio.volume);
|
||||
|
||||
// Only update state if values have changed significantly
|
||||
if (Math.abs(newCurrentTime - currentTime) > 0.3) {
|
||||
setCurrentTime(newCurrentTime);
|
||||
}
|
||||
if (Math.abs(newDuration - duration) > 0.1) {
|
||||
setDuration(newDuration);
|
||||
}
|
||||
if (newDuration > 0) {
|
||||
const newProgress = (newCurrentTime / newDuration) * 100;
|
||||
if (Math.abs(newProgress - progress) > 0.1) {
|
||||
setProgress(newProgress);
|
||||
}
|
||||
}
|
||||
if (Math.abs(mainAudio.volume - volume) > 0.01) {
|
||||
setVolume(mainAudio.volume);
|
||||
setProgress(newProgress);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (isOpen) {
|
||||
if (isOpen && currentTrack) {
|
||||
// Initial sync
|
||||
syncWithMainPlayer();
|
||||
|
||||
// Set up interval to keep syncing - more frequent for better responsiveness
|
||||
const interval = setInterval(syncWithMainPlayer, 50);
|
||||
// Set up interval to keep syncing
|
||||
const interval = setInterval(syncWithMainPlayer, 100);
|
||||
return () => clearInterval(interval);
|
||||
}
|
||||
}, [isOpen, currentTrack]); // Removed other dependencies to prevent loop
|
||||
}, [isOpen, currentTrack?.id]); // React to track changes
|
||||
|
||||
// Extract dominant color from cover art
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user