music / src /utils /urlCache.js
ahutchen's picture
feat(components): 优化多个组件的样式和功能
9e40388
// 音乐图片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