fix: 修复随机播放模式下预加载顺序错误的问题
- 修正 getNextIndex 在随机播放模式下返回正确的原始列表索引 - 简化预加载逻辑,因为 nextIndex 已经是正确的列表索引 - 保持 Player.vue 中更新歌曲信息时的索引计算逻辑 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
		
							parent
							
								
									dcf13b2f07
								
							
						
					
					
						commit
						ae2d8875ad
					
				| 
						 | 
				
			
			@ -1,13 +1,12 @@
 | 
			
		|||
<!-- Player.vue - 添加预加载功能 -->
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
 | 
			
		||||
import { usePlayQueueStore } from '../stores/usePlayQueueStore'
 | 
			
		||||
import { useTemplateRef, watch, nextTick, computed } from 'vue'
 | 
			
		||||
import { computed, nextTick, useTemplateRef, watch } from 'vue'
 | 
			
		||||
import { useRoute } from 'vue-router'
 | 
			
		||||
import { useFavourites } from '../stores/useFavourites'
 | 
			
		||||
import { usePlayQueueStore } from '../stores/usePlayQueueStore'
 | 
			
		||||
 | 
			
		||||
import PlayIcon from '../assets/icons/play.vue'
 | 
			
		||||
import LoadingIndicator from '../assets/icons/loadingindicator.vue'
 | 
			
		||||
import PlayIcon from '../assets/icons/play.vue'
 | 
			
		||||
import { audioVisualizer, checkAndRefreshSongResource } from '../utils'
 | 
			
		||||
 | 
			
		||||
const playQueueStore = usePlayQueueStore()
 | 
			
		||||
| 
						 | 
				
			
			@ -19,15 +18,20 @@ const player = useTemplateRef('playerRef')
 | 
			
		|||
