feat: align with upstream 1.5.9.9
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import { getMusicUrl } from '~/utils/musicUrl'
|
||||
import { isBilibiliSong } from '~/utils/bilibiliSource'
|
||||
import { useAudioPlayer, type PlayableSong } from './useAudioPlayer'
|
||||
import { useToast } from './useToast'
|
||||
import { useLocale } from '~/utils/locale'
|
||||
import type { Song } from '~/types'
|
||||
|
||||
export const useSongPlayer = () => {
|
||||
const audioPlayer = useAudioPlayer()
|
||||
const { showToast } = useToast()
|
||||
const { audioPlayer: audioPlayerLocale } = useLocale()
|
||||
|
||||
// 判断歌曲是否可入队(有自定义链接、B站视频或平台ID)
|
||||
const isPlayableSong = (s: Song | PlayableSong) => {
|
||||
return Boolean(
|
||||
(s.playUrl && s.playUrl.trim()) ||
|
||||
isBilibiliSong(s) ||
|
||||
(s.musicPlatform && s.musicId)
|
||||
)
|
||||
}
|
||||
|
||||
// 根据队列来源构建播放队列,返回队列与当前歌曲索引;来源为空时退化为单曲队列
|
||||
const buildQueue = (song: PlayableSong, queueSource?: (Song | PlayableSong)[]) => {
|
||||
const queue = (queueSource || []).filter(isPlayableSong) as PlayableSong[]
|
||||
const index = queue.findIndex((s) => String(s.id) === String(song.id))
|
||||
if (index === -1) {
|
||||
return { queue: [song, ...queue], index: 0 }
|
||||
}
|
||||
return { queue, index }
|
||||
}
|
||||
|
||||
const playSong = async (song: Song | PlayableSong, queueSource?: (Song | PlayableSong)[]) => {
|
||||
// 如果是当前选中的歌曲
|
||||
if (audioPlayer.isCurrentSong(song.id)) {
|
||||
// 如果正在播放,则暂停
|
||||
if (audioPlayer.getPlayingStatus().value) {
|
||||
audioPlayer.pauseSong()
|
||||
return
|
||||
}
|
||||
|
||||
// 如果是当前歌曲但暂停了,则恢复播放
|
||||
const currentGlobalSong = audioPlayer.getCurrentSong().value
|
||||
if (currentGlobalSong && (currentGlobalSong.musicUrl || isBilibiliSong(currentGlobalSong))) {
|
||||
// 恢复播放时同步刷新播放队列
|
||||
const { queue, index } = buildQueue(currentGlobalSong, queueSource)
|
||||
audioPlayer.playSong(currentGlobalSong, queue, index)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
let url = null
|
||||
|
||||
// 如果有手动填入的 playUrl,优先使用它(统一处理所有平台)
|
||||
if (song.playUrl && song.playUrl.trim()) {
|
||||
url = song.playUrl.trim()
|
||||
} else if (!isBilibiliSong(song)) {
|
||||
// 如果不是哔哩哔哩歌曲且没有手动 playUrl,通过 API 获取 URL
|
||||
url = await getMusicUrl(song.musicPlatform, song.musicId, song.playUrl, {
|
||||
musicInfo: {
|
||||
name: song.title,
|
||||
artist: song.artist,
|
||||
album: song.album || undefined
|
||||
}
|
||||
})
|
||||
}
|
||||
// 如果是哔哩哔哩歌曲且没有手动 playUrl,url 保持为 null,播放器会处理
|
||||
|
||||
const playableSong: PlayableSong = {
|
||||
...song,
|
||||
musicUrl: url
|
||||
}
|
||||
|
||||
const { queue, index } = buildQueue(playableSong, queueSource)
|
||||
audioPlayer.playSong(playableSong, queue, index)
|
||||
} catch (error: any) {
|
||||
console.error('播放失败:', error)
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
showToast(audioPlayerLocale.value.playFailed(errorMessage), 'error')
|
||||
|
||||
// 即使获取 URL 失败,也应该调用 playSong 以触发播放器的错误处理和弹窗逻辑
|
||||
const playableSong: PlayableSong = {
|
||||
...song,
|
||||
musicUrl: null
|
||||
}
|
||||
const { queue, index } = buildQueue(playableSong, queueSource)
|
||||
audioPlayer.playSong(playableSong, queue, index)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
playSong
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user