import React, { useState, useEffect, useCallback } from 'react'; import SongTable from './SongTable'; import NowPlaying from './NowPlaying'; import AddSongPanel from './AddSongPanel'; import { TabView, Tab } from './TabView'; import { API, getDisplayTitle, PlaylistItem } from '../api/player'; import { useEventWebSocket } from '../hooks/useEventWebsocket'; import { FaMusic, FaHeart } from 'react-icons/fa'; enum Tabs { Playlist = "playlist", Favorites = "favorites", } const EmptyContent: React.FC<{ label: string}> = ({label}) => (
{label}
); interface SonglistContentProps { songs: PlaylistItem[]; isPlaying: boolean; onNeedsRefresh: () => void; } const PlaylistContent: React.FC = ({ songs, isPlaying, onNeedsRefresh }) => { const handleDelete = (index: number) => { API.removeFromPlaylist(index); onNeedsRefresh(); }; const handleSkipTo = (index: number) => { API.skipTo(index); onNeedsRefresh(); }; return ( songs.length > 0 ? ( ) : ( ) ); }; const FavoritesContent: React.FC = ({ songs, isPlaying, onNeedsRefresh }) => { const handleDelete = (index: number) => { API.removeFromFavorites(index); onNeedsRefresh(); }; const handleSkipTo = (index: number) => { API.replaceCurrentFile(songs[index].filename); API.play(); onNeedsRefresh(); }; return ( songs.length > 0 ? ( ) : ( ) ); }; 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 [playlist, setPlaylist] = useState([]); const [favorites, setFavorites] = useState([]); const [selectedTab, setSelectedTab] = useState(Tabs.Playlist); const fetchPlaylist = useCallback(async () => { const playlist = await API.getPlaylist(); setPlaylist(playlist); }, []); const fetchFavorites = useCallback(async () => { const favorites = await API.getFavorites(); setFavorites(favorites); }, []); 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) { if (selectedTab === Tabs.Favorites) { await API.addToFavorites(urlToAdd); fetchFavorites(); } else { await API.addToPlaylist(urlToAdd); fetchPlaylist(); } if (!isPlaying) { await API.play(); } } }; 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; case 'favorites_update': fetchFavorites(); break; } }, [fetchPlaylist, fetchNowPlaying, fetchFavorites]); // Use the hook useEventWebSocket(handleWebSocketEvent); // Handle visibility changes useEffect(() => { const handleVisibilityChange = () => { if (document.visibilityState === 'visible') { fetchPlaylist(); fetchNowPlaying(); } }; document.addEventListener('visibilitychange', handleVisibilityChange); return () => { document.removeEventListener('visibilitychange', handleVisibilityChange); }; }, [fetchPlaylist, fetchNowPlaying]); const refreshContent = () => { fetchPlaylist(); fetchNowPlaying(); fetchFavorites(); } // Initial data fetch useEffect(() => { fetchPlaylist(); fetchNowPlaying(); fetchFavorites(); }, [fetchPlaylist, fetchNowPlaying, fetchFavorites]); return (
setVolumeSettingIsLocked(true)} onVolumeDidChange={() => setVolumeSettingIsLocked(false)} /> }> }> ({ ...f, playing: f.filename === nowPlayingFileName }))} isPlaying={isPlaying} onNeedsRefresh={refreshContent} />
); }; export default App;