// Music Player State const playerState = { isPlaying: false, currentTrackIndex: -1, volume: 80, progress: 0, tracks: [], draggedElement: null }; // DOM Elements const elements = { selectFolderBtn: document.getElementById('select-folder-btn'), folderInput: document.getElementById('folder-input'), tracksList: document.getElementById('tracks-list'), playPauseBtn: document.getElementById('play-pause-btn'), prevBtn: document.getElementById('prev-btn'), nextBtn: document.getElementById('next-btn'), progressBar: document.getElementById('progress-bar'), volumeSlider: document.getElementById('volume-slider'), currentTime: document.getElementById('current-time'), totalTime: document.getElementById('total-time'), currentTrackTitle: document.getElementById('current-track-title'), currentTrackArtist: document.getElementById('current-track-artist'), shuffleBtn: document.getElementById('shuffle-btn'), repeatBtn: document.getElementById('repeat-btn') }; // Initialize the application document.addEventListener('DOMContentLoaded', () => { setupEventListeners(); updatePlayerUI(); }); // Set up event listeners function setupEventListeners() { // Folder selection elements.selectFolderBtn.addEventListener('click', () => { elements.folderInput.click(); }); elements.folderInput.addEventListener('change', handleFolderSelection); // Player controls elements.playPauseBtn.addEventListener('click', togglePlayPause); elements.prevBtn.addEventListener('click', playPreviousTrack); elements.nextBtn.addEventListener('click', playNextTrack); elements.progressBar.addEventListener('input', handleProgressChange); elements.volumeSlider.addEventListener('input', handleVolumeChange); // Shuffle and repeat elements.shuffleBtn.addEventListener('click', toggleShuffle); elements.repeatBtn.addEventListener('click', toggleRepeat); // Keyboard shortcuts document.addEventListener('keydown', handleKeyboardShortcuts); } // Handle folder selection function handleFolderSelection(event) { const files = Array.from(event.target.files); const audioFiles = files.filter(file => file.type.startsWith('audio/')); if (audioFiles.length === 0) { alert('No audio files found in the selected folder.'); return; } playerState.tracks = audioFiles.map((file, index) => ({ id: index, title: file.name.replace(/\.[^/.]+$/, ""), // Remove extension artist: 'Unknown Artist', album: 'Unknown Album', duration: '0:00', file: file, url: URL.createObjectURL(file) })); renderPlaylist(); updatePlayerUI(); } // Render playlist function renderPlaylist() { elements.tracksList.innerHTML = ''; playerState.tracks.forEach((track, index) => { const trackElement = document.createElement('div'); trackElement.className = 'track-item grid grid-cols-12 gap-4 p-3 items-center cursor-pointer'; trackElement.draggable = true; trackElement.dataset.index = index; trackElement.innerHTML = `
${index + 1}
${track.title}
${track.album}
${track.duration}
`; // Add drag and drop events trackElement.addEventListener('dragstart', handleDragStart); trackElement.addEventListener('dragover', handleDragOver); trackElement.addEventListener('dragenter', handleDragEnter); trackElement.addEventListener('dragleave', handleDragLeave); trackElement.addEventListener('drop', handleDrop); trackElement.addEventListener('dragend', handleDragEnd); // Add click event to play track trackElement.addEventListener('click', (e) => { if (!e.target.closest('.more-button') && !e.target.closest('.play-button')) { playTrack(index); } }); elements.tracksList.appendChild(trackElement); }); feather.replace(); } // Drag and Drop Functions function handleDragStart(e) { playerState.draggedElement = this; setTimeout(() => { this.classList.add('dragging'); }, 0); } function handleDragOver(e) { e.preventDefault(); } function handleDragEnter(e) { e.preventDefault(); this.classList.add('drag-over'); } function handleDragLeave() { this.classList.remove('drag-over'); } function handleDrop(e) { e.preventDefault(); this.classList.remove('drag-over'); if (playerState.draggedElement !== this) { const draggedIndex = parseInt(playerState.draggedElement.dataset.index); const targetIndex = parseInt(this.dataset.index); // Reorder tracks array const draggedTrack = playerState.tracks[draggedIndex]; playerState.tracks.splice(draggedIndex, 1); playerState.tracks.splice(targetIndex, 0, draggedTrack); // Update indices playerState.tracks.forEach((track, index) => { track.id = index; }); // Update current track index if needed if (playerState.currentTrackIndex === draggedIndex) { playerState.currentTrackIndex = targetIndex; } else if (playerState.currentTrackIndex === targetIndex) { playerState.currentTrackIndex = draggedIndex; } renderPlaylist(); } } function handleDragEnd() { this.classList.remove('dragging'); playerState.draggedElement = null; document.querySelectorAll('.track-item').forEach(item => { item.classList.remove('drag-over', 'drag-over-after'); }); } // Player Control Functions function togglePlayPause() { playerState.isPlaying = !playerState.isPlaying; updatePlayPauseButton(); if (playerState.isPlaying && playerState.currentTrackIndex === -1 && playerState.tracks.length > 0) { playTrack(0); } } function playTrack(index) { if (index < 0 || index >= playerState.tracks.length) return; playerState.currentTrackIndex = index; playerState.isPlaying = true; const track = playerState.tracks[index]; elements.currentTrackTitle.textContent = track.title; elements.currentTrackArtist.textContent = track.artist; updatePlayPauseButton(); renderPlaylist(); simulatePlayback(); } function playNextTrack() { if (playerState.tracks.length === 0) return; let nextIndex = playerState.currentTrackIndex + 1; if (nextIndex >= playerState.tracks.length) { nextIndex = 0; // Loop to beginning } playTrack(nextIndex); } function playPreviousTrack() { if (playerState.tracks.length === 0) return; let prevIndex = playerState.currentTrackIndex - 1; if (prevIndex < 0) { prevIndex = playerState.tracks.length - 1; // Loop to end } playTrack(prevIndex); } function handleProgressChange() { playerState.progress = parseInt(elements.progressBar.value); updateTimeDisplay(); } function handleVolumeChange() { playerState.volume = parseInt(elements.volumeSlider.value); elements.volumeSlider.style.background = `linear-gradient(to right, var(--primary-color) 0%, var(--primary-color) ${playerState.volume}%, rgba(255,255,255,0.3) ${playerState.volume}%, rgba(255,255,255,0.3) 100%)`; } function toggleShuffle() { elements.shuffleBtn.classList.toggle('text-green-500'); } function toggleRepeat() { elements.repeatBtn.classList.toggle('text-green-500'); } // Update UI Functions function updatePlayPauseButton() { const icon = elements.playPauseBtn.querySelector('i'); if (playerState.isPlaying) { icon.setAttribute('data-feather', 'pause'); } else { icon.setAttribute('data-feather', 'play'); } feather.replace(); } function updateTimeDisplay() { // In a real app, this would be based on actual track time const totalSeconds = 210; // Example: 3:30 const currentSeconds = Math.floor((playerState.progress / 100) * totalSeconds); const formatTime = (seconds) => { const mins = Math.floor(seconds / 60); const secs = seconds % 60; return `${mins}:${secs < 10 ? '0' : ''}${secs}`; }; elements.currentTime.textContent = formatTime(currentSeconds); elements.totalTime.textContent = formatTime(totalSeconds); } function updatePlayerUI() { // Update volume slider background elements.volumeSlider.style.background = `linear-gradient(to right, var(--primary-color) 0%, var(--primary-color) ${playerState.volume}%, rgba(255,255,255,0.3) ${playerState.volume}%, rgba(255,255,255,0.3) 100%)`; // Update progress bar elements.progressBar.value = playerState.progress; updateTimeDisplay(); } // Simulate playback progress function simulatePlayback() { if (!playerState.isPlaying) return; const interval = setInterval(() => { if (!playerState.isPlaying) { clearInterval(interval); return; } playerState.progress += 0.5; if (playerState.progress >= 100) { playerState.progress = 0; playNextTrack(); } updatePlayerUI(); }, 100); } // Keyboard Shortcuts function handleKeyboardShortcuts(e) { // Spacebar to play/pause if (e.code === 'Space') { e.preventDefault(); togglePlayPause(); } // Left arrow for previous track if (e.code === 'ArrowLeft') { playPreviousTrack(); } // Right arrow for next track if (e.code === 'ArrowRight') { playNextTrack(); } }