添加歌曲预加载功能

This commit is contained in:
lyswhut
2024-11-23 14:21:59 +08:00
parent 0345419ef3
commit 4e3bdbcc74
6 changed files with 207 additions and 24 deletions
+6 -1
View File
@@ -14,6 +14,7 @@ import { apis } from '@renderer/utils/musicSdk/api-source'
const getOtherSourcePromises = new Map()
const otherSourceCache = new Map<LX.Music.MusicInfo | LX.Download.ListItem, LX.Music.MusicInfoOnline[]>()
export const existTimeExp = /\[\d{1,2}:.*\d{1,4}\]/
export const getOtherSource = async(musicInfo: LX.Music.MusicInfo | LX.Download.ListItem, isRefresh = false): Promise<LX.Music.MusicInfoOnline[]> => {
@@ -21,6 +22,7 @@ export const getOtherSource = async(musicInfo: LX.Music.MusicInfo | LX.Download.
// const cachedInfo = await getOtherSourceFromStore(musicInfo.id)
// if (cachedInfo.length) return cachedInfo
// }
if (otherSourceCache.has(musicInfo)) return otherSourceCache.get(musicInfo)!
let key: string
let searchMusicInfo: {
name: string
@@ -56,7 +58,10 @@ export const getOtherSource = async(musicInfo: LX.Music.MusicInfo | LX.Download.
reject(new Error('find music timeout'))
}, 15_000)
musicSdk.findMusic(searchMusicInfo).then((otherSource) => {
resolve(otherSource.map(toNewMusicInfo) as LX.Music.MusicInfoOnline[])
if (otherSourceCache.size > 100) otherSourceCache.clear()
const source = otherSource.map(toNewMusicInfo) as LX.Music.MusicInfoOnline[]
otherSourceCache.set(musicInfo, source)
resolve(source)
}).catch(reject).finally(() => {
if (timeout) clearTimeout(timeout)
})
+110 -23
View File
@@ -188,6 +188,7 @@ const handleRestorePlay = async(restorePlayInfo: LX.Player.SavedPlayInfo) => {
const handlePlay = () => {
window.lx.isPlayedStop &&= false
resetRandomNextMusicInfo()
if (window.lx.restorePlayInfo) {
void handleRestorePlay(window.lx.restorePlayInfo)
window.lx.restorePlayInfo = null
@@ -253,6 +254,104 @@ const handleToggleStop = () => {
})
}
const randomNextMusicInfo = {
info: null as LX.Player.PlayMusicInfo | null,
index: -1,
}
export const resetRandomNextMusicInfo = () => {
if (randomNextMusicInfo.info) {
randomNextMusicInfo.info = null
randomNextMusicInfo.index = -1
}
}
export const getNextPlayMusicInfo = async(): Promise<LX.Player.PlayMusicInfo | null> => {
if (tempPlayList.length) { // 如果稍后播放列表存在歌曲则直接播放改列表的歌曲
const playMusicInfo = tempPlayList[0]
return playMusicInfo
}
if (playMusicInfo.musicInfo == null) return null
if (randomNextMusicInfo.info) return randomNextMusicInfo.info
// console.log(playInfo.playerListId)
const currentListId = playInfo.playerListId
if (!currentListId) return null
const currentList = getList(currentListId)
if (playedList.length) { // 移除已播放列表内不存在原列表的歌曲
let currentId: string
if (playMusicInfo.isTempPlay) {
const musicInfo = currentList[playInfo.playerPlayIndex]
if (musicInfo) currentId = musicInfo.id
} else {
currentId = playMusicInfo.musicInfo.id
}
// 从已播放列表移除播放列表已删除的歌曲
let index
for (index = playedList.findIndex(m => m.musicInfo.id === currentId) + 1; index < playedList.length; index++) {
const playMusicInfo = playedList[index]
const currentId = playMusicInfo.musicInfo.id
if (playMusicInfo.listId == currentListId && !currentList.some(m => m.id === currentId)) {
removePlayedList(index)
continue
}
break
}
if (index < playedList.length) return playedList[index]
}
// const isCheckFile = findNum > 2 // 针对下载列表,如果超过两次都碰到无效歌曲,则过滤整个列表内的无效歌曲
let { filteredList, playerIndex } = await filterList({ // 过滤已播放歌曲
listId: currentListId,
list: currentList,
playedList,
playerMusicInfo: currentList[playInfo.playerPlayIndex],
isNext: true,
})
if (!filteredList.length) return null
// let currentIndex: number = filteredList.indexOf(currentList[playInfo.playerPlayIndex])
if (playerIndex == -1 && filteredList.length) playerIndex = 0
let nextIndex = playerIndex
let togglePlayMethod = appSetting['player.togglePlayMethod']
switch (togglePlayMethod) {
case 'listLoop':
nextIndex = playerIndex === filteredList.length - 1 ? 0 : playerIndex + 1
break
case 'random':
nextIndex = getRandom(0, filteredList.length)
break
case 'list':
nextIndex = playerIndex === filteredList.length - 1 ? -1 : playerIndex + 1
break
case 'singleLoop':
break
default:
return null
}
if (nextIndex < 0) return null
const nextPlayMusicInfo = {
musicInfo: filteredList[nextIndex],
listId: currentListId,
isTempPlay: false,
}
if (togglePlayMethod == 'random') {
randomNextMusicInfo.info = nextPlayMusicInfo
randomNextMusicInfo.index = nextIndex
}
return nextPlayMusicInfo
}
const handlePlayNext = (playMusicInfo: LX.Player.PlayMusicInfo) => {
pause()
setPlayMusicInfo(playMusicInfo.listId, playMusicInfo.musicInfo, playMusicInfo.isTempPlay)
handlePlay()
}
/**
* 下一曲
* @param isAutoToggle 是否自动切换
@@ -263,9 +362,7 @@ export const playNext = async(isAutoToggle = false): Promise<void> => {
if (tempPlayList.length) { // 如果稍后播放列表存在歌曲则直接播放改列表的歌曲
const playMusicInfo = tempPlayList[0]
removeTempPlayList(0)
pause()
setPlayMusicInfo(playMusicInfo.listId, playMusicInfo.musicInfo, playMusicInfo.isTempPlay)
handlePlay()
handlePlayNext(playMusicInfo)
console.log('play temp list')
return
}
@@ -306,14 +403,15 @@ export const playNext = async(isAutoToggle = false): Promise<void> => {
}
if (index < playedList.length) {
const playMusicInfo = playedList[index]
pause()
setPlayMusicInfo(playMusicInfo.listId, playMusicInfo.musicInfo, playMusicInfo.isTempPlay)
handlePlay()
handlePlayNext(playedList[index])
console.log('play played list')
return
}
}
if (randomNextMusicInfo.info) {
handlePlayNext(randomNextMusicInfo.info)
return
}
// const isCheckFile = findNum > 2 // 针对下载列表,如果超过两次都碰到无效歌曲,则过滤整个列表内的无效歌曲
let { filteredList, playerIndex } = await filterList({ // 过滤已播放歌曲
listId: currentListId,
@@ -363,15 +461,11 @@ export const playNext = async(isAutoToggle = false): Promise<void> => {
return
}
const nextPlayMusicInfo = {
handlePlayNext({
musicInfo: filteredList[nextIndex],
listId: currentListId,
isTempPlay: false,
}
pause()
setPlayMusicInfo(nextPlayMusicInfo.listId, nextPlayMusicInfo.musicInfo)
handlePlay()
})
}
/**
@@ -411,10 +505,7 @@ export const playPrev = async(isAutoToggle = false): Promise<void> => {
}
if (index > -1) {
const playMusicInfo = playedList[index]
pause()
setPlayMusicInfo(playMusicInfo.listId, playMusicInfo.musicInfo, playMusicInfo.isTempPlay)
handlePlay()
handlePlayNext(playedList[index])
return
}
}
@@ -462,15 +553,11 @@ export const playPrev = async(isAutoToggle = false): Promise<void> => {
if (nextIndex < 0) return
}
const nextPlayMusicInfo = {
handlePlayNext({
musicInfo: filteredList[nextIndex],
listId: currentListId,
isTempPlay: false,
}
pause()
setPlayMusicInfo(nextPlayMusicInfo.listId, nextPlayMusicInfo.musicInfo)
handlePlay()
})
}
/**
@@ -34,6 +34,7 @@ import usePlaybackRate from './usePlaybackRate'
import useSoundEffect from './useSoundEffect'
import useMaxOutputChannelCount from './useMaxOutputChannelCount'
import { setPowerSaveBlocker } from '@renderer/core/player/utils'
import usePreloadNextMusic from './usePreloadNextMusic'
export default () => {
@@ -48,6 +49,7 @@ export default () => {
useSoundEffect()
usePlaybackRate()
useWatchList()
usePreloadNextMusic()
const handlePlayNext = () => {
void playNext()
@@ -0,0 +1,75 @@
import { onBeforeUnmount, watch } from '@common/utils/vueTools'
import { onTimeupdate, getCurrentTime } from '@renderer/plugins/player'
import { playProgress } from '@renderer/store/player/playProgress'
import { musicInfo } from '@renderer/store/player/state'
// import { getList } from '@renderer/store/utils'
import { getNextPlayMusicInfo, resetRandomNextMusicInfo } from '@renderer/core/player'
import { getMusicUrl } from '@renderer/core/music'
import { checkUrl } from '@renderer/utils/request'
import { appSetting } from '@renderer/store/setting'
const preloadMusicInfo = {
isLoading: false,
preProgress: 0,
info: null as LX.Player.PlayMusicInfo | null,
}
const resetPreloadInfo = () => {
preloadMusicInfo.preProgress = 0
preloadMusicInfo.info = null
preloadMusicInfo.isLoading = false
}
const preloadNextMusicUrl = async(curTime: number) => {
if (preloadMusicInfo.isLoading || curTime - preloadMusicInfo.preProgress < 3) return
preloadMusicInfo.isLoading = true
console.log('preload next music url')
const info = await getNextPlayMusicInfo()
if (info) {
preloadMusicInfo.info = info
const url = await getMusicUrl({ musicInfo: info.musicInfo }).catch(() => '')
if (url) {
console.log('preload url', url)
const result = await checkUrl(url).then(() => true).catch(() => false)
if (!result) {
const url = await getMusicUrl({ musicInfo: info.musicInfo, isRefresh: true }).catch(() => '')
console.log('preload url refresh', url)
}
}
}
preloadMusicInfo.isLoading = false
}
export default () => {
const setProgress = (time: number) => {
if (!musicInfo.id) return
preloadMusicInfo.preProgress = time
}
const handleSetPlayInfo = () => {
resetPreloadInfo()
}
watch(() => appSetting['player.togglePlayMethod'], () => {
if (!preloadMusicInfo.info || preloadMusicInfo.info.isTempPlay) return
resetRandomNextMusicInfo()
preloadMusicInfo.info = null
preloadMusicInfo.preProgress = playProgress.nowPlayTime
})
window.app_event.on('setProgress', setProgress)
window.app_event.on('musicToggled', handleSetPlayInfo)
const rOnTimeupdate = onTimeupdate(() => {
const time = getCurrentTime()
const duration = playProgress.maxPlayTime
if (duration > 10 && duration - time < 10 && !preloadMusicInfo.info) {
void preloadNextMusicUrl(time)
}
})
onBeforeUnmount(() => {
rOnTimeupdate()
window.app_event.off('setProgress', setProgress)
window.app_event.off('musicToggled', handleSetPlayInfo)
})
}