console.log('[Player] 检查 store 方法:', {
 | 
			
		||||
	preloadNext: typeof playQueueStore.preloadNext,
 | 
			
		||||
	getPreloadedAudio: typeof playQueueStore.getPreloadedAudio,
 | 
			
		||||
	clearPreloadedAudio: typeof playQueueStore.clearPreloadedAudio
 | 
			
		||||
	clearPreloadedAudio: typeof playQueueStore.clearPreloadedAudio,
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 获取当前歌曲的计算属性
 | 
			
		||||
const currentTrack = computed(() => {
 | 
			
		||||
	if (playQueueStore.playMode.shuffle && playQueueStore.shuffleList.length > 0) {
 | 
			
		||||
		return playQueueStore.list[playQueueStore.shuffleList[playQueueStore.currentIndex]]
 | 
			
		||||
	if (
 | 
			
		||||
		playQueueStore.playMode.shuffle &&
 | 
			
		||||
		playQueueStore.shuffleList.length > 0
 | 
			
		||||
	) {
 | 
			
		||||
		return playQueueStore.list[
 | 
			
		||||
			playQueueStore.shuffleList[playQueueStore.currentIndex]
 | 
			
		||||
		]
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	return playQueueStore.list[playQueueStore.currentIndex]
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -37,114 +41,132 @@ const currentAudioSrc = computed(() => {
 | 
			
		|||
	return track ? track.song.sourceUrl : ''
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
watch(() => playQueueStore.isPlaying, (newValue) => {
 | 
			
		||||
	if (newValue) {
 | 
			
		||||
		player.value?.play()
 | 
			
		||||
		setMetadata()
 | 
			
		||||
	}
 | 
			
		||||
	else { player.value?.pause() }
 | 
			
		||||
})
 | 
			
		||||
watch(
 | 
			
		||||
	() => playQueueStore.isPlaying,
 | 
			
		||||
	(newValue) => {
 | 
			
		||||
		if (newValue) {
 | 
			
		||||
			player.value?.play()
 | 
			
		||||
			setMetadata()
 | 
			
		||||
		} else {
 | 
			
		||||
			player.value?.pause()
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 监听当前索引变化,处理预加载逻辑
 | 
			
		||||
watch(() => playQueueStore.currentIndex, async () => {
 | 
			
		||||
	console.log('[Player] 当前索引变化:', playQueueStore.currentIndex)
 | 
			
		||||
watch(
 | 
			
		||||
	() => playQueueStore.currentIndex,
 | 
			
		||||
	async () => {
 | 
			
		||||
		console.log('[Player] 当前索引变化:', playQueueStore.currentIndex)
 | 
			
		||||
 | 
			
		||||
	// 检查是否可以使用预加载的音频
 | 
			
		||||
	const track = currentTrack.value
 | 
			
		||||
	if (track) {
 | 
			
		||||
		const songId = track.song.cid
 | 
			
		||||
		// 检查是否可以使用预加载的音频
 | 
			
		||||
		const track = currentTrack.value
 | 
			
		||||
		if (track) {
 | 
			
		||||
			const songId = track.song.cid
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			// 首先检查和刷新当前歌曲的资源
 | 
			
		||||
			console.log('[Player] 检查当前歌曲资源:', track.song.name)
 | 
			
		||||
			const updatedSong = await checkAndRefreshSongResource(
 | 
			
		||||
				track.song,
 | 
			
		||||
				(updated) => {
 | 
			
		||||
					// 更新播放队列中的歌曲信息
 | 
			
		||||
					if (playQueueStore.list[playQueueStore.currentIndex]) {
 | 
			
		||||
						playQueueStore.list[playQueueStore.currentIndex].song = updated
 | 
			
		||||
			try {
 | 
			
		||||
				// 首先检查和刷新当前歌曲的资源
 | 
			
		||||
				console.log('[Player] 检查当前歌曲资源:', track.song.name)
 | 
			
		||||
				const updatedSong = await checkAndRefreshSongResource(
 | 
			
		||||
					track.song,
 | 
			
		||||
					(updated) => {
 | 
			
		||||
						// 更新播放队列中的歌曲信息
 | 
			
		||||
						// 在随机播放模式下,currentIndex 是 shuffleList 的索引
 | 
			
		||||
						// 需要通过 shuffleList[currentIndex] 获取实际的 list 索引
 | 
			
		||||
						const actualIndex =
 | 
			
		||||
							playQueueStore.playMode.shuffle &&
 | 
			
		||||
							playQueueStore.shuffleList.length > 0
 | 
			
		||||
								? playQueueStore.shuffleList[playQueueStore.currentIndex]
 | 
			
		||||
								: playQueueStore.currentIndex
 | 
			
		||||
						if (playQueueStore.list[actualIndex]) {
 | 
			
		||||
							playQueueStore.list[actualIndex].song = updated
 | 
			
		||||
						}
 | 
			
		||||
						// 如果歌曲在收藏夹中,也更新收藏夹
 | 
			
		||||
						favourites.updateSongInFavourites(songId, updated)
 | 
			
		||||
					},
 | 
			
		||||
				)
 | 
			
		||||
 | 
			
		||||
				// 使用更新后的歌曲信息
 | 
			
		||||
				const preloadedAudio = playQueueStore.getPreloadedAudio(songId)
 | 
			
		||||
 | 
			
		||||
				if (preloadedAudio && updatedSong.sourceUrl === track.song.sourceUrl) {
 | 
			
		||||
					console.log(`[Player] 使用预加载的音频: ${track.song.name}`)
 | 
			
		||||
 | 
			
		||||
					// 直接使用预加载的音频数据
 | 
			
		||||
					if (player.value) {
 | 
			
		||||
						// 复制预加载音频的状态到主播放器
 | 
			
		||||
						player.value.src = preloadedAudio.src
 | 
			
		||||
						player.value.currentTime = 0
 | 
			
		||||
 | 
			
		||||
						// 清理使用过的预加载音频
 | 
			
		||||
						playQueueStore.clearPreloadedAudio(songId)
 | 
			
		||||
 | 
			
		||||
						// 如果正在播放状态,立即播放
 | 
			
		||||
						if (playQueueStore.isPlaying) {
 | 
			
		||||
							await nextTick()
 | 
			
		||||
							player.value.play().catch(console.error)
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						playQueueStore.isBuffering = false
 | 
			
		||||
					}
 | 
			
		||||
					// 如果歌曲在收藏夹中,也更新收藏夹
 | 
			
		||||
					favourites.updateSongInFavourites(songId, updated)
 | 
			
		||||
				}
 | 
			
		||||
			)
 | 
			
		||||
				} else {
 | 
			
		||||
					console.log(`[Player] 正常加载音频: ${track.song.name}`)
 | 
			
		||||
					playQueueStore.isBuffering = true
 | 
			
		||||
 | 
			
		||||
			// 使用更新后的歌曲信息
 | 
			
		||||
			const preloadedAudio = playQueueStore.getPreloadedAudio(songId)
 | 
			
		||||
 | 
			
		||||
			if (preloadedAudio && updatedSong.sourceUrl === track.song.sourceUrl) {
 | 
			
		||||
				console.log(`[Player] 使用预加载的音频: ${track.song.name}`)
 | 
			
		||||
 | 
			
		||||
				// 直接使用预加载的音频数据
 | 
			
		||||
				if (player.value) {
 | 
			
		||||
					// 复制预加载音频的状态到主播放器
 | 
			
		||||
					player.value.src = preloadedAudio.src
 | 
			
		||||
					player.value.currentTime = 0
 | 
			
		||||
 | 
			
		||||
					// 清理使用过的预加载音频
 | 
			
		||||
					playQueueStore.clearPreloadedAudio(songId)
 | 
			
		||||
 | 
			
		||||
					// 如果正在播放状态,立即播放
 | 
			
		||||
					if (playQueueStore.isPlaying) {
 | 
			
		||||
						await nextTick()
 | 
			
		||||
						player.value.play().catch(console.error)
 | 
			
		||||
					// 如果资源地址已更新,清除旧的预加载音频
 | 
			
		||||
					if (updatedSong.sourceUrl !== track.song.sourceUrl) {
 | 
			
		||||
						playQueueStore.clearPreloadedAudio(songId)
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					playQueueStore.isBuffering = false
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				console.log(`[Player] 正常加载音频: ${track.song.name}`)
 | 
			
		||||
			} catch (error) {
 | 
			
		||||
				console.error('[Player] 处理预加载音频时出错:', error)
 | 
			
		||||
				playQueueStore.isBuffering = true
 | 
			
		||||
				
 | 
			
		||||
				// 如果资源地址已更新,清除旧的预加载音频
 | 
			
		||||
				if (updatedSong.sourceUrl !== track.song.sourceUrl) {
 | 
			
		||||
					playQueueStore.clearPreloadedAudio(songId)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		setMetadata()
 | 
			
		||||
 | 
			
		||||
		// 延迟预加载下一首歌,避免影响当前歌曲加载
 | 
			
		||||
		setTimeout(async () => {
 | 
			
		||||
			try {
 | 
			
		||||
				console.log('[Player] 尝试预加载下一首歌')
 | 
			
		||||
 | 
			
		||||
				// 检查函数是否存在
 | 
			
		||||
				if (typeof playQueueStore.preloadNext === 'function') {
 | 
			
		||||
					await playQueueStore.preloadNext()
 | 
			
		||||
 | 
			
		||||
					// 预加载完成后,检查播放队列是否有更新,同步到收藏夹
 | 
			
		||||
					playQueueStore.list.forEach((item) => {
 | 
			
		||||
						if (favourites.isFavourite(item.song.cid)) {
 | 
			
		||||
							favourites.updateSongInFavourites(item.song.cid, item.song)
 | 
			
		||||
						}
 | 
			
		||||
					})
 | 
			
		||||
 | 
			
		||||
					playQueueStore.limitPreloadCache()
 | 
			
		||||
				} else {
 | 
			
		||||
					console.error('[Player] preloadNext 不是一个函数')
 | 
			
		||||
				}
 | 
			
		||||
			} catch (error) {
 | 
			
		||||
				console.error('[Player] 预加载失败:', error)
 | 
			
		||||
			}
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			console.error('[Player] 处理预加载音频时出错:', error)
 | 
			
		||||
			playQueueStore.isBuffering = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setMetadata()
 | 
			
		||||
 | 
			
		||||
	// 延迟预加载下一首歌,避免影响当前歌曲加载
 | 
			
		||||
	setTimeout(async () => {
 | 
			
		||||
		try {
 | 
			
		||||
			console.log('[Player] 尝试预加载下一首歌')
 | 
			
		||||
 | 
			
		||||
			// 检查函数是否存在
 | 
			
		||||
			if (typeof playQueueStore.preloadNext === 'function') {
 | 
			
		||||
				await playQueueStore.preloadNext()
 | 
			
		||||
				
 | 
			
		||||
				// 预加载完成后,检查播放队列是否有更新,同步到收藏夹
 | 
			
		||||
				playQueueStore.list.forEach(item => {
 | 
			
		||||
					if (favourites.isFavourite(item.song.cid)) {
 | 
			
		||||
						favourites.updateSongInFavourites(item.song.cid, item.song)
 | 
			
		||||
					}
 | 
			
		||||
				})
 | 
			
		||||
				
 | 
			
		||||
				playQueueStore.limitPreloadCache()
 | 
			
		||||
			} else {
 | 
			
		||||
				console.error('[Player] preloadNext 不是一个函数')
 | 
			
		||||
			}
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			console.error('[Player] 预加载失败:', error)
 | 
			
		||||
		}
 | 
			
		||||
	}, 1000)
 | 
			
		||||
})
 | 
			
		||||
		}, 1000)
 | 
			
		||||
	},
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
function artistsOrganize(list: string[]) {
 | 
			
		||||
	if (list.length === 0) { return '未知音乐人' }
 | 
			
		||||
	return list.map((artist) => {
 | 
			
		||||
		return artist
 | 
			
		||||
	}).join(' / ')
 | 
			
		||||
	if (list.length === 0) {
 | 
			
		||||
		return '未知音乐人'
 | 
			
		||||
	}
 | 
			
		||||
	return list
 | 
			
		||||
		.map((artist) => {
 | 
			
		||||
			return artist
 | 
			
		||||
		})
 | 
			
		||||
		.join(' / ')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function setMetadata() {
 | 
			
		||||
	if ('mediaSession' in navigator) {
 | 
			
		||||
		let current = currentTrack.value
 | 
			
		||||
		const current = currentTrack.value
 | 
			
		||||
		if (!current) return
 | 
			
		||||
 | 
			
		||||
		navigator.mediaSession.metadata = new MediaMetadata({
 | 
			
		||||
| 
						 | 
				
			
			@ -152,8 +174,12 @@ function setMetadata() {
 | 
			
		|||
			artist: artistsOrganize(current.song.artists ?? []),
 | 
			
		||||
			album: current.album?.name,
 | 
			
		||||
			artwork: [
 | 
			
		||||
				{ src: current.album?.coverUrl ?? '', sizes: '500x500', type: 'image/png' },
 | 
			
		||||
			]
 | 
			
		||||
				{
 | 
			
		||||
					src: current.album?.coverUrl ?? '',
 | 
			
		||||
					sizes: '500x500',
 | 
			
		||||
					type: 'image/png',
 | 
			
		||||
				},
 | 
			
		||||
			],
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		navigator.mediaSession.setActionHandler('previoustrack', playPrevious)
 | 
			
		||||
| 
						 | 
				
			
			@ -163,16 +189,21 @@ function setMetadata() {
 | 
			
		|||
		playQueueStore.currentTime = player.value?.currentTime ?? 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	watch(() => playQueueStore.updatedCurrentTime, (newValue) => {
 | 
			
		||||
		if (newValue === null) { return }
 | 
			
		||||
		if (player.value) player.value.currentTime = newValue
 | 
			
		||||
		playQueueStore.updatedCurrentTime = null
 | 
			
		||||
	})
 | 
			
		||||
	watch(
 | 
			
		||||
		() => playQueueStore.updatedCurrentTime,
 | 
			
		||||
		(newValue) => {
 | 
			
		||||
			if (newValue === null) {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			if (player.value) player.value.currentTime = newValue
 | 
			
		||||
			playQueueStore.updatedCurrentTime = null
 | 
			
		||||
		},
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function playNext() {
 | 
			
		||||
	if (playQueueStore.currentIndex === playQueueStore.list.length - 1) {
 | 
			
		||||
		console.log("at the bottom, pause")
 | 
			
		||||
		console.log('at the bottom, pause')
 | 
			
		||||
		playQueueStore.currentIndex = 0
 | 
			
		||||
		if (playQueueStore.playMode.repeat === 'all') {
 | 
			
		||||
			playQueueStore.currentIndex = 0
 | 
			
		||||
| 
						 | 
				
			
			@ -188,11 +219,17 @@ function playNext() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function playPrevious() {
 | 
			
		||||
	if (player.value && (player.value.currentTime ?? 0) < 5 && playQueueStore.currentIndex > 0) {
 | 
			
		||||
	if (
 | 
			
		||||
		player.value &&
 | 
			
		||||
		(player.value.currentTime ?? 0) < 5 &&
 | 
			
		||||
		playQueueStore.currentIndex > 0
 | 
			
		||||
	) {
 | 
			
		||||
		playQueueStore.currentIndex--
 | 
			
		||||
		playQueueStore.isPlaying = true
 | 
			
		||||
	} else {
 | 
			
		||||
		if (player.value) { player.value.currentTime = 0 }
 | 
			
		||||
		if (player.value) {
 | 
			
		||||
			player.value.currentTime = 0
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -209,8 +246,10 @@ function updateCurrentTime() {
 | 
			
		|||
		const preloadTrigger = (config.preloadTrigger || 50) / 100 // 转换为小数
 | 
			
		||||
		const remainingTimeThreshold = config.remainingTimeThreshold || 30
 | 
			
		||||
 | 
			
		||||
		if ((progress > preloadTrigger || remainingTime < remainingTimeThreshold) && !playQueueStore.isPreloading) {
 | 
			
		||||
 | 
			
		||||
		if (
 | 
			
		||||
			(progress > preloadTrigger || remainingTime < remainingTimeThreshold) &&
 | 
			
		||||
			!playQueueStore.isPreloading
 | 
			
		||||
		) {
 | 
			
		||||
			try {
 | 
			
		||||
				if (typeof playQueueStore.preloadNext === 'function') {
 | 
			
		||||
					playQueueStore.preloadNext()
 | 
			
		||||
| 
						 | 
				
			
			@ -232,107 +271,129 @@ const { barHeights, connectAudio, isAnalyzing, error } = audioVisualizer({
 | 
			
		|||
	bassBoost: 0.8,
 | 
			
		||||
	midBoost: 1.2,
 | 
			
		||||
	trebleBoost: 1.4,
 | 
			
		||||
	threshold: 0
 | 
			
		||||
	threshold: 0,
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
console.log('[Player] audioVisualizer 返回值:', { barHeights: barHeights.value, isAnalyzing: isAnalyzing.value })
 | 
			
		||||
console.log('[Player] audioVisualizer 返回值:', {
 | 
			
		||||
	barHeights: barHeights.value,
 | 
			
		||||
	isAnalyzing: isAnalyzing.value,
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 监听播放列表变化
 | 
			
		||||
watch(() => playQueueStore.list.length, async (newLength) => {
 | 
			
		||||
	console.log('[Player] 播放列表长度变化:', newLength)
 | 
			
		||||
	if (newLength === 0) {
 | 
			
		||||
		console.log('[Player] 播放列表为空,跳过连接')
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 等待下一帧,确保 audio 元素已经渲染
 | 
			
		||||
	await nextTick()
 | 
			
		||||
 | 
			
		||||
	if (player.value) {
 | 
			
		||||
		console.log('[Player] 连接音频元素到可视化器')
 | 
			
		||||
		console.log('[Player] 音频元素状态:', {
 | 
			
		||||
			src: player.value.src?.substring(0, 50) + '...',
 | 
			
		||||
			readyState: player.value.readyState,
 | 
			
		||||
			paused: player.value.paused
 | 
			
		||||
		})
 | 
			
		||||
		connectAudio(player.value)
 | 
			
		||||
	} else {
 | 
			
		||||
		console.log('[Player] ❌ 音频元素不存在')
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	playQueueStore.visualizer = barHeights.value
 | 
			
		||||
 | 
			
		||||
	// 开始预加载第一首歌的下一首
 | 
			
		||||
	setTimeout(() => {
 | 
			
		||||
		playQueueStore.preloadNext()
 | 
			
		||||
	}, 2000)
 | 
			
		||||
 | 
			
		||||
	// 初始化音量
 | 
			
		||||
	if (player.value) {
 | 
			
		||||
		initializeVolume()
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 监听音频元素变化
 | 
			
		||||
watch(() => player.value, (audioElement) => {
 | 
			
		||||
	if (audioElement && playQueueStore.list.length > 0) {
 | 
			
		||||
		connectAudio(audioElement)
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 监听可视化器数据变化
 | 
			
		||||
watch(() => barHeights.value, (newHeights) => {
 | 
			
		||||
	playQueueStore.visualizer = newHeights
 | 
			
		||||
}, { deep: true })
 | 
			
		||||
 | 
			
		||||
// 监听错误
 | 
			
		||||
watch(() => error.value, (newError) => {
 | 
			
		||||
	if (newError) {
 | 
			
		||||
		console.error('[Player] 可视化器错误:', newError)
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 切换播放模式
 | 
			
		||||
watch(() => playQueueStore.playMode.shuffle, (isShuffle) => {
 | 
			
		||||
	if (isShuffle) {
 | 
			
		||||
		const currentIndex = playQueueStore.currentIndex
 | 
			
		||||
		const trackCount = playQueueStore.list.length
 | 
			
		||||
 | 
			
		||||
		// 1. 已播放部分:不变
 | 
			
		||||
		let shuffledList = [...Array(currentIndex).keys()]
 | 
			
		||||
 | 
			
		||||
		// 2. 构建待打乱的列表
 | 
			
		||||
		let shuffleSpace = [...Array(trackCount).keys()].filter(index =>
 | 
			
		||||
			playQueueStore.shuffleCurrent ? index >= currentIndex : index > currentIndex
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
		// 3. 随机打乱
 | 
			
		||||
		shuffleSpace.sort(() => Math.random() - 0.5)
 | 
			
		||||
 | 
			
		||||
		// 4. 如果当前曲目不参与打乱,插入回当前位置(即 currentIndex 处)
 | 
			
		||||
		if (!playQueueStore.shuffleCurrent) {
 | 
			
		||||
			shuffledList.push(currentIndex)
 | 
			
		||||
watch(
 | 
			
		||||
	() => playQueueStore.list.length,
 | 
			
		||||
	async (newLength) => {
 | 
			
		||||
		console.log('[Player] 播放列表长度变化:', newLength)
 | 
			
		||||
		if (newLength === 0) {
 | 
			
		||||
			console.log('[Player] 播放列表为空,跳过连接')
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 5. 拼接:已播放部分 + 当前(可选)+ 打乱后的剩余部分
 | 
			
		||||
		shuffledList = shuffledList.concat(shuffleSpace)
 | 
			
		||||
		// 等待下一帧,确保 audio 元素已经渲染
 | 
			
		||||
		await nextTick()
 | 
			
		||||
 | 
			
		||||
		// 6. 应用 shuffleList
 | 
			
		||||
		playQueueStore.shuffleList = shuffledList
 | 
			
		||||
		if (player.value) {
 | 
			
		||||
			console.log('[Player] 连接音频元素到可视化器')
 | 
			
		||||
			console.log('[Player] 音频元素状态:', {
 | 
			
		||||
				src: player.value.src?.substring(0, 50) + '...',
 | 
			
		||||
				readyState: player.value.readyState,
 | 
			
		||||
				paused: player.value.paused,
 | 
			
		||||
			})
 | 
			
		||||
			connectAudio(player.value)
 | 
			
		||||
		} else {
 | 
			
		||||
			console.log('[Player] ❌ 音频元素不存在')
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 清除 shuffleCurrent 状态
 | 
			
		||||
		playQueueStore.shuffleCurrent = undefined
 | 
			
		||||
	} else {
 | 
			
		||||
		// 退出随机播放:恢复当前播放曲目的原索引
 | 
			
		||||
		playQueueStore.currentIndex = playQueueStore.shuffleList[playQueueStore.currentIndex]
 | 
			
		||||
	}
 | 
			
		||||
		playQueueStore.visualizer = barHeights.value
 | 
			
		||||
 | 
			
		||||
	// 切换播放模式后重新预加载
 | 
			
		||||
	setTimeout(() => {
 | 
			
		||||
		playQueueStore.clearAllPreloadedAudio()
 | 
			
		||||
		playQueueStore.preloadNext()
 | 
			
		||||
	}, 500)
 | 
			
		||||
})
 | 
			
		||||
		// 开始预加载第一首歌的下一首
 | 
			
		||||
		setTimeout(() => {
 | 
			
		||||
			playQueueStore.preloadNext()
 | 
			
		||||
		}, 2000)
 | 
			
		||||
 | 
			
		||||
		// 初始化音量
 | 
			
		||||
		if (player.value) {
 | 
			
		||||
			initializeVolume()
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 监听音频元素变化
 | 
			
		||||
watch(
 | 
			
		||||
	() => player.value,
 | 
			
		||||
	(audioElement) => {
 | 
			
		||||
		if (audioElement && playQueueStore.list.length > 0) {
 | 
			
		||||
			connectAudio(audioElement)
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 监听可视化器数据变化
 | 
			
		||||
watch(
 | 
			
		||||
	() => barHeights.value,
 | 
			
		||||
	(newHeights) => {
 | 
			
		||||
		playQueueStore.visualizer = newHeights
 | 
			
		||||
	},
 | 
			
		||||
	{ deep: true },
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 监听错误
 | 
			
		||||
watch(
 | 
			
		||||
	() => error.value,
 | 
			
		||||
	(newError) => {
 | 
			
		||||
		if (newError) {
 | 
			
		||||
			console.error('[Player] 可视化器错误:', newError)
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 切换播放模式
 | 
			
		||||
watch(
 | 
			
		||||
	() => playQueueStore.playMode.shuffle,
 | 
			
		||||
	(isShuffle) => {
 | 
			
		||||
		if (isShuffle) {
 | 
			
		||||
			const currentIndex = playQueueStore.currentIndex
 | 
			
		||||
			const trackCount = playQueueStore.list.length
 | 
			
		||||
 | 
			
		||||
			// 1. 已播放部分:不变
 | 
			
		||||
			let shuffledList = [...Array(currentIndex).keys()]
 | 
			
		||||
 | 
			
		||||
			// 2. 构建待打乱的列表
 | 
			
		||||
			const shuffleSpace = [...Array(trackCount).keys()].filter((index) =>
 | 
			
		||||
				playQueueStore.shuffleCurrent
 | 
			
		||||
					? index >= currentIndex
 | 
			
		||||
					: index > currentIndex,
 | 
			
		||||
			)
 | 
			
		||||
 | 
			
		||||
			// 3. 随机打乱
 | 
			
		||||
			shuffleSpace.sort(() => Math.random() - 0.5)
 | 
			
		||||
 | 
			
		||||
			// 4. 如果当前曲目不参与打乱,插入回当前位置(即 currentIndex 处)
 | 
			
		||||
			if (!playQueueStore.shuffleCurrent) {
 | 
			
		||||
				shuffledList.push(currentIndex)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// 5. 拼接:已播放部分 + 当前(可选)+ 打乱后的剩余部分
 | 
			
		||||
			shuffledList = shuffledList.concat(shuffleSpace)
 | 
			
		||||
 | 
			
		||||
			// 6. 应用 shuffleList
 | 
			
		||||
			playQueueStore.shuffleList = shuffledList
 | 
			
		||||
 | 
			
		||||
			// 清除 shuffleCurrent 状态
 | 
			
		||||
			playQueueStore.shuffleCurrent = undefined
 | 
			
		||||
		} else {
 | 
			
		||||
			// 退出随机播放:恢复当前播放曲目的原索引
 | 
			
		||||
			playQueueStore.currentIndex =
 | 
			
		||||
				playQueueStore.shuffleList[playQueueStore.currentIndex]
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 切换播放模式后重新预加载
 | 
			
		||||
		setTimeout(() => {
 | 
			
		||||
			playQueueStore.clearAllPreloadedAudio()
 | 
			
		||||
			playQueueStore.preloadNext()
 | 
			
		||||
		}, 500)
 | 
			
		||||
	},
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
function getCurrentTrack() {
 | 
			
		||||
	return currentTrack.value
 | 
			
		||||
| 
						 | 
				
			
			@ -343,7 +404,7 @@ function initializeVolume() {
 | 
			
		|||
	if (player.value) {
 | 
			
		||||
		const savedVolume = localStorage.getItem('audioVolume')
 | 
			
		||||
		if (savedVolume) {
 | 
			
		||||
			const volumeValue = parseFloat(savedVolume)
 | 
			
		||||
			const volumeValue = Number.parseFloat(savedVolume)
 | 
			
		||||
			player.value.volume = volumeValue
 | 
			
		||||
			console.log('[Player] 初始化音量:', volumeValue)
 | 
			
		||||
		} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -369,7 +430,7 @@ function syncVolumeFromStorage() {
 | 
			
		|||
	if (player.value) {
 | 
			
		||||
		const savedVolume = localStorage.getItem('audioVolume')
 | 
			
		||||
		if (savedVolume) {
 | 
			
		||||
			const volumeValue = parseFloat(savedVolume)
 | 
			
		||||
			const volumeValue = Number.parseFloat(savedVolume)
 | 
			
		||||
			if (player.value.volume !== volumeValue) {
 | 
			
		||||
				player.value.volume = volumeValue
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
import { defineStore } from "pinia"
 | 
			
		||||
import { ref, computed } from "vue"
 | 
			
		||||
import { checkAndRefreshSongResource } from "../utils"
 | 
			
		||||
import { defineStore } from 'pinia'
 | 
			
		||||
import { computed, ref } from 'vue'
 | 
			
		||||
import { checkAndRefreshSongResource } from '../utils'
 | 
			
		||||
 | 
			
		||||
export const usePlayQueueStore = defineStore('queue', () => {
 | 
			
		||||
	const list = ref<QueueItem[]>([])
 | 
			
		||||
| 
						 | 
				
			
			@ -14,11 +14,11 @@ export const usePlayQueueStore = defineStore('queue', () => {
 | 
			
		|||
	const visualizer = ref<number[]>([0, 0, 0, 0, 0, 0])
 | 
			
		||||
	const shuffleList = ref<number[]>([])
 | 
			
		||||
	const playMode = ref<{
 | 
			
		||||
		shuffle: boolean,
 | 
			
		||||
		shuffle: boolean
 | 
			
		||||
		repeat: 'off' | 'single' | 'all'
 | 
			
		||||
	}>({
 | 
			
		||||
		shuffle: false,
 | 
			
		||||
		repeat: 'off'
 | 
			
		||||
		repeat: 'off',
 | 
			
		||||
	})
 | 
			
		||||
	const shuffleCurrent = ref<boolean | undefined>(undefined)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36,10 +36,13 @@ export const usePlayQueueStore = defineStore('queue', () => {
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		if (playMode.value.shuffle && shuffleList.value.length > 0) {
 | 
			
		||||
			const currentShuffleIndex = shuffleList.value.indexOf(currentIndex.value)
 | 
			
		||||
			// 当前在 shuffleList 中的位置
 | 
			
		||||
			const currentShuffleIndex = currentIndex.value
 | 
			
		||||
			if (currentShuffleIndex < shuffleList.value.length - 1) {
 | 
			
		||||
				// 返回下一个位置对应的原始 list 索引
 | 
			
		||||
				return shuffleList.value[currentShuffleIndex + 1]
 | 
			
		||||
			} else if (playMode.value.repeat === 'all') {
 | 
			
		||||
				// 返回第一个位置对应的原始 list 索引
 | 
			
		||||
				return shuffleList.value[0]
 | 
			
		||||
			}
 | 
			
		||||
			return -1
 | 
			
		||||
| 
						 | 
				
			
			@ -56,19 +59,14 @@ export const usePlayQueueStore = defineStore('queue', () => {
 | 
			
		|||
 | 
			
		||||
	// 预加载下一首歌
 | 
			
		||||
	const preloadNext = async () => {
 | 
			
		||||
 | 
			
		||||
		const nextIndex = getNextIndex.value
 | 
			
		||||
		if (nextIndex === -1) {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 获取下一首歌曲对象
 | 
			
		||||
		let nextSong
 | 
			
		||||
		if (playMode.value.shuffle && shuffleList.value.length > 0) {
 | 
			
		||||
			nextSong = list.value[shuffleList.value[nextIndex]]
 | 
			
		||||
		} else {
 | 
			
		||||
			nextSong = list.value[nextIndex]
 | 
			
		||||
		}
 | 
			
		||||
		// nextIndex 已经是原始 list 中的索引
 | 
			
		||||
		const nextSong = list.value[nextIndex]
 | 
			
		||||
 | 
			
		||||
		if (!nextSong || !nextSong.song) {
 | 
			
		||||
			return
 | 
			
		||||
| 
						 | 
				
			
			@ -96,18 +94,16 @@ export const usePlayQueueStore = defineStore('queue', () => {
 | 
			
		|||
				nextSong.song,
 | 
			
		||||
				(updated) => {
 | 
			
		||||
					// 更新播放队列中的歌曲信息
 | 
			
		||||
					const actualIndex = playMode.value.shuffle && shuffleList.value.length > 0 
 | 
			
		||||
						? shuffleList.value[nextIndex] 
 | 
			
		||||
						: nextIndex
 | 
			
		||||
					if (list.value[actualIndex]) {
 | 
			
		||||
						list.value[actualIndex].song = updated
 | 
			
		||||
					// nextIndex 已经是原始 list 中的索引
 | 
			
		||||
					if (list.value[nextIndex]) {
 | 
			
		||||
						list.value[nextIndex].song = updated
 | 
			
		||||
					}
 | 
			
		||||
					
 | 
			
		||||
 | 
			
		||||
					// 如果歌曲在收藏夹中,也更新收藏夹
 | 
			
		||||
					// 注意:这里不直接导入 favourites store 以避免循环依赖
 | 
			
		||||
					// 改为触发一个事件或者在调用方处理
 | 
			
		||||
					console.log('[Store] 预加载时需要更新收藏夹:', updated.name)
 | 
			
		||||
				}
 | 
			
		||||
				},
 | 
			
		||||
			)
 | 
			
		||||
 | 
			
		||||
			const audio = new Audio()
 | 
			
		||||
| 
						 | 
				
			
			@ -140,7 +136,6 @@ export const usePlayQueueStore = defineStore('queue', () => {
 | 
			
		|||
 | 
			
		||||
			// 使用更新后的音频源
 | 
			
		||||
			audio.src = updatedSong.sourceUrl!
 | 
			
		||||
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			console.error('[Store] 预加载过程出错:', error)
 | 
			
		||||
			isPreloading.value = false
 | 
			
		||||
| 
						 | 
				
			
			@ -190,7 +185,7 @@ export const usePlayQueueStore = defineStore('queue', () => {
 | 
			
		|||
			progress: preloadProgress.value,
 | 
			
		||||
			cacheSize: preloadedAudio.value.size,
 | 
			
		||||
			cachedSongs: Array.from(preloadedAudio.value.keys()),
 | 
			
		||||
			nextIndex: getNextIndex.value
 | 
			
		||||
			nextIndex: getNextIndex.value,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -217,6 +212,6 @@ export const usePlayQueueStore = defineStore('queue', () => {
 | 
			
		|||
		clearPreloadedAudio,
 | 
			
		||||
		clearAllPreloadedAudio,
 | 
			
		||||
		limitPreloadCache,
 | 
			
		||||
		debugPreloadState
 | 
			
		||||
		debugPreloadState,
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user