import React, { useState, ChangeEvent, useEffect } from 'react'; import { Upload, Music, FileText, Image as ImageIcon, X, Link, ListMusic } from 'lucide-react'; import { TrackData } from '../types'; import { parseLrc, fetchPlaylist } from '../utils/parsers'; interface UploadOverlayProps { isOpen: boolean; onClose: () => void; onTrackLoaded: (track: TrackData) => void; onPlaylistLoaded: (playlist: TrackData[]) => void; currentPlaylistUrl: string; } const UploadOverlay: React.FC = ({ isOpen, onClose, onTrackLoaded, onPlaylistLoaded, currentPlaylistUrl }) => { // Playlist State const [playlistUrl, setPlaylistUrl] = useState(currentPlaylistUrl); const [playlistLoading, setPlaylistLoading] = useState(false); // Local Upload State const [audioFile, setAudioFile] = useState(null); const [coverFile, setCoverFile] = useState(null); const [lrcFile, setLrcFile] = useState(null); const [title, setTitle] = useState('Unknown Track'); const [artist, setArtist] = useState('Unknown Artist'); const [localLoading, setLocalLoading] = useState(false); // Tab state const [activeTab, setActiveTab] = useState<'playlist' | 'local'>('playlist'); useEffect(() => { setPlaylistUrl(currentPlaylistUrl); }, [currentPlaylistUrl]); if (!isOpen) return null; const handleFileChange = (e: ChangeEvent, setter: (f: File | null) => void) => { if (e.target.files && e.target.files[0]) { const file = e.target.files[0]; setter(file); // Auto-parse filename if it's the audio file if (setter === setAudioFile) { // Remove extension const filename = file.name.replace(/\.[^/.]+$/, ""); // Try parsing "Artist - Title" format const parts = filename.split(' - '); if (parts.length >= 2) { setArtist(parts[1].trim()); setTitle(parts.slice(0).join(' - ').trim()); } else { setArtist("Unknown Artist"); setTitle(filename); } } } }; const handleLoadPlaylist = async () => { if (!playlistUrl) return; setPlaylistLoading(true); try { const tracks = await fetchPlaylist(playlistUrl); if (tracks.length > 0) { onPlaylistLoaded(tracks); onClose(); } else { alert("No tracks found in playlist or invalid format."); } } catch (e) { alert("Failed to load playlist."); } finally { setPlaylistLoading(false); } }; const handleLocalLoad = async () => { if (!audioFile) return; setLocalLoading(true); try { const audioUrl = URL.createObjectURL(audioFile); const coverUrl = coverFile ? URL.createObjectURL(coverFile) : 'https://picsum.photos/400/400'; // Fallback let lyrics: any[] = []; if (lrcFile) { const text = await lrcFile.text(); lyrics = parseLrc(text); } const track: TrackData = { title: title || audioFile.name.replace(/\.[^/.]+$/, ""), artist: artist || "Unknown Artist", audioUrl, coverUrl, lyrics }; onTrackLoaded(track); onClose(); } catch (error) { console.error("Error loading track", error); } finally { setLocalLoading(false); } }; return (

Library & Source

{/* Tabs */}
{activeTab === 'playlist' && (
setPlaylistUrl(e.target.value)} className="w-full bg-neutral-800 border border-neutral-700 rounded-lg pl-9 pr-3 py-2.5 text-sm text-white focus:outline-none focus:border-amber-500" placeholder="https://example.com/playlist.json" />

Supported format: JSON array with Title, Artist, Audio, Cover, Lyrics fields.

)} {activeTab === 'local' && (
{/* Metadata Inputs */}
setTitle(e.target.value)} className="w-full bg-neutral-800 border border-neutral-700 rounded px-3 py-2 text-sm text-white focus:outline-none focus:border-amber-500" placeholder="Song Title" />
setArtist(e.target.value)} className="w-full bg-neutral-800 border border-neutral-700 rounded px-3 py-2 text-sm text-white focus:outline-none focus:border-amber-500" placeholder="Artist Name" />
{/* File Inputs */}
{audioFile ? audioFile.name : 'Select Audio (MP3/WAV)'}
handleFileChange(e, setAudioFile)} />
{coverFile ? coverFile.name : 'Select Cover (Img)'}
handleFileChange(e, setCoverFile)} />
{lrcFile ? lrcFile.name : 'Select Lyrics (.lrc)'}
handleFileChange(e, setLrcFile)} />
)}
); }; export default UploadOverlay;