// 音乐图片URL缓存管理器 class UrlCacheManager { constructor() { this.cache = new Map() this.maxCacheSize = 1000 // 上限1000个 this.storageKey = 'music-url-cache-v1' this.cacheExpiry = 7 * 24 * 60 * 60 * 1000 // 7天过期 this.loadFromStorage() } /** * 生成缓存键 * @param {string} source - 音乐源 * @param {string} id - 歌曲或图片ID * @param {string} br - 比特率或尺寸 * @returns {string} 缓存键 */ getCacheKey(source, id, br) { return `${source}+${id}+${br}` } /** * 获取缓存的URL * @param {string} source - 音乐源 * @param {string} id - 歌曲或图片ID * @param {string} br - 比特率或尺寸 * @returns {string|null} 缓存的URL,如果不存在返回null */ getCachedUrl(source, id, br) { if (!source || !id) return null const key = this.getCacheKey(source, id, br) const cached = this.cache.get(key) if (cached) { // 检查是否过期 if (Date.now() - cached.timestamp < this.cacheExpiry) { return cached.url } else { // 过期删除 this.cache.delete(key) this.saveToStorage() } } return null } /** * 设置缓存URL * @param {string} source - 音乐源 * @param {string} id - 歌曲或图片ID * @param {string} br - 比特率或尺寸 * @param {string} url - 要缓存的URL */ setCachedUrl(source, id, br, url) { if (!source || !id || !url) return const key = this.getCacheKey(source, id, br) // 如果缓存已满,删除最旧的条目 if (this.cache.size >= this.maxCacheSize) { this.evictOldest() } this.cache.set(key, { url, timestamp: Date.now() }) this.saveToStorage() } /** * 删除最旧的缓存条目 */ evictOldest() { let oldestKey = null let oldestTime = Date.now() for (const [key, value] of this.cache.entries()) { if (value.timestamp < oldestTime) { oldestTime = value.timestamp oldestKey = key } } if (oldestKey) { this.cache.delete(oldestKey) } } /** * 清理过期的缓存条目 */ cleanExpired() { const now = Date.now() const expiredKeys = [] for (const [key, value] of this.cache.entries()) { if (now - value.timestamp > this.cacheExpiry) { expiredKeys.push(key) } } expiredKeys.forEach(key => this.cache.delete(key)) if (expiredKeys.length > 0) { this.saveToStorage() } } /** * 从localStorage加载缓存 */ loadFromStorage() { try { const saved = localStorage.getItem(this.storageKey) if (saved) { const data = JSON.parse(saved) if (data && Array.isArray(data.entries)) { // 恢复Map数据,同时清理过期条目 const now = Date.now() data.entries.forEach(([key, value]) => { if (now - value.timestamp < this.cacheExpiry) { this.cache.set(key, value) } }) } } } catch (error) { console.error('加载URL缓存失败:', error) this.cache.clear() } } /** * 保存缓存到localStorage */ saveToStorage() { try { const data = { entries: Array.from(this.cache.entries()), timestamp: Date.now() } localStorage.setItem(this.storageKey, JSON.stringify(data)) } catch (error) { console.error('保存URL缓存失败:', error) // 如果保存失败(可能是空间不足),清理一些旧缓存 this.evictOldest() try { const data = { entries: Array.from(this.cache.entries()), timestamp: Date.now() } localStorage.setItem(this.storageKey, JSON.stringify(data)) } catch (e) { console.warn('URL缓存保存最终失败:', e) } } } /** * 清空所有缓存 */ clear() { this.cache.clear() localStorage.removeItem(this.storageKey) } /** * 获取缓存统计信息 */ getStats() { return { size: this.cache.size, maxSize: this.maxCacheSize, utilization: (this.cache.size / this.maxCacheSize * 100).toFixed(1) + '%' } } } // 创建全局实例 export const urlCacheManager = new UrlCacheManager() // 启动定期清理过期缓存(每小时清理一次) setInterval(() => { urlCacheManager.cleanExpired() }, 60 * 60 * 1000) export default urlCacheManager