// ============ 全局状态 ============ const state = { currentPage: 'home', currentSong: null, playlist: [], playlistIndex: -1, isPlaying: false, lyricsData: [], currentLyricIndex: -1 }; // ============ 路由系统 ============ const router = { go(path) { history.pushState(null, '', path); this.handleRoute(); }, handleRoute() { const path = window.location.pathname; // 更新导航激活状态 document.querySelectorAll('.header-nav a').forEach(a => { a.classList.remove('active'); const page = a.dataset.page; if (path === '/' && page === 'home') a.classList.add('active'); else if (path.startsWith('/' + page)) a.classList.add('active'); }); // 路由匹配 if (path === '/') { this.renderHome(); } else if (path === '/discover') { this.renderDiscover(); } else if (path === '/artists') { this.renderArtists(); } else if (path === '/playlists') { this.renderPlaylists(); } else if (path.startsWith('/song/')) { const id = path.split('/')[2]; this.renderSongDetail(id); } else if (path.startsWith('/artist/')) { const id = path.split('/')[2]; this.renderArtistDetail(id); } else if (path.startsWith('/album/')) { const id = path.split('/')[2]; this.renderAlbumDetail(id); } else if (path.startsWith('/playlist/')) { const id = path.split('/')[2]; this.renderPlaylistDetail(id); } else if (path.startsWith('/search')) { const q = new URLSearchParams(window.location.search).get('q'); this.renderSearch(q); } else { this.renderHome(); } }, // 首页 async renderHome() { const app = document.getElementById('app'); app.innerHTML = '
加载中
'; try { const data = await api.get('/api/home'); let html = ''; // 轮播图 if (data.banners.length > 0) { html += ''; } // 推荐歌单 if (data.featuredPlaylists.length > 0) { html += '

推荐歌单

更多
'; html += '
'; data.featuredPlaylists.forEach(pl => { html += `
${pl.title}
${pl.title}
`; }); html += '
'; } // 热门歌曲 if (data.hotSongs.length > 0) { html += '

热门推荐

'; html += '
'; data.hotSongs.slice(0, 10).forEach((song, i) => { html += renderSongItem(song, i + 1); }); html += '
'; } // 最新专辑 if (data.albums.length > 0) { html += '

新碟上架

更多
'; html += '
'; data.albums.slice(0, 6).forEach(album => { html += `
${album.title}
${album.title}
${album.artist_name || ''}
`; }); html += '
'; } // 热门歌手 if (data.artists.length > 0) { html += '

热门歌手

更多
'; html += '
'; data.artists.slice(0, 6).forEach(artist => { html += `
${artist.name}
${artist.name}
`; }); html += '
'; } app.innerHTML = html; // 初始化轮播 if (data.banners.length > 0) { banner.init(data.banners.length); } } catch (err) { app.innerHTML = '
加载失败
'; console.error(err); } }, // 发现页 async renderDiscover() { const app = document.getElementById('app'); app.innerHTML = '
加载中
'; try { const [songsData, albumsData] = await Promise.all([ api.get('/api/songs?limit=50'), api.get('/api/albums') ]); let html = '

全部歌曲

'; html += '
'; songsData.songs.forEach((song, i) => { html += renderSongItem(song, i + 1); }); html += '
'; html += '

全部专辑

'; html += '
'; albumsData.forEach(album => { html += `
${album.title}
${album.title}
${album.artist_name || ''}
`; }); html += '
'; app.innerHTML = html; } catch (err) { app.innerHTML = '
加载失败
'; } }, // 歌手列表页 async renderArtists() { const app = document.getElementById('app'); app.innerHTML = '
加载中
'; try { const artists = await api.get('/api/artists'); let html = '

全部歌手

'; html += '
'; artists.forEach(artist => { html += `
${artist.name}
${artist.name}
`; }); html += '
'; app.innerHTML = html; } catch (err) { app.innerHTML = '
加载失败
'; } }, // 歌单列表页 async renderPlaylists() { const app = document.getElementById('app'); app.innerHTML = '
加载中
'; try { const playlists = await api.get('/api/playlists'); let html = '

全部歌单

'; html += '
'; playlists.forEach(pl => { html += `
${pl.title}
${pl.title}
`; }); html += '
'; app.innerHTML = html; } catch (err) { app.innerHTML = '
加载失败
'; } }, // 歌曲详情 async renderSongDetail(id) { const app = document.getElementById('app'); app.innerHTML = '
加载中
'; try { const song = await api.get(`/api/songs/${id}`); let html = `
${song.title}
单曲

${song.title}

${song.artist_name || '未知歌手'} ${song.album_title ? ` · ${song.album_title}` : ''} · 播放 ${formatNumber(song.play_count)} 次
`; app.innerHTML = html; // 设置歌词 if (song.lyrics) { lyrics.parse(song.lyrics); } } catch (err) { app.innerHTML = '
加载失败
'; } }, // 歌手详情 async renderArtistDetail(id) { const app = document.getElementById('app'); app.innerHTML = '
加载中
'; try { const artist = await api.get(`/api/artists/${id}`); let html = `
${artist.name}
歌手

