|
|
|
|
|
class UrlCacheManager { |
|
|
constructor() { |
|
|
this.cache = new Map() |
|
|
this.maxCacheSize = 1000 |
|
|
this.storageKey = 'music-url-cache-v1' |
|
|
this.cacheExpiry = 7 * 24 * 60 * 60 * 1000 |
|
|
this.loadFromStorage() |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getCacheKey(source, id, br) { |
|
|
return `${source}+${id}+${br}` |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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() |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
loadFromStorage() { |
|
|
try { |
|
|
const saved = localStorage.getItem(this.storageKey) |
|
|
if (saved) { |
|
|
const data = JSON.parse(saved) |
|
|
if (data && Array.isArray(data.entries)) { |
|
|
|
|
|
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() |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |