// 网易云榜单详情 JavaScript class NeteaseMusicRankDetail { constructor() { this.apiUrls = []; this.currentApiIndex = 0; this.rankData = null; this.init(); } async init() { try { await this.loadApiUrls(); this.bindEvents(); this.checkUrlParams(); } catch (error) { console.error('初始化失败:', error); this.showError('初始化失败,请刷新页面重试'); } } // 加载API接口列表 async loadApiUrls() { try { const response = await fetch('./接口集合.json'); if (!response.ok) { throw new Error('无法加载API接口配置'); } this.apiUrls = await response.json(); console.log('API接口加载成功:', this.apiUrls); } catch (error) { console.error('加载API接口失败:', error); // 使用默认接口 this.apiUrls = [ 'https://60s-cf.viki.moe', 'https://60s.viki.moe', 'https://60s.b23.run', 'https://60s.114128.xyz', 'https://60s-cf.114128.xyz' ]; } } // 绑定事件 bindEvents() { const loadBtn = document.getElementById('loadBtn'); const rankIdInput = document.getElementById('rankId'); const retryBtn = document.getElementById('retryBtn'); loadBtn.addEventListener('click', () => this.loadRankDetail()); retryBtn.addEventListener('click', () => this.loadRankDetail()); // 回车键加载 rankIdInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { this.loadRankDetail(); } }); // 输入验证 rankIdInput.addEventListener('input', (e) => { const value = e.target.value.trim(); loadBtn.disabled = !value || !/^\d+$/.test(value); }); } // 检查URL参数 checkUrlParams() { const urlParams = new URLSearchParams(window.location.search); const rankId = urlParams.get('id'); const rankName = urlParams.get('name'); if (rankId && /^\d+$/.test(rankId)) { document.getElementById('rankId').value = rankId; // 如果有榜单名称,更新页面标题 if (rankName) { document.title = `${decodeURIComponent(rankName)} - 网易云榜单详情`; document.querySelector('.title').textContent = `🎵 ${decodeURIComponent(rankName)}`; document.querySelector('.subtitle').textContent = '正在加载榜单详情...'; } this.loadRankDetail(); } } // 加载榜单详情 async loadRankDetail() { const rankId = document.getElementById('rankId').value.trim(); if (!rankId) { this.showError('请输入榜单ID'); return; } if (!/^\d+$/.test(rankId)) { this.showError('榜单ID必须是数字'); return; } this.showLoading(); this.currentApiIndex = 0; try { const data = await this.fetchRankDetail(rankId); this.displayRankDetail(data); this.hideLoading(); // 更新URL const newUrl = new URL(window.location); newUrl.searchParams.set('id', rankId); window.history.replaceState({}, '', newUrl); } catch (error) { console.error('加载榜单详情失败:', error); this.hideLoading(); this.showError(error.message || '加载失败,请检查榜单ID是否正确'); } } // 获取榜单详情数据 async fetchRankDetail(rankId) { let lastError = null; for (let i = 0; i < this.apiUrls.length; i++) { try { const apiUrl = this.apiUrls[this.currentApiIndex]; const url = `${apiUrl}/v2/ncm-rank/${rankId}`; console.log(`尝试API ${this.currentApiIndex + 1}:`, url); const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); const response = await fetch(url, { signal: controller.signal, headers: { 'Accept': 'application/json', } }); clearTimeout(timeoutId); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); if (data.code !== 200) { throw new Error(data.message || '获取数据失败'); } console.log('API调用成功:', data); return data; } catch (error) { console.warn(`API ${this.currentApiIndex + 1} 失败:`, error.message); lastError = error; this.currentApiIndex = (this.currentApiIndex + 1) % this.apiUrls.length; if (error.name === 'AbortError') { lastError = new Error('请求超时,请重试'); } } } throw lastError || new Error('所有API接口都无法访问'); } // 显示榜单详情 displayRankDetail(data) { this.rankData = data; const songs = data.data || []; // 显示榜单信息(如果有的话) this.displayRankInfo(songs[0]); // 显示歌曲列表 this.displaySongList(songs); // 显示相关区域 document.getElementById('songList').style.display = 'block'; document.getElementById('error').style.display = 'none'; } // 显示榜单信息 displayRankInfo(firstSong) { const rankInfo = document.getElementById('rankInfo'); if (firstSong && firstSong.rank_name) { document.getElementById('rankName').textContent = firstSong.rank_name; document.getElementById('rankDescription').textContent = `${firstSong.rank_name} - 网易云音乐官方榜单`; // 如果有专辑封面,使用第一首歌的专辑封面作为榜单封面 if (firstSong.album && firstSong.album.cover) { document.getElementById('rankCover').src = firstSong.album.cover; document.getElementById('rankCover').alt = firstSong.rank_name; } document.getElementById('updateTime').textContent = `更新时间: ${this.formatDate(new Date())}`; document.getElementById('updateFrequency').textContent = '实时更新'; rankInfo.style.display = 'block'; } else { rankInfo.style.display = 'none'; } } // 显示歌曲列表 displaySongList(songs) { const songsContainer = document.getElementById('songs'); const songCount = document.getElementById('songCount'); songCount.textContent = `共 ${songs.length} 首歌曲`; songsContainer.innerHTML = ''; songs.forEach((song, index) => { const songElement = this.createSongElement(song, index); songsContainer.appendChild(songElement); }); } // 创建歌曲元素 createSongElement(song) { const songDiv = document.createElement('div'); songDiv.className = 'song-item'; // 处理艺术家信息 const artists = Array.isArray(song.artist) ? song.artist : [song.artist].filter(Boolean); const artistNames = artists.map(artist => typeof artist === 'object' ? artist.name : artist ).join(', ') || '未知艺术家'; // 处理专辑信息 const albumName = song.album && song.album.name ? song.album.name : '未知专辑'; // 处理时长 const duration = song.duration_desc || this.formatDuration(song.duration); // 处理热度 const popularity = song.popularity || song.score || 0; songDiv.innerHTML = `