diff --git a/.env b/.env new file mode 100644 index 0000000..1f4e47a --- /dev/null +++ b/.env @@ -0,0 +1 @@ +VITE_DEFAULT_PLAYLIST_URL=http://t91rqdjhx.hn-bkt.clouddn.com/playlist.json \ No newline at end of file diff --git a/.gemini-clipboard/clipboard-1768725784576.png b/.gemini-clipboard/clipboard-1768725784576.png new file mode 100644 index 0000000..f3480b9 Binary files /dev/null and b/.gemini-clipboard/clipboard-1768725784576.png differ diff --git a/.gemini-clipboard/clipboard-1768726005656.png b/.gemini-clipboard/clipboard-1768726005656.png new file mode 100644 index 0000000..9eddeb1 Binary files /dev/null and b/.gemini-clipboard/clipboard-1768726005656.png differ diff --git a/App.tsx b/App.tsx index 6ac5fc8..67a0658 100644 --- a/App.tsx +++ b/App.tsx @@ -9,13 +9,13 @@ import { Disc } from 'lucide-react'; // Use HTTP. The bucket likely does not support HTTPS. // The proxy in utils/parsers.ts will handle the fetching securely. -const DEFAULT_PLAYLIST_URL = "http://t91rqdjhx.hn-bkt.clouddn.com/playlist.json"; +const DEFAULT_PLAYLIST_URL = import.meta.env.VITE_DEFAULT_PLAYLIST_URL || ""; // Placeholder track while loading const INITIAL_TRACK: TrackData = { title: "Waiting for vinyl...", artist: "Vinyl Vibes", - coverUrl: "https://images.unsplash.com/photo-1605559911160-a60e5a88948c?q=80&w=1000&auto=format&fit=crop", + coverUrl: "", audioUrl: "", lyrics: [] }; @@ -33,6 +33,7 @@ const App: React.FC = () => { const [currentIndex, setCurrentIndex] = useState(0); const [playbackMode, setPlaybackMode] = useState('SEQUENCE'); const [playlistUrl, setPlaylistUrl] = useState(DEFAULT_PLAYLIST_URL); + const [isSingleMode, setIsSingleMode] = useState(false); // UI State const [isUploadOpen, setIsUploadOpen] = useState(false); @@ -43,7 +44,22 @@ const App: React.FC = () => { const tracks = await fetchPlaylist(DEFAULT_PLAYLIST_URL); if (tracks.length > 0) { setPlaylist(tracks); - setCurrentIndex(0); + + // Check for deep link track index + const params = new URLSearchParams(window.location.search); + const trackIndexParam = params.get('track'); + let initialIndex = 0; + + if (trackIndexParam) { + const parsedIndex = parseInt(trackIndexParam, 10); + // Validate index is within bounds (User provides 1-based index) + if (!isNaN(parsedIndex) && parsedIndex >= 1 && parsedIndex <= tracks.length) { + initialIndex = parsedIndex - 1; // Convert to 0-based + setIsSingleMode(true); + } + } + + setCurrentIndex(initialIndex); } }; init(); @@ -123,7 +139,7 @@ const App: React.FC = () => { }; const playNext = () => { - if (playlist.length <= 1) return; + if (isSingleMode || playlist.length <= 1) return; let nextIndex = 0; if (playbackMode === 'SHUFFLE') { @@ -138,14 +154,18 @@ const App: React.FC = () => { }; const playPrev = () => { - if (playlist.length <= 1) return; + if (isSingleMode || playlist.length <= 1) return; let prevIndex = currentIndex - 1; if (prevIndex < 0) prevIndex = playlist.length - 1; setCurrentIndex(prevIndex); }; const handleTrackEnded = () => { - playNext(); + if (isSingleMode) { + setIsPlaying(false); + } else { + playNext(); + } }; const handleAudioError = (e: any) => { @@ -189,16 +209,33 @@ const App: React.FC = () => { Vinyl Vibes - + {/* Right/Bottom: Lyrics Area */} -
- +
+ {/* Internal Background Image */} + {(currentTrack.coverUrl || INITIAL_TRACK.coverUrl) && ( + Background + )} + {/* Lighter overlay to let more color through */} +
- {/* Gradient masks for lyrics fade effect */} -
-
+
+ +
+ + {/* Gradient masks for lyrics fade effect - adjusted to be more subtle */} +
+
@@ -226,12 +263,11 @@ const App: React.FC = () => { {/* Hidden Audio Element */}