'use client'; import React, { useEffect, useState } from 'react'; import Image from 'next/image'; import { useNavidrome } from '@/app/components/NavidromeContext'; import { useAudioPlayer } from '@/app/components/AudioPlayerContext'; import { Song } from '@/lib/navidrome'; import { Button } from '@/components/ui/button'; import { Separator } from '@/components/ui/separator'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Search, Play, Plus, Clock, User, Disc } from 'lucide-react'; import Loading from '@/app/components/loading'; import { getNavidromeAPI } from '@/lib/navidrome'; type SortOption = 'title' | 'artist' | 'album' | 'year' | 'duration' | 'track'; type SortDirection = 'asc' | 'desc'; export default function SongsPage() { const { getAllSongs } = useNavidrome(); const { playTrack, addToQueue, currentTrack } = useAudioPlayer(); const [songs, setSongs] = useState([]); const [filteredSongs, setFilteredSongs] = useState([]); const [loading, setLoading] = useState(true); const [searchQuery, setSearchQuery] = useState(''); const [sortBy, setSortBy] = useState('title'); const [sortDirection, setSortDirection] = useState('asc'); const api = getNavidromeAPI(); useEffect(() => { const fetchSongs = async () => { setLoading(true); try { const allSongs = await getAllSongs(); setSongs(allSongs); setFilteredSongs(allSongs); } catch (error) { console.error('Failed to fetch songs:', error); } setLoading(false); }; fetchSongs(); }, [getAllSongs]); useEffect(() => { let filtered = songs; // Apply search filter if (searchQuery.trim()) { const query = searchQuery.toLowerCase(); filtered = songs.filter(song => song.title.toLowerCase().includes(query) || song.artist.toLowerCase().includes(query) || song.album.toLowerCase().includes(query) ); } // Apply sorting filtered = [...filtered].sort((a, b) => { let aValue: string | number; let bValue: string | number; switch (sortBy) { case 'title': aValue = a.title.toLowerCase(); bValue = b.title.toLowerCase(); break; case 'artist': aValue = a.artist.toLowerCase(); bValue = b.artist.toLowerCase(); break; case 'album': aValue = a.album.toLowerCase(); bValue = b.album.toLowerCase(); break; case 'year': aValue = a.year || 0; bValue = b.year || 0; break; case 'duration': aValue = a.duration; bValue = b.duration; break; case 'track': aValue = a.track || 0; bValue = b.track || 0; break; default: aValue = a.title.toLowerCase(); bValue = b.title.toLowerCase(); } if (sortDirection === 'asc') { return aValue < bValue ? -1 : aValue > bValue ? 1 : 0; } else { return aValue > bValue ? -1 : aValue < bValue ? 1 : 0; } }); setFilteredSongs(filtered); }, [songs, searchQuery, sortBy, sortDirection]); const handlePlaySong = (song: Song) => { const track = { id: song.id, name: song.title, url: api.getStreamUrl(song.id), artist: song.artist, album: song.album, duration: song.duration, coverArt: song.coverArt ? api.getCoverArtUrl(song.coverArt, 300) : undefined, albumId: song.albumId, artistId: song.artistId }; playTrack(track); }; const handleAddToQueue = (song: Song) => { const track = { id: song.id, name: song.title, url: api.getStreamUrl(song.id), artist: song.artist, album: song.album, duration: song.duration, coverArt: song.coverArt ? api.getCoverArtUrl(song.coverArt, 300) : undefined, albumId: song.albumId, artistId: song.artistId }; addToQueue(track); }; const formatDuration = (seconds: number): string => { const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`; }; const isCurrentlyPlaying = (song: Song): boolean => { return currentTrack?.id === song.id; }; if (loading) { return ; } return (
{/* Header */}

Songs

{filteredSongs.length} of {songs.length} songs

{/* Search and Filters */}
setSearchQuery(e.target.value)} className="pl-10" />
{/* Songs List */} {filteredSongs.length === 0 ? (

{searchQuery ? 'No songs found matching your search.' : 'No songs available.'}

) : (
{filteredSongs.map((song, index) => (
handlePlaySong(song)} > {/* Track Number / Play Indicator */}
{isCurrentlyPlaying(song) ? (
) : ( {index + 1} )}
{/* Album Art */}
{song.album}
{/* Song Info */}

{song.title}

{song.year && ( {song.year} )}
{song.artist}
{song.album}
{/* Duration */}
{formatDuration(song.duration)}
{/* Actions */}
))}
)}
); }