${artist.name}

${artist.bio || ''}
`; if (artist.albums.length > 0) { html += '

专辑

'; html += '
'; artist.albums.forEach(album => { html += `
${album.title}
${album.title}
`; }); html += '
'; } if (artist.songs.length > 0) { html += '

热门歌曲

'; html += '
'; artist.songs.forEach((song, i) => { html += renderSongItem(song, i + 1); }); html += '
'; } app.innerHTML = html; } catch (err) { app.innerHTML = '
加载失败
'; } }, // 专辑详情 async renderAlbumDetail(id) { const app = document.getElementById('app'); app.innerHTML = '
加载中
'; try { const album = await api.get(`/api/albums/${id}`); let html = `
${album.title}
专辑

${album.title}

${album.artist_name || '未知歌手'} ${album.release_date ? ` · ${album.release_date}` : ''}
${album.description || ''}
`; if (album.songs.length > 0) { html += '

歌曲列表

'; html += '
'; album.songs.forEach((song, i) => { html += renderSongItem(song, i + 1); }); html += '
'; } app.innerHTML = html; } catch (err) { app.innerHTML = '
加载失败
'; } }, // 歌单详情 async renderPlaylistDetail(id) { const app = document.getElementById('app'); app.innerHTML = '
加载中
'; try { const playlist = await api.get(`/api/playlists/${id}`); let html = `
${playlist.title}
歌单

${playlist.title}

${playlist.description || ''}
${playlist.songs.length} 首歌曲
`; if (playlist.songs.length > 0) { html += '

歌曲列表

'; html += '
'; playlist.songs.forEach((song, i) => { html += renderSongItem(song, i + 1); }); html += '
'; } app.innerHTML = html; } catch (err) { app.innerHTML = '
加载失败
'; } }, // 搜索结果 async renderSearch(q) { const app = document.getElementById('app'); if (!q) { app.innerHTML = '

请输入搜索关键词

'; return; } app.innerHTML = '
搜索中
'; try { const data = await api.get(`/api/search?q=${encodeURIComponent(q)}`); let html = `
`; html += `

搜索: "${q}"

