import React, { useState, useEffect, useCallback } from 'react'; import SongTable from './SongTable'; import NowPlaying from './NowPlaying'; import AddSongPanel from './AddSongPanel'; import { API, getDisplayTitle, PlaylistItem } from '../api/player'; const App: React.FC = () => { const [isPlaying, setIsPlaying] = useState(false); const [nowPlayingSong, setNowPlayingSong] = useState(null); const [nowPlayingFileName, setNowPlayingFileName] = useState(null); const [volume, setVolume] = useState(100); const [volumeSettingIsLocked, setVolumeSettingIsLocked] = useState(false); const [songs, setSongs] = useState([]); const [ws, setWs] = useState(null); const fetchPlaylist = useCallback(async () => { const playlist = await API.getPlaylist(); setSongs(playlist); }, []); const fetchNowPlaying = useCallback(async () => { const nowPlaying = await API.getNowPlaying(); setNowPlayingSong(getDisplayTitle(nowPlaying.playingItem)); setNowPlayingFileName(nowPlaying.playingItem.filename); setIsPlaying(!nowPlaying.isPaused); if (!volumeSettingIsLocked) { setVolume(nowPlaying.volume); } }, [volumeSettingIsLocked]); const handleAddURL = async (url: string) => { const urlToAdd = url.trim(); if (urlToAdd) { await API.addToPlaylist(urlToAdd); fetchPlaylist(); if (!isPlaying) { await API.play(); } } }; const handleDelete = (index: number) => { setSongs(songs.filter((_, i) => i !== index)); API.removeFromPlaylist(index); fetchPlaylist(); fetchNowPlaying(); }; const handleSkipTo = async (index: number) => { const song = songs[index]; if (song.playing) { togglePlayPause(); } else { await API.skipTo(index); await API.play(); } fetchNowPlaying(); fetchPlaylist(); }; const togglePlayPause = async () => { if (isPlaying) { await API.pause(); } else { await API.play(); } fetchNowPlaying(); }; const handleSkip = async () => { await API.skip(); fetchNowPlaying(); }; const handlePrevious = async () => { await API.previous(); fetchNowPlaying(); }; const handleVolumeSettingChange = async (volume: number) => { setVolume(volume); await API.setVolume(volume); }; const handleWebSocketEvent = useCallback((event: any) => { switch (event.event) { case 'user_modify': case 'end-file': case 'playback-restart': case 'metadata_update': fetchPlaylist(); fetchNowPlaying(); break; } }, [fetchPlaylist, fetchNowPlaying]); // Initial data fetch useEffect(() => { fetchPlaylist(); fetchNowPlaying(); }, [fetchPlaylist, fetchNowPlaying]); // Update WebSocket connection useEffect(() => { const websocket = API.subscribeToEvents(handleWebSocketEvent); setWs(websocket); // Handle page visibility changes, so if the user navigates back to this tab, we reconnect the WebSocket const handleVisibilityChange = () => { if (document.visibilityState === 'visible' && (!ws || ws.readyState === WebSocket.CLOSED)) { const newWs = API.subscribeToEvents(handleWebSocketEvent); setWs(newWs); } }; document.addEventListener('visibilitychange', handleVisibilityChange); return () => { document.removeEventListener('visibilitychange', handleVisibilityChange); if (websocket) { websocket.close(); } }; }, [handleWebSocketEvent]); return (
setVolumeSettingIsLocked(true)} onVolumeDidChange={() => setVolumeSettingIsLocked(false)} /> {songs.length > 0 ? ( ) : (
Playlist is empty
)}
); }; export default App;