File size: 4,966 Bytes
9e40388
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3b9298b
 
9e40388
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3b9298b
 
9e40388
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3b9298b
9e40388
 
 
 
 
 
 
 
 
 
 
3b9298b
 
9e40388
 
 
 
 
 
 
 
 
 
 
 
 
3b9298b
9e40388
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import { urlCacheManager } from './urlCache.js'

// 请求去重映射
const pendingRequests = new Map()

/**
 * 带缓存的音乐图片URL获取函数
 * @param {string} source - 音乐源
 * @param {string} id - 图片ID  
 * @param {string|number} size - 图片尺寸
 * @param {boolean} skipCache - 是否跳过缓存
 * @returns {Promise<string>} 图片URL
 */
export async function getCachedMusicPicUrl(source, id, size = 300, skipCache = false) {
  if (!source || !id) return null
  
  // 强制使用 300 尺寸,不管传入什么参数
  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)
  }
  
  // 创建新的API请求
  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
}

/**
 * 带延时的音乐图片URL获取函数(懒加载专用)
 * 第一个请求立即执行,后续请求间隔200ms
 * @param {string} source - 音乐源
 * @param {string} id - 图片ID
 * @param {string|number} size - 图片尺寸  
 * @returns {Promise<string>} 图片URL
 */
export async function getCachedMusicPicUrlWithDelay(source, id, size = 300) {
  if (!source || !id) return null
  
  // 强制使用 300 尺寸,不管传入什么参数
  const sizeStr = '300'
  
  // 先检查缓存
  const cached = urlCacheManager.getCachedUrl(source, id, sizeStr)
  if (cached) {
    // 缓存命中,直接返回,无需延时
    return cached
  }
  
  // 缓存未命中,需要请求API
  // 如果不是第一个请求,添加200ms延时
  const requestKey = `${source}+${id}+${sizeStr}`
  if (pendingRequests.size > 0) {
    await new Promise(resolve => setTimeout(resolve, 200))
  }
  
  return getCachedMusicPicUrl(source, id, 300)
}

/**
 * 批量预加载音乐图片URL
 * @param {Array} songs - 歌曲数组,每个歌曲应包含source和pic_id字段
 * @param {string|number} size - 图片尺寸
 * @param {number} concurrency - 并发数量
 */
export async function preloadMusicPics(songs, size = 300, concurrency = 1) {
  if (!Array.isArray(songs) || songs.length === 0) return
  
  // 强制使用 300 尺寸,不管传入什么参数
  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)
    
    // 批次间间隔200ms
    if (i + concurrency < toLoad.length) {
      await new Promise(resolve => setTimeout(resolve, 200))
    }
  }
}

/**
 * 清除指定歌曲的图片缓存
 * @param {string} source - 音乐源
 * @param {string} id - 图片ID
 */
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
}