feat: 替换播放列表时重新播放一轮
This commit is contained in:
parent
03cd58b944
commit
ea8d31a49d
|
@ -150,8 +150,8 @@ async function playTheAlbum(from: number = 0) {
|
||||||
album: album.value,
|
album: album.value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
await playQueue.replaceQueue(newQueue)
|
playQueue.replaceQueue(newQueue)
|
||||||
await playState.togglePlay(true)
|
playState.togglePlay(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
function shuffle() {
|
function shuffle() {
|
||||||
|
|
|
@ -17,6 +17,7 @@ class WebAudioPlayer {
|
||||||
currentSource: AudioBufferSourceNode | null
|
currentSource: AudioBufferSourceNode | null
|
||||||
nextSource: AudioBufferSourceNode | null
|
nextSource: AudioBufferSourceNode | null
|
||||||
reportInterval: ReturnType<typeof setTimeout> | null
|
reportInterval: ReturnType<typeof setTimeout> | null
|
||||||
|
isInternalTrackChange: boolean
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.context = new window.AudioContext()
|
this.context = new window.AudioContext()
|
||||||
|
@ -25,6 +26,7 @@ class WebAudioPlayer {
|
||||||
this.currentSource = null
|
this.currentSource = null
|
||||||
this.nextSource = null
|
this.nextSource = null
|
||||||
this.reportInterval = null
|
this.reportInterval = null
|
||||||
|
this.isInternalTrackChange = false
|
||||||
|
|
||||||
// 创建一个隐藏的 HTML Audio 元素来帮助同步媒体会话状态
|
// 创建一个隐藏的 HTML Audio 元素来帮助同步媒体会话状态
|
||||||
this.dummyAudio = new Audio()
|
this.dummyAudio = new Audio()
|
||||||
|
@ -146,8 +148,8 @@ class WebAudioPlayer {
|
||||||
if (!playQueue.currentTrack) return
|
if (!playQueue.currentTrack) return
|
||||||
|
|
||||||
// 检查是否已经有音频在播放,避免重复播放
|
// 检查是否已经有音频在播放,避免重复播放
|
||||||
if (this.currentSource && playState.actualPlaying) {
|
if (this.currentSource && this.reportInterval) {
|
||||||
debugPlayer("已经在播放中,跳过")
|
debugPlayer("已经在播放中,跳过重复播放")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,16 +280,32 @@ class WebAudioPlayer {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 切换到下一首
|
// 3. 标记为内部切歌,避免 watch 重复触发
|
||||||
|
this.isInternalTrackChange = true
|
||||||
|
|
||||||
|
// 4. 切换到下一首
|
||||||
playQueue.continueToNext()
|
playQueue.continueToNext()
|
||||||
this.currentSource = this.nextSource
|
this.currentSource = this.nextSource
|
||||||
this.nextSource = null
|
this.nextSource = null
|
||||||
|
|
||||||
// 4. 重新计算时间轴并启动进度报告
|
// 5. 重新计算时间轴并启动进度报告
|
||||||
this.currentTrackStartTime = this.context.currentTime
|
this.currentTrackStartTime = this.context.currentTime
|
||||||
this.reportProgress()
|
this.reportProgress()
|
||||||
|
|
||||||
|
// 6. 为新的当前播放源设置 onended 处理程序
|
||||||
|
if (this.currentSource) {
|
||||||
|
this.currentSource.onended = () => {
|
||||||
|
debugPlayer("当前歌曲播放结束")
|
||||||
|
if (!!this.reportInterval) {
|
||||||
|
debugPlayer("歌曲自然结束")
|
||||||
|
this.onTrackEnded()
|
||||||
|
} else {
|
||||||
|
debugPlayer("用户暂停")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 5. 处理下下首
|
// 7. 处理下下首
|
||||||
if (playQueue.nextTrack) {
|
if (playQueue.nextTrack) {
|
||||||
debugPlayer("处理下下一首歌")
|
debugPlayer("处理下下一首歌")
|
||||||
if (this.audioBuffer[playQueue.nextTrack.song.cid]) {
|
if (this.audioBuffer[playQueue.nextTrack.song.cid]) {
|
||||||
|
@ -297,6 +315,11 @@ class WebAudioPlayer {
|
||||||
if (playState.actualPlaying) this.scheduleNextTrack()
|
if (playState.actualPlaying) this.scheduleNextTrack()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 8. 重置标记
|
||||||
|
setTimeout(() => {
|
||||||
|
this.isInternalTrackChange = false
|
||||||
|
}, 100)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,7 +338,7 @@ watch(() => playQueue.currentTrack, (newTrack, oldTrack) => {
|
||||||
navigator.mediaSession.playbackState = playState.isPlaying ? 'playing' : 'paused'
|
navigator.mediaSession.playbackState = playState.isPlaying ? 'playing' : 'paused'
|
||||||
navigator.mediaSession.metadata = new MediaMetadata({
|
navigator.mediaSession.metadata = new MediaMetadata({
|
||||||
title: newTrack.song.name,
|
title: newTrack.song.name,
|
||||||
artist: artistsOrganize(newTrack.song.artistes ?? []),
|
artist: artistsOrganize(newTrack.song.artistes ?? newTrack.song.artists ?? []),
|
||||||
album: newTrack.album?.name,
|
album: newTrack.album?.name,
|
||||||
artwork: [
|
artwork: [
|
||||||
{ src: newTrack.album?.coverUrl ?? "", sizes: '500x500', type: 'image/png' },
|
{ src: newTrack.album?.coverUrl ?? "", sizes: '500x500', type: 'image/png' },
|
||||||
|
@ -323,9 +346,9 @@ watch(() => playQueue.currentTrack, (newTrack, oldTrack) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果是自然切歌(onTrackEnded 触发的),不需要重新播放
|
// 如果是内部切歌(onTrackEnded 触发的),不需要重新播放
|
||||||
// 只有在用户主动切歌或首次播放时才调用 loadResourceAndPlay
|
// 只有在用户主动切歌或首次播放时才调用 loadResourceAndPlay
|
||||||
if (!playState.actualPlaying || !oldTrack) {
|
if (!playerInstance.value?.isInternalTrackChange) {
|
||||||
playerInstance.value?.loadResourceAndPlay()
|
playerInstance.value?.loadResourceAndPlay()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,6 +363,18 @@ watch(() => playState.isPlaying, () => {
|
||||||
playerInstance.value?.play()
|
playerInstance.value?.play()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(() => playQueue.queue, () => {
|
||||||
|
debugPlayer("检测到播放列表更新")
|
||||||
|
// 如果新列表是空的,那么代表用户选择彻底换一个新的播放列表进行播放
|
||||||
|
if (playQueue.queue.length === 0) {
|
||||||
|
debugPlayer("触发暂停播放")
|
||||||
|
// 此时需要暂停播放
|
||||||
|
playerInstance.value?.pause()
|
||||||
|
playState.togglePlay(false)
|
||||||
|
playState.reportPlayProgress(0)
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user