向浏览器回报歌曲元数据

This commit is contained in:
Astrian Zheng 2025-08-22 19:11:08 +10:00
parent d89dd55a51
commit d63e18f0c7
Signed by: Astrian
SSH Key Fingerprint: SHA256:rVnhx3DAKjujCwWE13aDl7uV6+9U1MvydLkNRXJrBiA
2 changed files with 27 additions and 124 deletions

View File

@ -2,7 +2,7 @@
import { usePlayQueueStore } from '../stores/usePlayQueueStore'
import { usePlayState } from '../stores/usePlayState'
import { debugPlayer } from '../utils/debug'
import { watch, ref, onMounted, onUnmounted } from 'vue'
import { watch, ref, onMounted } from 'vue'
import artistsOrganize from '../utils/artistsOrganize'
const playQueue = usePlayQueueStore()
@ -82,11 +82,11 @@ class WebAudioPlayer {
if ('mediaSession' in navigator) {
navigator.mediaSession.setActionHandler('play', () => {
console.log('Media session: play requested')
this.play()
playState.togglePlay(true)
})
navigator.mediaSession.setActionHandler('pause', () => {
console.log('Media session: pause requested')
this.pause()
playState.togglePlay(false)
})
navigator.mediaSession.setActionHandler('stop', () => {
console.log('Media session: stop requested')
@ -148,6 +148,7 @@ class WebAudioPlayer {
if (!playState.actualPlaying) {
//
debugPlayer("开始播放")
navigator.mediaSession.playbackState = 'playing'
if (playState.playProgress !== 0) debugPlayer(`已经有所进度!${playState.playProgress}`)
this.currentSource = this.context.createBufferSource()
this.currentSource.buffer = this.audioBuffer[playQueue.currentTrack.song.cid]
@ -201,6 +202,19 @@ class WebAudioPlayer {
const progress = this.context.currentTime - this.currentTrackStartTime
playState.reportPlayProgress(progress)
playState.reportCurrentTrackDuration(this.audioBuffer[playQueue.currentTrack.song.cid].duration)
//
if (('mediaSession' in navigator) && ('setPositionState' in navigator.mediaSession)) {
try {
navigator.mediaSession.setPositionState({
duration: this.audioBuffer[playQueue.currentTrack.song.cid].duration || 0,
playbackRate: 1.0,
position: progress,
})
} catch (error) {
debugPlayer('媒体会话位置更新失败:', error)
}
}
}, 100)
}
@ -212,6 +226,7 @@ class WebAudioPlayer {
}
pause() {
navigator.mediaSession.playbackState = 'paused'
debugPlayer("尝试暂停播放")
debugPlayer(this.currentSource)
this.currentSource?.stop()
@ -263,6 +278,15 @@ onMounted(() => {
watch(() => playQueue.currentTrack, () => {
debugPlayer(`检测到当前播放曲目更新`)
navigator.mediaSession.playbackState = playState.isPlaying ? 'playing' : 'paused'
navigator.mediaSession.metadata = new MediaMetadata({
title: playQueue.currentTrack.song.name,
artist: artistsOrganize(playQueue.currentTrack.song.artistes ?? []),
album: playQueue.currentTrack.album?.name,
artwork: [
{ src: playQueue.currentTrack.album?.coverUrl ?? "", sizes: '500x500', type: 'image/png' },
]
})
playerInstance.value?.loadResourceAndPlay()
})

View File

@ -68,119 +68,6 @@ export const usePlayState = defineStore('playState', () => {
actualPlaying.value = playing
}
/***********
*
**********/
// 设置当前播放曲目
const setCurrentTrack = (track: QueueItem | null) => {
debugStore('设置当前曲目:', track?.song.name || 'null')
currentTrack.value = track
if (track) {
updateMediaSession(track)
}
}
// 初始化媒体会话处理器
const setupMediaSessionHandlers = () => {
if (!('mediaSession' in navigator) || mediaSessionInitialized.value) return
debugStore('设置媒体会话处理器')
navigator.mediaSession.setActionHandler('play', () => {
debugStore('媒体会话: 播放')
togglePlay(true)
})
navigator.mediaSession.setActionHandler('pause', () => {
debugStore('媒体会话: 暂停')
togglePlay(false)
})
// 上一首和下一首需要从外部传入回调
mediaSessionInitialized.value = true
}
// 设置上一首/下一首处理器
const setTrackNavigationHandlers = (
previousHandler: () => void,
nextHandler: () => void,
) => {
if (!('mediaSession' in navigator)) return
navigator.mediaSession.setActionHandler('previoustrack', () => {
debugStore('媒体会话: 上一首')
previousHandler()
})
navigator.mediaSession.setActionHandler('nexttrack', () => {
debugStore('媒体会话: 下一首')
nextHandler()
})
}
// 更新媒体会话信息
const updateMediaSession = (track: QueueItem) => {
if (!('mediaSession' in navigator)) return
debugStore('更新媒体会话:', track.song.name)
try {
navigator.mediaSession.metadata = new MediaMetadata({
title: track.song.name,
artist: artistsOrganize(track.song.artists ?? []),
album: track.album?.name,
artwork: [
{
src: track.album?.coverUrl ?? '',
sizes: '500x500',
type: 'image/png',
},
],
})
} catch (error) {
console.error('更新媒体会话元数据失败:', error)
}
}
// 更新媒体会话播放状态
const updateMediaSessionPlaybackState = () => {
if (!('mediaSession' in navigator)) return
navigator.mediaSession.playbackState = isPlaying.value
? 'playing'
: 'paused'
debugStore('媒体会话状态更新:', navigator.mediaSession.playbackState)
}
// 更新媒体会话位置信息
const updateMediaSessionPosition = () => {
if (
!('mediaSession' in navigator) ||
!('setPositionState' in navigator.mediaSession)
)
return
try {
navigator.mediaSession.setPositionState({
duration: currentTrackDuration.value || 0,
playbackRate: 1.0,
position: playProgress.value,
})
} catch (error) {
debugStore('媒体会话位置更新失败:', error)
}
}
// 监听播放状态变化,自动更新媒体会话
watch(isPlaying, () => {
updateMediaSessionPlaybackState()
})
// 监听播放进度变化,定期更新位置信息
watch(playProgress, () => {
updateMediaSessionPosition()
})
return {
// 状态读取
isPlaying: playingState,
@ -198,13 +85,5 @@ export const usePlayState = defineStore('playState', () => {
resetProgress,
seekTo,
reportActualPlaying,
// 媒体会话方法
setCurrentTrack,
setupMediaSessionHandlers,
setTrackNavigationHandlers,
updateMediaSession,
updateMediaSessionPlaybackState,
updateMediaSessionPosition,
}
})