`; if (data.songs.length > 0) { html += '

歌曲

'; html += '
'; data.songs.forEach((song, i) => { html += renderSongItem(song, i + 1); }); html += '
'; } if (data.artists.length > 0) { html += '

歌手

'; html += '
'; data.artists.forEach(artist => { html += `
${artist.name}
${artist.name}
`; }); html += '
'; } if (data.albums.length > 0) { html += '

专辑

'; html += '
'; data.albums.forEach(album => { html += `
${album.title}
${album.title}
${album.artist_name || ''}
`; }); html += '
'; } if (data.songs.length === 0 && data.artists.length === 0 && data.albums.length === 0) { html += '
未找到相关结果
'; } html += '
'; app.innerHTML = html; } catch (err) { app.innerHTML = '
搜索失败
'; } } }; // ============ API 工具 ============ const api = { async get(url) { const res = await fetch(url); return res.json(); }, async post(url, data) { const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); return res.json(); } }; // ============ 播放器 ============ const player = { audio: null, init() { this.audio = document.getElementById('audio'); this.audio.addEventListener('timeupdate', () => this.onTimeUpdate()); this.audio.addEventListener('ended', () => this.next()); this.audio.addEventListener('loadedmetadata', () => { document.getElementById('totalTime').textContent = formatTime(this.audio.duration); }); }, playSong(song) { state.currentSong = song; // 更新UI document.getElementById('playerTitle').textContent = song.title; document.getElementById('playerArtist').textContent = song.artist_name || '未知歌手'; const coverEl = document.getElementById('playerCover'); if (song.cover) { coverEl.innerHTML = `${song.title}`; } else { coverEl.innerHTML = '
'; } // 设置音频源 this.audio.src = song.file_path; this.audio.play(); state.isPlaying = true; this.updatePlayBtn(); // 解析歌词 if (song.lyrics) { lyrics.parse(song.lyrics); } else { lyrics.clear(); } // 增加播放次数 api.post(`/api/songs/${song.id}/play`, {}); // 高亮当前播放 document.querySelectorAll('.song-item').forEach(el => el.classList.remove('playing')); const currentEl = document.querySelector(`.song-item[data-id="${song.id}"]`); if (currentEl) currentEl.classList.add('playing'); }, playAll(songs) { if (songs.length === 0) return; state.playlist = songs; state.playlistIndex = 0; this.playSong(songs[0]); }, toggle() { if (!state.currentSong) return; if (state.isPlaying) { this.audio.pause(); state.isPlaying = false; } else { this.audio.play(); state.isPlaying = true; } this.updatePlayBtn(); }, prev() { if (state.playlist.length === 0) return; state.playlistIndex = (state.playlistIndex - 1 + state.playlist.length) % state.playlist.length; this.playSong(state.playlist[state.playlistIndex]); }, next() { if (state.playlist.length === 0) return; state.playlistIndex = (state.playlistIndex + 1) % state.playlist.length; this.playSong(state.playlist[state.playlistIndex]); }, seek(e) { if (!this.audio.duration) return; const bar = e.currentTarget; const rect = bar.getBoundingClientRect(); const percent = (e.clientX - rect.left) / rect.width; this.audio.currentTime = percent * this.audio.duration; }, setVolume(e) { const bar = e.currentTarget; const rect = bar.getBoundingClientRect(); const percent = (e.clientX - rect.left) / rect.width; this.audio.volume = Math.max(0, Math.min(1, percent)); document.getElementById('volumeLevel').style.width = (percent * 100) + '%'; }, toggleMute() { this.audio.muted = !this.audio.muted; const btn = document.getElementById('volumeBtn'); btn.innerHTML = this.audio.muted ? '' : ''; }, updatePlayBtn() { const btn = document.getElementById('playBtn'); btn.innerHTML = state.isPlaying ? '' : ''; }, onTimeUpdate() { const current = this.audio.currentTime; const duration = this.audio.duration || 0; // 更新进度条 const percent = duration > 0 ? (current / duration) * 100 : 0; document.getElementById('progress').style.width = percent + '%'; document.getElementById('currentTime').textContent = formatTime(current); // 更新歌词高亮 lyrics.update(current); } }; // ============ 歌词模块 ============ const lyrics = { toggle() { const panel = document.getElementById('lyricsPanel'); panel.classList.toggle('open'); }, parse(lyricsText) { const lines = lyricsText.split('\n'); state.lyricsData = []; lines.forEach(line => { const match = line.match(/\[(\d{2}):(\d{2})\.(\d{2,3})\](.*)/); if (match) { const min = parseInt(match[1]); const sec = parseInt(match[2]); const ms = parseInt(match[3].padEnd(3, '0')); const time = min * 60 + sec + ms / 1000; const text = match[4].trim(); if (text) { state.lyricsData.push({ time, text }); } } }); this.render(); }, render() { const content = document.getElementById('lyricsContent'); if (state.lyricsData.length === 0) { content.innerHTML = '
暂无歌词
'; return; } let html = '
'; state.lyricsData.forEach((line, i) => { html += `
${line.text}
`; }); html += '
'; content.innerHTML = html; state.currentLyricIndex = -1; }, update(currentTime) { if (state.lyricsData.length === 0) return; let newIndex = -1; for (let i = state.lyricsData.length - 1; i >= 0; i--) { if (currentTime >= state.lyricsData[i].time) { newIndex = i; break; } } if (newIndex !== state.currentLyricIndex) { state.currentLyricIndex = newIndex; // 更新高亮 document.querySelectorAll('.lyrics-line').forEach(el => el.classList.remove('active')); if (newIndex >= 0) { const activeLine = document.querySelector(`.lyrics-line[data-index="${newIndex}"]`); if (activeLine) { activeLine.classList.add('active'); // 滚动到可视区域 activeLine.scrollIntoView({ behavior: 'smooth', block: 'center' }); } } } }, clear() { state.lyricsData = []; state.currentLyricIndex = -1; document.getElementById('lyricsContent').innerHTML = '
暂无歌词
'; } }; // ============ 轮播图 ============ const banner = { timer: null, currentIndex: 0, total: 0, init(total) { this.total = total; this.currentIndex = 0; this.startAutoPlay(); }, goTo(index) { this.currentIndex = index; const slides = document.querySelectorAll('.banner-slide'); const dots = document.querySelectorAll('.banner-dots span'); slides.forEach((s, i) => s.classList.toggle('active', i === index)); dots.forEach((d, i) => d.classList.toggle('active', i === index)); }, next() { this.goTo((this.currentIndex + 1) % this.total); }, startAutoPlay() { if (this.timer) clearInterval(this.timer); this.timer = setInterval(() => this.next(), 5000); } }; // ============ 辅助函数 ============ function renderSongItem(song, index) { return `
${index}
${song.title}
${song.title}
${song.artist_name || '未知歌手'}
${formatTime(song.duration)}
`; } function formatTime(seconds) { if (!seconds || isNaN(seconds)) return '0:00'; const min = Math.floor(seconds / 60); const sec = Math.floor(seconds % 60); return `${min}:${sec.toString().padStart(2, '0')}`; } function formatNumber(num) { if (!num) return '0'; if (num >= 10000) return (num / 10000).toFixed(1) + '万'; return num.toString(); } function handleSearch(e) { if (e.key === 'Enter') { const q = e.target.value.trim(); if (q) { router.go(`/search?q=${encodeURIComponent(q)}`); } } } // ============ 初始化 ============ document.addEventListener('DOMContentLoaded', () => { player.init(); router.handleRoute(); // 处理浏览器后退 window.addEventListener('popstate', () => { router.handleRoute(); }); });