feat: 跳转至下一首功能
This commit is contained in:
parent
024a84b2eb
commit
61a99975b2
|
@ -7,6 +7,7 @@ import apis from '../apis'
|
|||
const playQueue = usePlayQueueStore()
|
||||
|
||||
const resourcesUrl = ref<{ [key: string]: string }>({})
|
||||
const audioRefs = ref<{ [key: string]: HTMLAudioElement }>({}) // audio 元素的引用
|
||||
|
||||
// 监听播放列表变化
|
||||
watch(() => playQueue.queue, async () => {
|
||||
|
@ -20,9 +21,10 @@ watch(() => playQueue.queue, async () => {
|
|||
resourcesUrl.value = newResourcesUrl
|
||||
})
|
||||
|
||||
// 在播放曲目变动时,将元数据更新到浏览器和操作系统中
|
||||
watch(() => playQueue.currentTrack, async () => {
|
||||
watch(() => playQueue.currentTrack, async (newTrack, oldTrack) => {
|
||||
if (!playQueue.currentTrack) return
|
||||
|
||||
// 更新元数据
|
||||
navigator.mediaSession.metadata = new MediaMetadata({
|
||||
title: playQueue.currentTrack.song.name,
|
||||
artist: artistsOrganize(playQueue.currentTrack.song.artists ?? []),
|
||||
|
@ -35,6 +37,30 @@ watch(() => playQueue.currentTrack, async () => {
|
|||
},
|
||||
],
|
||||
})
|
||||
navigator.mediaSession.setActionHandler('previoustrack', () => {})
|
||||
navigator.mediaSession.setActionHandler('nexttrack', playQueue.skipToNext)
|
||||
|
||||
// 如果目前歌曲变动时正在播放,则激活对应的 audio 组件,并将播放时间进度重置为零
|
||||
if (!playQueue.isPlaying) return
|
||||
debugPlayer("正在播放,变更至下一首歌")
|
||||
if (oldTrack) {
|
||||
const oldAudio = getAudioElement(oldTrack.song.cid)
|
||||
if (oldAudio && !oldAudio.paused) {
|
||||
oldAudio.pause()
|
||||
}
|
||||
}
|
||||
|
||||
const newAudio = getAudioElement(newTrack.song.cid)
|
||||
if (newAudio) {
|
||||
try {
|
||||
await newAudio.play()
|
||||
debugPlayer(`开始播放: audio-${newTrack.song.cid}`)
|
||||
} catch (error) {
|
||||
console.error(`播放失败: audio-${newTrack.song.cid}`, error)
|
||||
}
|
||||
} else {
|
||||
console.warn(`找不到音频元素: audio-${newTrack.song.cid}`)
|
||||
}
|
||||
})
|
||||
|
||||
// 优化音乐人字符串显示
|
||||
|
@ -65,6 +91,32 @@ function isAutoPlay(cid: string) {
|
|||
|
||||
return true
|
||||
}
|
||||
|
||||
// 获取 audio 元素的 ref
|
||||
function getAudioElement(cid: string): HTMLAudioElement | null {
|
||||
debugPlayer('Getting audio element for:', cid, audioRefs.value)
|
||||
return audioRefs.value[cid] || null
|
||||
}
|
||||
|
||||
// audio 元素结束播放事件
|
||||
function endOfPlay() {
|
||||
debugPlayer("结束播放")
|
||||
if (playQueue.loopingMode !== "single") {
|
||||
const next = playQueue.queue[playQueue.currentIndex + 1]
|
||||
debugPlayer(next.song.cid)
|
||||
debugPlayer(audioRefs.value[next.song.cid])
|
||||
audioRefs.value[next.song.cid].play()
|
||||
}
|
||||
}
|
||||
|
||||
function setAudioRef(cid: string, el: HTMLAudioElement | null) {
|
||||
if (el) {
|
||||
audioRefs.value[cid] = el
|
||||
debugPlayer(`Audio element for ${cid} registered`, el)
|
||||
} else {
|
||||
delete audioRefs.value[cid]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -74,9 +126,12 @@ function isAutoPlay(cid: string) {
|
|||
v-if="resourcesUrl[track.song.cid]"
|
||||
:src="resourcesUrl[track.song.cid]"
|
||||
preload="auto"
|
||||
:ref="`audio-${track.song.cid}`"
|
||||
:ref="el => setAudioRef(track.song.cid, el as HTMLAudioElement)"
|
||||
:autoplay="isAutoPlay(track.song.cid)"
|
||||
@ended="endOfPlay"
|
||||
@timeupdate=""
|
||||
/>
|
||||
{{track.song.cid}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import { debugStore } from '../utils/debug'
|
||||
|
||||
export const usePlayQueueStore = defineStore('queue', () => {
|
||||
// 内部状态
|
||||
|
@ -10,6 +11,7 @@ export const usePlayQueueStore = defineStore('queue', () => {
|
|||
const currentPlaying = ref(0) // 当前播放指针,指针在 queueOrder 中寻址(无论是否开启了随机播放)
|
||||
const queueOrder = ref<number[]>([]) // 播放队列顺序
|
||||
const isPlaying = ref(false)
|
||||
const playProgress = ref(0) // 当前曲目的播放时间指针
|
||||
|
||||
// 暴露给外部的响应式只读引用
|
||||
const queueState = computed(() =>
|
||||
|
@ -27,6 +29,9 @@ export const usePlayQueueStore = defineStore('queue', () => {
|
|||
return queue.value[actualIndex] || null
|
||||
})
|
||||
|
||||
// 获取当前播放时间
|
||||
const playProgressState = computed(() => playProgress.value)
|
||||
|
||||
// 获取当前是否正在播放
|
||||
const playingState = computed(() => isPlaying.value)
|
||||
|
||||
|
@ -62,7 +67,6 @@ export const usePlayQueueStore = defineStore('queue', () => {
|
|||
|
||||
/***********
|
||||
* 播放控制相关
|
||||
*
|
||||
**********/
|
||||
// 控制播放
|
||||
const togglePlay = (turnTo?: boolean) => {
|
||||
|
@ -71,6 +75,33 @@ export const usePlayQueueStore = defineStore('queue', () => {
|
|||
isPlaying.value = newPlayState
|
||||
}
|
||||
|
||||
// 跳转至队列的某首歌曲
|
||||
const toggleQueuePlay = (turnTo: number) => {
|
||||
if (turnTo < 0 || turnTo >= queue.value.length) return
|
||||
currentPlaying.value = turnTo
|
||||
}
|
||||
|
||||
// 跳至下一首(通常为用户点按下一首按钮)
|
||||
const skipToNext = () => {
|
||||
currentPlaying.value = currentPlaying.value + 1
|
||||
}
|
||||
|
||||
// 继续播放接下来的曲目
|
||||
// 通常为当前曲目播放完毕,需要通过循环模式判断应该重置进度或队列指针 +1
|
||||
const continueToNext = () => {
|
||||
debugStore(loopingMode.value)
|
||||
// TODO: 需要留意 progress seeking 相关
|
||||
if (loopingMode.value === 'single') playProgress.value = 0
|
||||
else currentPlaying.value = currentPlaying.value + 1
|
||||
}
|
||||
|
||||
// 回报播放进度
|
||||
const reportPlayProgress = (progress: number) => {
|
||||
debugStore(`进度更新回报: ${progress}`)
|
||||
playProgress.value = progress
|
||||
}
|
||||
|
||||
|
||||
/************
|
||||
* 播放模式相关
|
||||
**********/
|
||||
|
@ -81,7 +112,7 @@ export const usePlayQueueStore = defineStore('queue', () => {
|
|||
|
||||
if (newShuffleState === isShuffle.value) return // 状态未改变
|
||||
|
||||
// TODO: 进行洗牌
|
||||
// TODO: 进行洗牌(以下代码是 AI 写的,需要人工复查)
|
||||
/* if (newShuffleState) {
|
||||
// 开启随机播放:保存当前顺序并打乱
|
||||
const originalOrder = [...queueOrder.value]
|
||||
|
@ -149,11 +180,16 @@ export const usePlayQueueStore = defineStore('queue', () => {
|
|||
currentTrack,
|
||||
currentIndex: currentPlaying,
|
||||
isPlaying: playingState,
|
||||
playProgress: playProgressState,
|
||||
|
||||
// 修改方法
|
||||
replaceQueue,
|
||||
toggleShuffle,
|
||||
toggleLoop,
|
||||
togglePlay
|
||||
togglePlay,
|
||||
toggleQueuePlay,
|
||||
skipToNext,
|
||||
continueToNext,
|
||||
reportPlayProgress
|
||||
}
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue
Block a user