|
|
import { urlCacheManager } from './urlCache.js' |
|
|
|
|
|
|
|
|
const pendingRequests = new Map() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export async function getCachedMusicPicUrl(source, id, size = 300, skipCache = false) { |
|
|
if (!source || !id) return null |
|
|
|
|
|
|
|
|
const sizeStr = '300' |
|
|
|
|
|
|
|
|
if (!skipCache) { |
|
|
const cached = urlCacheManager.getCachedUrl(source, id, sizeStr) |
|
|
if (cached) { |
|
|
return cached |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const requestKey = `${source}+${id}+${sizeStr}` |
|
|
if (pendingRequests.has(requestKey)) { |
|
|
return pendingRequests.get(requestKey) |
|
|
} |
|
|
|
|
|
|
|
|
const apiUrl = `https://music-api.gdstudio.xyz/api.php?types=pic&source=${encodeURIComponent(source)}&id=${encodeURIComponent(id)}&size=${encodeURIComponent(sizeStr)}` |
|
|
|
|
|
const requestPromise = fetch(apiUrl) |
|
|
.then(response => { |
|
|
if (!response.ok) { |
|
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`) |
|
|
} |
|
|
return response.json() |
|
|
}) |
|
|
.then(data => { |
|
|
let resultUrl = null |
|
|
if (data && data.url) { |
|
|
resultUrl = data.url |
|
|
|
|
|
urlCacheManager.setCachedUrl(source, id, sizeStr, resultUrl) |
|
|
} |
|
|
return resultUrl |
|
|
}) |
|
|
.catch(error => { |
|
|
console.error('获取音乐图片失败:', error) |
|
|
return null |
|
|
}) |
|
|
.finally(() => { |
|
|
|
|
|
pendingRequests.delete(requestKey) |
|
|
}) |
|
|
|
|
|
|
|
|
pendingRequests.set(requestKey, requestPromise) |
|
|
|
|
|
return requestPromise |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export async function getCachedMusicPicUrlWithDelay(source, id, size = 300) { |
|
|
if (!source || !id) return null |
|
|
|
|
|
|
|
|
const sizeStr = '300' |
|
|
|
|
|
|
|
|
const cached = urlCacheManager.getCachedUrl(source, id, sizeStr) |
|
|
if (cached) { |
|
|
|
|
|
return cached |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const requestKey = `${source}+${id}+${sizeStr}` |
|
|
if (pendingRequests.size > 0) { |
|
|
await new Promise(resolve => setTimeout(resolve, 200)) |
|
|
} |
|
|
|
|
|
return getCachedMusicPicUrl(source, id, 300) |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export async function preloadMusicPics(songs, size = 300, concurrency = 1) { |
|
|
if (!Array.isArray(songs) || songs.length === 0) return |
|
|
|
|
|
|
|
|
const sizeStr = '300' |
|
|
|
|
|
|
|
|
const toLoad = songs.filter(song => { |
|
|
if (!song.source || !song.pic_id) return false |
|
|
return !urlCacheManager.getCachedUrl(song.source, song.pic_id, sizeStr) |
|
|
}) |
|
|
|
|
|
if (toLoad.length === 0) return |
|
|
|
|
|
|
|
|
for (let i = 0; i < toLoad.length; i += concurrency) { |
|
|
const batch = toLoad.slice(i, i + concurrency) |
|
|
const promises = batch.map(song => |
|
|
getCachedMusicPicUrl(song.source, song.pic_id, 300).catch(error => { |
|
|
console.warn(`预加载 ${song.name} 图片失败:`, error) |
|
|
return null |
|
|
}) |
|
|
) |
|
|
|
|
|
await Promise.all(promises) |
|
|
|
|
|
|
|
|
if (i + concurrency < toLoad.length) { |
|
|
await new Promise(resolve => setTimeout(resolve, 200)) |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function clearMusicPicCache(source, id) { |
|
|
if (!source || !id) return |
|
|
|
|
|
|
|
|
const commonSizes = ['300', '500', '800', '1200'] |
|
|
commonSizes.forEach(size => { |
|
|
const key = urlCacheManager.getCacheKey(source, id, size) |
|
|
urlCacheManager.cache.delete(key) |
|
|
}) |
|
|
|
|
|
urlCacheManager.saveToStorage() |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function getCacheStats() { |
|
|
return urlCacheManager.getStats() |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function clearAllCache() { |
|
|
urlCacheManager.clear() |
|
|
} |
|
|
|
|
|
export default { |
|
|
getCachedMusicPicUrl, |
|
|
getCachedMusicPicUrlWithDelay, |
|
|
preloadMusicPics, |
|
|
clearMusicPicCache, |
|
|
getCacheStats, |
|
|
clearAllCache |
|
|
} |