
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>旋律 - 现代音乐播放器</title><script src="https://cdn.tailwindcss.com"></script><link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet"><script>tailwind.config = {theme: {extend: {colors: {primary: '#6366F1', secondary: '#EC4899', dark: '#1E1B4B', light: '#EEF2FF', },fontFamily: {inter: ['Inter', 'system-ui', 'sans-serif'],},},}}</script><style type="text/tailwindcss">@layer utilities {.content-auto {content-visibility: auto;}.backdrop-blur {backdrop-filter: blur(8px);}.text-shadow {text-shadow: 0 2px 4px rgba(0,0,0,0.1);}.player-gradient {background: linear-gradient(135deg, #1E1B4B 0%, #3B3B98 100%);}.album-rotate {animation: rotate 20s linear infinite;}@keyframes rotate {from { transform: rotate(0deg); }to { transform: rotate(360deg); }}.progress-thumb {transform: scale(0);transition: transform 0.2s ease;}.progress-bar:hover .progress-thumb {transform: scale(1);}.fade-in {animation: fadeIn 0.3s ease-in-out;}@keyframes fadeIn {from { opacity: 0; }to { opacity: 1; }}.pulse {animation: pulse 1.5s infinite;}@keyframes pulse {0% { transform: scale(1); }50% { transform: scale(1.05); }100% { transform: scale(1); }}.mode-badge {transform-origin: center;animation: popIn 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);}@keyframes popIn {0% { transform: scale(0); }70% { transform: scale(1.2); }100% { transform: scale(1); }}.repeat-highlight {animation: highlight 2s infinite;}@keyframes highlight {0%, 100% { box-shadow: 0 0 0 0 rgba(236, 72, 153, 0.6); }50% { box-shadow: 0 0 0 6px rgba(236, 72, 153, 0.2); }}.single-repeat-indicator {position: relative;}.single-repeat-indicator::after {content: "1";position: absolute;bottom: -2px;right: -2px;width: 14px;height: 14px;background-color: #EC4899;color: white;border-radius: 50%;font-size: 8px;display: flex;align-items: center;justify-content: center;animation: pulse 1.5s infinite;}.track-highlight {background: linear-gradient(90deg, rgba(236, 72, 153, 0.1) 0%, rgba(236, 72, 153, 0) 100%);}.auto-import-notification {position: fixed;top: 20px;right: 20px;z-index: 1000;animation: slideIn 0.3s ease-out;}@keyframes slideIn {from { transform: translateX(100%); opacity: 0; }to { transform: translateX(0); opacity: 1; }}}</style>
</head><body class="font-inter bg-gray-900 text-light min-h-screen flex flex-col"><header class="fixed top-0 left-0 right-0 z-50 bg-dark/80 backdrop-blur transition-all duration-300"><div class="container mx-auto px-4 py-3 flex items-center justify-between"><div class="flex items-center space-x-2"><i class="fa fa-music text-primary text-2xl"></i><h1 class="text-xl font-bold bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">旋律</h1></div><div class="hidden md:flex items-center space-x-6"><a href="#" class="hover:text-primary transition-colors">发现</a><a href="#" class="hover:text-primary transition-colors">我的音乐</a><a href="#" class="hover:text-primary transition-colors">电台</a><a href="#" class="hover:text-primary transition-colors">排行榜</a></div><div class="flex items-center space-x-4"><button class="hover:text-primary transition-colors"><i class="fa fa-search text-lg"></i></button><button class="hover:text-primary transition-colors md:hidden"><i class="fa fa-bars text-lg"></i></button><div class="hidden md:block w-8 h-8 rounded-full bg-primary/20 flex items-center justify-center"><i class="fa fa-user text-primary"></i></div></div></div></header><main class="flex-grow pt-16 flex flex-col md:flex-row"><aside class="w-full md:w-80 bg-dark/50 border-r border-gray-800 p-4 overflow-y-auto max-h-[calc(100vh-160px)] md:max-h-[calc(100vh-64px)]"><div class="flex items-center justify-between mb-4"><h2 class="text-lg font-semibold">播放列表</h2><div class="flex space-x-2"><label for="import-music" class="text-gray-400 hover:text-primary transition-colors cursor-pointer"><i class="fa fa-upload"></i></label><input type="file" id="import-music" accept="audio/*" multiple style="display: none"><button class="text-gray-400 hover:text-primary transition-colors"><i class="fa fa-plus"></i></button></div></div><div id="mode-indicator" class="mb-4 p-2 bg-primary/10 rounded-lg text-xs text-gray-300 hidden fade-in flex items-center"><i id="mode-icon" class="fa fa-random mr-2 text-primary"></i><span id="mode-text">随机播放已开启</span></div><div id="import-hint" class="mb-4 p-3 bg-primary/10 rounded-lg text-sm text-gray-300 hidden fade-in"><i class="fa fa-info-circle mr-2 text-primary"></i><span>支持导入 MP3, WAV, OGG 等音频格式</span></div><div id="import-success" class="mb-4 p-3 bg-green-500/20 rounded-lg text-sm text-green-300 hidden fade-in"><i class="fa fa-check-circle mr-2 text-green-400"></i><span id="import-success-text">成功导入 2 首音乐</span></div><div id="single-repeat-hint" class="mb-4 p-3 bg-secondary/10 rounded-lg text-sm text-secondary hidden fade-in"><i class="fa fa-info-circle mr-2"></i><span>单曲循环已开启,当前歌曲将重复播放</span></div><ul id="playlist" class="space-y-2"></ul></aside><section class="flex-grow flex flex-col items-center justify-center p-6 md:p-12"><div class="relative mb-8 group"><div id="album-container" class="w-64 h-64 md:w-80 md:h-80 rounded-full overflow-hidden border-4 border-primary/30 shadow-lg shadow-primary/20"><img id="album-cover" src="https://picsum.photos/id/1025/400/400" alt="专辑封面" class="w-full h-full object-cover album-rotate"></div><div id="repeat-overlay" class="absolute -top-3 -right-3 bg-dark/80 backdrop-blur px-2 py-1 rounded-full text-xs hidden items-center space-x-1 mode-badge"><i id="repeat-overlay-icon" class="fa fa-repeat text-primary"></i><span id="repeat-overlay-text">列表循环</span></div><div class="absolute inset-0 rounded-full bg-black/20 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center"><button id="play-pause-btn" class="w-16 h-16 rounded-full bg-primary flex items-center justify-center shadow-lg transform scale-90 group-hover:scale-100 transition-transform"><i id="play-icon" class="fa fa-pause text-white text-2xl"></i></button></div></div><div class="text-center mb-8"><h2 id="song-title" class="text-2xl md:text-3xl font-bold mb-2 text-shadow">未播放歌曲</h2><p id="song-artist" class="text-gray-400">艺术家</p><div id="single-repeat-label" class="mt-2 inline-block px-3 py-0.5 bg-secondary/20 text-secondary text-xs rounded-full hidden fade-in"><i class="fa fa-repeat mr-1"></i>单曲循环中</div></div><div class="w-full max-w-2xl mb-2 px-2"><div class="flex justify-between text-xs text-gray-500 mb-1"><span id="current-time">00:00</span><span id="total-time">00:00</span></div><div class="progress-bar relative h-1 bg-gray-700 rounded-full cursor-pointer group"><div id="progress" class="absolute left-0 top-0 h-full bg-gradient-to-r from-primary to-secondary rounded-full w-0"></div><div class="progress-thumb absolute h-3 w-3 bg-white rounded-full -mt-1 group-hover:ring-4 group-hover:ring-primary/50"></div></div></div><div class="flex items-center justify-center space-x-6 md:space-x-10 mt-6"><button id="shuffle-btn" class="text-gray-400 hover:text-primary transition-colors relative"><i class="fa fa-random text-xl"></i><span id="shuffle-indicator" class="absolute -top-2 -right-2 w-4 h-4 bg-primary rounded-full text-[10px] flex items-center justify-center hidden mode-badge"><i class="fa fa-check"></i></span></button><button id="prev-btn" class="text-gray-300 hover:text-primary transition-colors"><i class="fa fa-step-backward text-2xl"></i></button><button id="big-play-pause-btn" class="w-14 h-14 md:w-16 md:h-16 rounded-full bg-gradient-to-r from-primary to-secondary flex items-center justify-center shadow-lg shadow-primary/20 hover:scale-105 transition-transform"><i id="big-play-icon" class="fa fa-pause text-white text-2xl md:text-3xl"></i></button><button id="next-btn" class="text-gray-300 hover:text-primary transition-colors"><i class="fa fa-step-forward text-2xl"></i></button><button id="repeat-btn" class="text-gray-400 hover:text-primary transition-colors relative group"><i id="repeat-btn-icon" class="fa fa-repeat text-xl"></i><div class="absolute bottom-full right-0 mb-2 bg-dark/90 backdrop-blur rounded px-3 py-1.5 text-xs opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 pointer-events-none whitespace-nowrap"><span id="repeat-tooltip">点击切换重复模式</span></div><span id="repeat-indicator" class="absolute -top-2 -right-2 w-4 h-4 bg-secondary rounded-full text-[10px] flex items-center justify-center hidden mode-badge">1</span></button></div><div class="w-full max-w-md mt-8 px-2"><div class="flex items-center space-x-3"><i class="fa fa-volume-up text-gray-400"></i><div class="flex-grow h-1 bg-gray-700 rounded-full relative cursor-pointer group"><div id="volume-level" class="absolute left-0 top-0 h-full bg-gray-400 rounded-full w-3/4"></div><div class="progress-thumb absolute h-3 w-3 bg-white rounded-full -mt-1 group-hover:ring-4 group-hover:ring-gray-400/50" style="left: 75%"></div></div></div></div></section></main><div class="md:hidden fixed bottom-0 left-0 right-0 bg-dark/90 backdrop-blur border-t border-gray-800 p-3"><div class="flex items-center justify-between"><div class="flex items-center space-x-3"><img src="https://picsum.photos/id/1025/60/60" alt="当前播放歌曲封面" class="w-12 h-12 rounded shadow"><div><h4 class="text-sm font-medium truncate w-24">未播放歌曲</h4><p class="text-xs text-gray-400 truncate w-24">艺术家</p></div></div><div class="flex items-center space-x-4"><button class="text-gray-300 hover:text-primary transition-colors relative"><i class="fa fa-random"></i><span class="absolute -top-1 -right-1 w-3 h-3 bg-primary rounded-full text-[8px] flex items-center justify-center hidden mode-badge"><i class="fa fa-check"></i></span></button><button class="text-gray-300 hover:text-primary transition-colors"><i class="fa fa-step-backward"></i></button><button class="w-10 h-10 rounded-full bg-primary flex items-center justify-center"><i class="fa fa-pause text-white"></i></button><button class="text-gray-300 hover:text-primary transition-colors"><i class="fa fa-step-forward"></i></button><button class="text-gray-300 hover:text-primary transition-colors relative"><i class="fa fa-repeat"></i><span class="absolute -top-1 -right-1 w-3 h-3 bg-secondary rounded-full text-[8px] flex items-center justify-center hidden mode-badge">1</span></button></div></div></div><audio id="audio-player" preload="metadata">您的浏览器不支持音频播放</audio><input type="file" id="directory-reader" webkitdirectory directory multiple style="display: none"><script>let songs = [{id: 1,title: "星光下的海",artist: "梦境乐队",src: "https://example.com/music/song1.mp3", cover: "https://picsum.photos/id/1025/400/400",duration: "3:45",isLocal: false},{id: 2,title: "城市脉动",artist: "节奏工厂",src: "https://example.com/music/song2.mp3",cover: "https://picsum.photos/id/1039/400/400",duration: "4:12",isLocal: false},{id: 3,title: "微风轻拂",artist: "自然之声",src: "https://example.com/music/song3.mp3",cover: "https://picsum.photos/id/1043/400/400",duration: "2:58",isLocal: false},{id: 4,title: "午夜旋律",artist: "蓝调爵士",src: "https://example.com/music/song4.mp3",cover: "https://picsum.photos/id/1050/400/400",duration: "5:20",isLocal: false},{id: 5,title: "晨曦微光",artist: "宁静钢琴",src: "https://example.com/music/song5.mp3",cover: "https://picsum.photos/id/1054/400/400",duration: "3:30",isLocal: false}];const audioPlayer = document.getElementById('audio-player');const playPauseBtn = document.getElementById('play-pause-btn');const bigPlayPauseBtn = document.getElementById('big-play-pause-btn');const playIcon = document.getElementById('play-icon');const bigPlayIcon = document.getElementById('big-play-icon');const prevBtn = document.getElementById('prev-btn');const nextBtn = document.getElementById('next-btn');const progressBar = document.querySelector('.progress-bar');const progress = document.getElementById('progress');const progressThumb = document.querySelector('.progress-thumb');const currentTimeEl = document.getElementById('current-time');const totalTimeEl = document.getElementById('total-time');const shuffleBtn = document.getElementById('shuffle-btn');const repeatBtn = document.getElementById('repeat-btn');const shuffleIndicator = document.getElementById('shuffle-indicator');const repeatIndicator = document.getElementById('repeat-indicator');const repeatOverlay = document.getElementById('repeat-overlay');const repeatOverlayIcon = document.getElementById('repeat-overlay-icon');const repeatOverlayText = document.getElementById('repeat-overlay-text');const repeatTooltip = document.getElementById('repeat-tooltip');const repeatBtnIcon = document.getElementById('repeat-btn-icon');const volumeControl = document.querySelector('.flex-grow.relative');const volumeLevel = document.getElementById('volume-level');const volumeThumb = volumeControl.querySelector('.progress-thumb');const albumCover = document.getElementById('album-cover');const albumContainer = document.getElementById('album-container');const songTitle = document.getElementById('song-title');const songArtist = document.getElementById('song-artist');const playlist = document.getElementById('playlist');const importMusicInput = document.getElementById('import-music');const directoryReader = document.getElementById('directory-reader');const importHint = document.getElementById('import-hint');const importSuccess = document.getElementById('import-success');const importSuccessText = document.getElementById('import-success-text');const modeIndicator = document.getElementById('mode-indicator');const modeIcon = document.getElementById('mode-icon');const modeText = document.getElementById('mode-text');const singleRepeatHint = document.getElementById('single-repeat-hint');const singleRepeatLabel = document.getElementById('single-repeat-label');let currentSongIndex = 0;let isPlaying = false;let isShuffle = false;let repeatMode = 0; let isDragging = false;let lastImportHintTime = 0;let playHistory = []; let historyIndex = -1; let modeIndicatorTimeout; let repeatEndTimeout; let repeatNotificationTimeout; let singleRepeatCount = 0; const SINGLE_REPEAT_ANIMATION_THRESHOLD = 2; const SINGLE_REPEAT_NOTIFICATION_DELAY = 10000; function initPlaylist() {playlist.innerHTML = '';songs.forEach((song, index) => {const li = document.createElement('li');const isCurrentAndSingle = index === currentSongIndex && repeatMode === 1;li.className = `p-3 rounded-lg hover:bg-gray-800/50 transition-colors cursor-pointer ${index === currentSongIndex ? 'bg-primary/20' : ''} ${isCurrentAndSingle ? 'border-l-2 border-secondary track-highlight' : ''} fade-in`;li.innerHTML = `<div class="flex items-center justify-between"><div class="flex items-center space-x-3"><div class="w-10 h-10 rounded overflow-hidden ${isCurrentAndSingle ? 'ring-2 ring-secondary' : ''}"><img src="${song.cover}" alt="${song.title}封面" class="w-full h-full object-cover"></div><div><h4 class="text-sm font-medium truncate w-40 ${isCurrentAndSingle ? 'text-secondary' : ''}">${song.title}</h4><p class="text-xs text-gray-400">${song.artist} ${song.isLocal ? '<span class="inline-block ml-1 px-1.5 py-0.5 bg-primary/20 text-primary text-[10px] rounded">本地</span>' : ''}${isCurrentAndSingle ? '<span class="inline-block ml-1 px-1.5 py-0.5 bg-secondary/20 text-secondary text-[10px] rounded">单曲循环中</span>' : ''}</p></div></div><div class="flex items-center space-x-2"><span class="text-xs text-gray-500">${song.duration}</span>${song.isLocal ? `<button class="remove-song text-gray-500 hover:text-red-400 transition-colors" data-index="${index}"><i class="fa fa-times text-xs"></i></button>` : ''}</div></div>`;li.addEventListener('click', (e) => {if (!e.target.closest('.remove-song')) {playSong(index);}});playlist.appendChild(li);});document.querySelectorAll('.remove-song').forEach(btn => {btn.addEventListener('click', (e) => {e.stopPropagation();const index = parseInt(btn.getAttribute('data-index'));removeSong(index);});});}function playSong(index) {if (index < 0 || index >= songs.length) return;if (index !== currentSongIndex) {singleRepeatCount = 0;albumContainer.classList.remove('repeat-highlight');singleRepeatLabel.classList.add('hidden');if (repeatNotificationTimeout) {clearTimeout(repeatNotificationTimeout);}}if (historyIndex >= 0) {if (index !== playHistory[historyIndex + 1]) {playHistory = playHistory.slice(0, historyIndex + 1);}}if (playHistory.length === 0 || index !== playHistory[playHistory.length - 1]) {playHistory.push(index);historyIndex = playHistory.length - 1;}currentSongIndex = index;const song = songs[currentSongIndex];albumCover.src = song.cover;songTitle.textContent = song.title;songArtist.textContent = song.artist;totalTimeEl.textContent = song.duration;updateSingleRepeatDisplay();initPlaylist();audioPlayer.src = song.src;audioPlayer.load();play();updateModeIndicator();}function play() {audioPlayer.play();isPlaying = true;playIcon.className = 'fa fa-pause text-white text-2xl';bigPlayIcon.className = 'fa fa-pause text-white text-2xl md:text-3xl';albumCover.classList.add('album-rotate');}function pause() {audioPlayer.pause();isPlaying = false;playIcon.className = 'fa fa-play text-white text-2xl';bigPlayIcon.className = 'fa fa-play text-white text-2xl md:text-3xl';albumCover.classList.remove('album-rotate');}function togglePlayPause() {if (isPlaying) {pause();} else {play();}}function prevSong() {if (songs.length <= 1) return;singleRepeatCount = 0;albumContainer.classList.remove('repeat-highlight');singleRepeatLabel.classList.add('hidden');if (repeatNotificationTimeout) {clearTimeout(repeatNotificationTimeout);}let index;if (historyIndex > 0) {historyIndex--;index = playHistory[historyIndex];} else {if (isShuffle) {do {index = Math.floor(Math.random() * songs.length);} while (index === currentSongIndex);} else {index = currentSongIndex - 1;if (index < 0) index = songs.length - 1;}}playSong(index);}function nextSong() {if (songs.length <= 1) return;singleRepeatCount = 0;albumContainer.classList.remove('repeat-highlight');singleRepeatLabel.classList.add('hidden');if (repeatNotificationTimeout) {clearTimeout(repeatNotificationTimeout);}let index;if (historyIndex < playHistory.length - 1) {historyIndex++;index = playHistory[historyIndex];} else {if (isShuffle) {if (songs.length <= 3) {index = Math.floor(Math.random() * songs.length);} else {do {index = Math.floor(Math.random() * songs.length);} while (index === currentSongIndex);}} else {index = currentSongIndex + 1;if (index >= songs.length) index = 0;}}playSong(index);}function updateProgress() {if (isDragging) return;const { currentTime, duration } = audioPlayer;if (isNaN(duration)) return;const progressPercent = (currentTime / duration) * 100;progress.style.width = `${progressPercent}%`;progressThumb.style.left = `${progressPercent}%`;currentTimeEl.textContent = formatTime(currentTime);if (songs[currentSongIndex]?.isLocal && duration > 0) {const totalTime = formatTime(duration);totalTimeEl.textContent = totalTime;songs[currentSongIndex].duration = totalTime;}if (duration - currentTime < 1 && currentTime > 0 && duration > 0) {handleSongAlmostEnd();}}function handleSongAlmostEnd() {if (repeatEndTimeout) {clearTimeout(repeatEndTimeout);}repeatEndTimeout = setTimeout(handleSongEnd, 500);}function handleSongEnd() {switch (repeatMode) {case 1: singleRepeatCount++;if (singleRepeatCount >= SINGLE_REPEAT_ANIMATION_THRESHOLD) {albumContainer.classList.add('repeat-highlight');}if (singleRepeatCount === 1) {showSingleRepeatNotification();}audioPlayer.currentTime = 0;play();initPlaylist();break;case 0: if (currentSongIndex === songs.length - 1) {pause();audioPlayer.currentTime = 0;updateProgress();return;}case 2: nextSong();break;}}function showSingleRepeatNotification() {singleRepeatHint.classList.remove('hidden');singleRepeatLabel.classList.remove('hidden');if (repeatNotificationTimeout) {clearTimeout(repeatNotificationTimeout);}repeatNotificationTimeout = setTimeout(() => {singleRepeatHint.classList.add('hidden');}, SINGLE_REPEAT_NOTIFICATION_DELAY);}function updateSingleRepeatDisplay() {if (repeatMode === 1) {singleRepeatLabel.classList.remove('hidden');if (singleRepeatCount >= SINGLE_REPEAT_ANIMATION_THRESHOLD) {albumContainer.classList.add('repeat-highlight');}} else {singleRepeatLabel.classList.add('hidden');albumContainer.classList.remove('repeat-highlight');}}function formatTime(seconds) {if (isNaN(seconds)) return "00:00";const minutes = Math.floor(seconds / 60);const secs = Math.floor(seconds % 60);return `${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;}function setProgress(e) {const rect = progressBar.getBoundingClientRect();const pos = (e.clientX - rect.left) / rect.width;const newTime = pos * audioPlayer.duration;audioPlayer.currentTime = newTime;progress.style.width = `${pos * 100}%`;progressThumb.style.left = `${pos * 100}%`;}function setVolume(e) {const rect = volumeControl.getBoundingClientRect();const pos = (e.clientX - rect.left) / rect.width;const volume = Math.max(0, Math.min(1, pos));audioPlayer.volume = volume;volumeLevel.style.width = `${pos * 100}%`;volumeThumb.style.left = `${pos * 100}%`;}function toggleShuffle() {isShuffle = !isShuffle;if (isShuffle && repeatMode === 1) {repeatMode = 0;updateRepeatDisplay();singleRepeatCount = 0;albumContainer.classList.remove('repeat-highlight');singleRepeatLabel.classList.add('hidden');if (repeatNotificationTimeout) {clearTimeout(repeatNotificationTimeout);}}shuffleBtn.classList.toggle('text-primary', isShuffle);shuffleIndicator.classList.toggle('hidden', !isShuffle);if (isShuffle) {playHistory = [currentSongIndex];historyIndex = 0;}showModeIndicator();}function toggleRepeat() {const oldMode = repeatMode;repeatMode = (repeatMode + 1) % 3;if (oldMode === 1 && repeatMode !== 1) {singleRepeatCount = 0;albumContainer.classList.remove('repeat-highlight');singleRepeatLabel.classList.add('hidden');if (repeatNotificationTimeout) {clearTimeout(repeatNotificationTimeout);}}if (repeatMode === 1 && isShuffle) {isShuffle = false;shuffleBtn.classList.remove('text-primary');shuffleIndicator.classList.add('hidden');playHistory = [currentSongIndex];historyIndex = 0;}updateRepeatDisplay();if (repeatMode === 1 && oldMode !== 1) {showSingleRepeatNotification();}showModeIndicator();}function updateRepeatDisplay() {if (repeatMode === 1) {repeatBtn.classList.add('text-secondary');repeatBtn.classList.remove('text-primary');repeatBtnIcon.classList.add('single-repeat-indicator');} else {repeatBtn.classList.toggle('text-primary', repeatMode !== 0);repeatBtn.classList.remove('text-secondary');repeatBtnIcon.classList.remove('single-repeat-indicator');}if (repeatMode === 1) {repeatIndicator.textContent = '1';repeatIndicator.classList.remove('hidden');} else {repeatIndicator.classList.add('hidden');}switch (repeatMode) {case 0:repeatTooltip.textContent = "点击开启列表循环";repeatOverlayIcon.className = 'fa fa-repeat text-primary';repeatOverlayText.textContent = "不重复";break;case 1:repeatTooltip.textContent = "点击开启不重复模式";repeatOverlayIcon.className = 'fa fa-repeat text-secondary single-repeat-indicator';repeatOverlayText.textContent = "单曲循环";break;case 2:repeatTooltip.textContent = "点击开启单曲循环";repeatOverlayIcon.className = 'fa fa-repeat text-primary';repeatOverlayText.textContent = "列表循环";break;}if (repeatMode === 0) {repeatOverlay.classList.add('hidden');} else {repeatOverlay.classList.remove('hidden');repeatOverlay.classList.remove('mode-badge');void repeatOverlay.offsetWidth; repeatOverlay.classList.add('mode-badge');}updateSingleRepeatDisplay();initPlaylist();}function showModeIndicator() {updateModeIndicator();modeIndicator.classList.remove('hidden');if (modeIndicatorTimeout) {clearTimeout(modeIndicatorTimeout);}modeIndicatorTimeout = setTimeout(() => {modeIndicator.classList.add('hidden');}, 3000);}function updateModeIndicator() {if (isShuffle) {modeIcon.className = 'fa fa-random mr-2 text-primary';modeText.textContent = '随机播放已开启';return;}switch (repeatMode) {case 0:modeIcon.className = 'fa fa-repeat mr-2 text-gray-500';modeText.textContent = '顺序播放(不重复)';break;case 1:modeIcon.className = 'fa fa-repeat mr-2 text-secondary';modeText.textContent = '单曲循环已开启';break;case 2:modeIcon.className = 'fa fa-repeat mr-2 text-primary';modeText.textContent = '列表循环已开启';break;}}function importLocalMusic(files) {if (!files || files.length === 0) return 0;let importedCount = 0;Array.from(files).forEach(file => {if (!file.type.startsWith('audio/')) {console.log(`跳过非音频文件: ${file.name}`);return;}const isDuplicate = songs.some(song => song.isLocal && song.title === file.name.replace(/\.[^/.]+$/, ""));if (isDuplicate) {console.log(`已跳过重复文件: ${file.name}`);return;}importedCount++;const objectUrl = URL.createObjectURL(file);const fileName = file.name.replace(/\.[^/.]+$/, "");let title = fileName;let artist = "未知艺术家";const separatorIndex = fileName.indexOf(' - ');if (separatorIndex > 0) {artist = fileName.substring(0, separatorIndex);title = fileName.substring(separatorIndex + 3);}const id = Date.now() + Math.floor(Math.random() * 1000);songs.push({id,title,artist,src: objectUrl,cover: `https://picsum.photos/seed/${id}/400/400`, duration: "00:00", isLocal: true});});initPlaylist();if (importedCount > 0) {importSuccessText.textContent = `成功导入 ${importedCount} 首音乐`;importSuccess.classList.remove('hidden');setTimeout(() => {importSuccess.classList.add('hidden');}, 3000);}return importedCount;}function removeSong(index) {if (index < 0 || index >= songs.length) return;const song = songs[index];if (song.isLocal) {URL.revokeObjectURL(song.src);}const historyPos = playHistory.indexOf(index);if (historyPos !== -1) {playHistory.splice(historyPos, 1);if (historyIndex >= historyPos) {historyIndex--;}if (historyIndex < 0 && playHistory.length > 0) {historyIndex = 0;}}if (index === currentSongIndex && repeatMode === 1) {singleRepeatCount = 0;albumContainer.classList.remove('repeat-highlight');singleRepeatLabel.classList.add('hidden');if (repeatNotificationTimeout) {clearTimeout(repeatNotificationTimeout);}}if (index === currentSongIndex) {pause();if (songs.length > 1) {const newIndex = index < songs.length - 1 ? index : 0;setTimeout(() => {playSong(newIndex);}, 300);} else {songTitle.textContent = "未播放歌曲";songArtist.textContent = "艺术家";totalTimeEl.textContent = "00:00";currentTimeEl.textContent = "00:00";progress.style.width = "0%";progressThumb.style.left = "0%";}} else if (index < currentSongIndex) {currentSongIndex--;}songs.splice(index, 1);initPlaylist();}function showImportHint() {const now = Date.now();if (now - lastImportHintTime > 2000) {importHint.classList.remove('hidden');setTimeout(() => {importHint.classList.add('hidden');}, 2000);lastImportHintTime = now;}}audioPlayer.addEventListener('ended', handleSongEnd);playPauseBtn.addEventListener('click', togglePlayPause);bigPlayPauseBtn.addEventListener('click', togglePlayPause);prevBtn.addEventListener('click', prevSong);nextBtn.addEventListener('click', nextSong);audioPlayer.addEventListener('timeupdate', updateProgress);shuffleBtn.addEventListener('click', toggleShuffle);repeatBtn.addEventListener('click', toggleRepeat);progressBar.addEventListener('click', setProgress);progressBar.addEventListener('mousedown', () => isDragging = true);document.addEventListener('mouseup', (e) => {if (isDragging) {setProgress(e);isDragging = false;}});document.addEventListener('mousemove', (e) => {if (isDragging) {setProgress(e);}});volumeControl.addEventListener('click', setVolume);volumeControl.addEventListener('mousedown', (e) => {isDragging = true;setVolume(e);});importMusicInput.addEventListener('change', (e) => {importLocalMusic(e.target.files);e.target.value = '';});document.querySelector('label[for="import-music"]').addEventListener('mouseenter', showImportHint);window.addEventListener('DOMContentLoaded', () => {initPlaylist();playHistory = [0];historyIndex = 0;audioPlayer.src = songs[0].src;audioPlayer.load();updateRepeatDisplay();updateModeIndicator();});window.addEventListener('beforeunload', () => {songs.forEach(song => {if (song.isLocal) {URL.revokeObjectURL(song.src);}});});</script>
</body>
</html>