v2.0.0
This commit is contained in:
@@ -0,0 +1,434 @@
|
||||
import { isEmpty, setPause, setPlay, setResource, setStop } from '@renderer/plugins/player'
|
||||
import { isPlay, playedList, playInfo, playMusicInfo, tempPlayList } from '@renderer/store/player/state'
|
||||
import {
|
||||
getList,
|
||||
clearPlayedList,
|
||||
clearTempPlayeList,
|
||||
setPlayMusicInfo,
|
||||
addPlayedList,
|
||||
setMusicInfo,
|
||||
setAllStatus,
|
||||
removeTempPlayList,
|
||||
setPlayListId,
|
||||
removePlayedList,
|
||||
} from '@renderer/store/player/action'
|
||||
import { appSetting } from '@renderer/store/setting'
|
||||
import { getMusicUrl, getPicPath, getLyricInfo } from '../music/index'
|
||||
import { filterList } from './utils'
|
||||
import { requestMsg } from '@renderer/utils/message'
|
||||
import { getRandom } from '@renderer/utils/index'
|
||||
// import { checkMusicFileAvailable } from '@renderer/utils/music'
|
||||
|
||||
let isGettingUrl = false
|
||||
const createDelayNextTimeout = (delay: number) => {
|
||||
let timeout: NodeJS.Timeout | null
|
||||
const clearDelayNextTimeout = () => {
|
||||
// console.log(this.timeout)
|
||||
if (timeout) {
|
||||
clearTimeout(timeout)
|
||||
timeout = null
|
||||
}
|
||||
}
|
||||
|
||||
const addDelayNextTimeout = () => {
|
||||
clearDelayNextTimeout()
|
||||
timeout = setTimeout(() => {
|
||||
timeout = null
|
||||
if (window.lx.isPlayedStop) return
|
||||
console.warn('delay next timeout timeout', delay)
|
||||
void playNext(true)
|
||||
}, delay)
|
||||
}
|
||||
|
||||
return {
|
||||
clearDelayNextTimeout,
|
||||
addDelayNextTimeout,
|
||||
}
|
||||
}
|
||||
const { addDelayNextTimeout, clearDelayNextTimeout } = createDelayNextTimeout(5000)
|
||||
const { addDelayNextTimeout: addLoadTimeout, clearDelayNextTimeout: clearLoadTimeout } = createDelayNextTimeout(100000)
|
||||
|
||||
/**
|
||||
* 检查音乐信息是否已更改
|
||||
*/
|
||||
const diffCurrentMusicInfo = (curMusicInfo: LX.Music.MusicInfo | LX.Download.ListItem): boolean => {
|
||||
return curMusicInfo !== playMusicInfo.musicInfo || isPlay.value
|
||||
}
|
||||
|
||||
const getMusicPlayUrl = async(musicInfo: LX.Music.MusicInfo | LX.Download.ListItem, isRefresh = false, isRetryed = false): Promise<string | null> => {
|
||||
// this.musicInfo.url = await getMusicPlayUrl(targetSong, type)
|
||||
setAllStatus(window.i18n.t('player__geting_url'))
|
||||
|
||||
// const type = getPlayType(appSetting['player.highQuality'], musicInfo)
|
||||
|
||||
return getMusicUrl({
|
||||
musicInfo,
|
||||
isRefresh,
|
||||
onToggleSource(mInfo) {
|
||||
if (diffCurrentMusicInfo(musicInfo)) return
|
||||
setAllStatus(window.i18n.t('toggle_source_try'))
|
||||
},
|
||||
}).then(url => {
|
||||
if (window.lx.isPlayedStop || diffCurrentMusicInfo(musicInfo)) return null
|
||||
|
||||
return url
|
||||
}).catch(err => {
|
||||
// console.log('err', err.message)
|
||||
if (window.lx.isPlayedStop ||
|
||||
diffCurrentMusicInfo(musicInfo) ||
|
||||
err.message == requestMsg.cancelRequest) return null
|
||||
|
||||
if (!isRetryed) return getMusicPlayUrl(musicInfo, isRefresh, true)
|
||||
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
export const setMusicUrl = (musicInfo: LX.Music.MusicInfo | LX.Download.ListItem, isRefresh?: boolean) => {
|
||||
if (appSetting['player.autoSkipOnError']) addLoadTimeout()
|
||||
isGettingUrl = true
|
||||
void getMusicPlayUrl(musicInfo, isRefresh).then((url) => {
|
||||
if (!url) return
|
||||
setResource(url)
|
||||
}).catch((err: any) => {
|
||||
console.log(err)
|
||||
setAllStatus(err.message)
|
||||
window.app_event.error()
|
||||
if (appSetting['player.autoSkipOnError']) addDelayNextTimeout()
|
||||
}).finally(() => {
|
||||
clearLoadTimeout()
|
||||
if (musicInfo === playMusicInfo.musicInfo) isGettingUrl = false
|
||||
})
|
||||
}
|
||||
|
||||
// 恢复上次播放的状态
|
||||
const handleRestorePlay = async(restorePlayInfo: LX.Player.SavedPlayInfo) => {
|
||||
const musicInfo = playMusicInfo.musicInfo
|
||||
if (!musicInfo) return
|
||||
|
||||
setImmediate(() => {
|
||||
window.app_event.setProgress(appSetting['player.isSavePlayTime'] ? restorePlayInfo.time : 0, restorePlayInfo.maxTime)
|
||||
})
|
||||
|
||||
|
||||
void getPicPath({ musicInfo, listId: playMusicInfo.isTempPlay ? null : playMusicInfo.listId }).then((url: string) => {
|
||||
if (musicInfo.id != playMusicInfo.musicInfo?.id) return
|
||||
setMusicInfo({ pic: url })
|
||||
window.app_event.picUpdated()
|
||||
})
|
||||
|
||||
void getLyricInfo({ musicInfo }).then((lyricInfo) => {
|
||||
if (musicInfo.id != playMusicInfo.musicInfo?.id) return
|
||||
setMusicInfo({
|
||||
lrc: lyricInfo.lyric,
|
||||
tlrc: lyricInfo.tlyric,
|
||||
lxlrc: lyricInfo.lxlyric,
|
||||
rlrc: lyricInfo.rlyric,
|
||||
rawlrc: lyricInfo.rawlrcInfo.lyric,
|
||||
})
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
if (musicInfo.id != playMusicInfo.musicInfo?.id) return
|
||||
setAllStatus(window.i18n.t('lyric__load_error'))
|
||||
}).finally(() => {
|
||||
window.app_event.lyricUpdated()
|
||||
})
|
||||
|
||||
if (appSetting['player.togglePlayMethod'] == 'random') addPlayedList({ ...playMusicInfo as LX.Player.PlayMusicInfo })
|
||||
}
|
||||
|
||||
|
||||
// 处理音乐播放
|
||||
const handlePlay = () => {
|
||||
if (window.lx.isPlayedStop) window.lx.isPlayedStop = false
|
||||
if (isGettingUrl) isGettingUrl = false
|
||||
|
||||
if (window.lx.restorePlayInfo) {
|
||||
void handleRestorePlay(window.lx.restorePlayInfo)
|
||||
window.lx.restorePlayInfo = null
|
||||
return
|
||||
}
|
||||
|
||||
setStop()
|
||||
window.app_event.pause()
|
||||
|
||||
clearDelayNextTimeout()
|
||||
clearLoadTimeout()
|
||||
|
||||
const musicInfo = playMusicInfo.musicInfo
|
||||
|
||||
if (!musicInfo) return
|
||||
|
||||
if (appSetting['player.togglePlayMethod'] == 'random' && !playMusicInfo.isTempPlay) addPlayedList({ ...(playMusicInfo as LX.Player.PlayMusicInfo) })
|
||||
|
||||
void setMusicUrl(musicInfo)
|
||||
|
||||
void getPicPath({ musicInfo, listId: playMusicInfo.isTempPlay ? null : playMusicInfo.listId }).then((url: string) => {
|
||||
if (musicInfo.id != playMusicInfo.musicInfo?.id) return
|
||||
setMusicInfo({ pic: url })
|
||||
window.app_event.picUpdated()
|
||||
})
|
||||
|
||||
void getLyricInfo({ musicInfo }).then((lyricInfo) => {
|
||||
if (musicInfo.id != playMusicInfo.musicInfo?.id) return
|
||||
setMusicInfo({
|
||||
lrc: lyricInfo.lyric,
|
||||
tlrc: lyricInfo.tlyric,
|
||||
lxlrc: lyricInfo.lxlyric,
|
||||
rlrc: lyricInfo.rlyric,
|
||||
rawlrc: lyricInfo.rawlrcInfo.lyric,
|
||||
})
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
if (musicInfo.id != playMusicInfo.musicInfo?.id) return
|
||||
setAllStatus(window.i18n.t('lyric__load_error'))
|
||||
}).finally(() => {
|
||||
window.app_event.lyricUpdated()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放列表内歌曲
|
||||
* @param listId 列表id
|
||||
* @param index 播放的歌曲位置
|
||||
*/
|
||||
export const playList = (listId: string, index: number) => {
|
||||
setPlayListId(listId)
|
||||
setPlayMusicInfo(listId, getList(listId)[index])
|
||||
clearPlayedList()
|
||||
clearTempPlayeList()
|
||||
handlePlay()
|
||||
}
|
||||
|
||||
const handleToggleStop = () => {
|
||||
stop()
|
||||
setTimeout(() => {
|
||||
setPlayMusicInfo(null, null)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 下一曲
|
||||
* @param isAutoToggle 是否自动切换
|
||||
* @returns
|
||||
*/
|
||||
export const playNext = async(isAutoToggle = false): Promise<void> => {
|
||||
if (tempPlayList.length) { // 如果稍后播放列表存在歌曲则直接播放改列表的歌曲
|
||||
const playMusicInfo = tempPlayList[0]
|
||||
removeTempPlayList(0)
|
||||
setPlayMusicInfo(playMusicInfo.listId, playMusicInfo.musicInfo, playMusicInfo.isTempPlay)
|
||||
handlePlay()
|
||||
return
|
||||
}
|
||||
|
||||
if (playMusicInfo.musicInfo == null) return handleToggleStop()
|
||||
|
||||
// console.log(playInfo.playerListId)
|
||||
const currentListId = playInfo.playerListId
|
||||
if (!currentListId) return handleToggleStop()
|
||||
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) {
|
||||
const playMusicInfo = playedList[index]
|
||||
setPlayMusicInfo(playMusicInfo.listId, playMusicInfo.musicInfo, playMusicInfo.isTempPlay)
|
||||
handlePlay()
|
||||
return
|
||||
}
|
||||
}
|
||||
// const isCheckFile = findNum > 2 // 针对下载列表,如果超过两次都碰到无效歌曲,则过滤整个列表内的无效歌曲
|
||||
let { filteredList, playerIndex } = await filterList({ // 过滤已播放歌曲
|
||||
listId: currentListId,
|
||||
list: currentList,
|
||||
playedList,
|
||||
playerMusicInfo: currentList[playInfo.playerPlayIndex],
|
||||
})
|
||||
|
||||
if (!filteredList.length) return handleToggleStop()
|
||||
// let currentIndex: number = filteredList.indexOf(currentList[playInfo.playerPlayIndex])
|
||||
if (playerIndex == -1 && filteredList.length) playerIndex = 0
|
||||
let nextIndex = playerIndex
|
||||
|
||||
let togglePlayMethod = appSetting['player.togglePlayMethod']
|
||||
if (!isAutoToggle) {
|
||||
switch (togglePlayMethod) {
|
||||
case 'list':
|
||||
case 'singleLoop':
|
||||
case 'none':
|
||||
togglePlayMethod = 'listLoop'
|
||||
}
|
||||
}
|
||||
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:
|
||||
nextIndex = -1
|
||||
return
|
||||
}
|
||||
if (nextIndex < 0) return
|
||||
|
||||
const nextPlayMusicInfo = {
|
||||
musicInfo: filteredList[nextIndex],
|
||||
listId: currentListId,
|
||||
isTempPlay: false,
|
||||
}
|
||||
|
||||
setPlayMusicInfo(nextPlayMusicInfo.listId, nextPlayMusicInfo.musicInfo)
|
||||
handlePlay()
|
||||
}
|
||||
|
||||
/**
|
||||
* 上一曲
|
||||
*/
|
||||
export const playPrev = async(isAutoToggle = false): Promise<void> => {
|
||||
if (playMusicInfo.musicInfo == null) return handleToggleStop()
|
||||
|
||||
const currentListId = playInfo.playerListId
|
||||
if (!currentListId) return handleToggleStop()
|
||||
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 > -1; 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 > -1) {
|
||||
const playMusicInfo = playedList[index]
|
||||
setPlayMusicInfo(playMusicInfo.listId, playMusicInfo.musicInfo, playMusicInfo.isTempPlay)
|
||||
handlePlay()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// const isCheckFile = findNum > 2
|
||||
let { filteredList, playerIndex } = await filterList({ // 过滤已播放歌曲
|
||||
listId: currentListId,
|
||||
list: currentList,
|
||||
playedList,
|
||||
playerMusicInfo: currentList[playInfo.playerPlayIndex],
|
||||
})
|
||||
if (!filteredList.length) return handleToggleStop()
|
||||
|
||||
// let currentIndex = filteredList.indexOf(currentList[playInfo.playerPlayIndex])
|
||||
if (playerIndex == -1 && filteredList.length) playerIndex = 0
|
||||
let nextIndex = playerIndex
|
||||
if (!playMusicInfo.isTempPlay) {
|
||||
let togglePlayMethod = appSetting['player.togglePlayMethod']
|
||||
if (!isAutoToggle) {
|
||||
switch (togglePlayMethod) {
|
||||
case 'list':
|
||||
case 'singleLoop':
|
||||
case 'none':
|
||||
togglePlayMethod = 'listLoop'
|
||||
}
|
||||
}
|
||||
switch (togglePlayMethod) {
|
||||
case 'random':
|
||||
nextIndex = getRandom(0, filteredList.length)
|
||||
break
|
||||
case 'listLoop':
|
||||
case 'list':
|
||||
nextIndex = playerIndex === 0 ? filteredList.length - 1 : playerIndex - 1
|
||||
break
|
||||
case 'singleLoop':
|
||||
break
|
||||
default:
|
||||
nextIndex = -1
|
||||
return
|
||||
}
|
||||
if (nextIndex < 0) return
|
||||
}
|
||||
|
||||
const nextPlayMusicInfo = {
|
||||
musicInfo: filteredList[nextIndex],
|
||||
listId: currentListId,
|
||||
isTempPlay: false,
|
||||
}
|
||||
|
||||
setPlayMusicInfo(nextPlayMusicInfo.listId, nextPlayMusicInfo.musicInfo)
|
||||
handlePlay()
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复播放
|
||||
*/
|
||||
export const play = () => {
|
||||
if (playMusicInfo.musicInfo == null) return
|
||||
if (isEmpty()) {
|
||||
void setMusicUrl(playMusicInfo.musicInfo)
|
||||
return
|
||||
}
|
||||
setPlay()
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停播放
|
||||
*/
|
||||
export const pause = () => {
|
||||
setPause()
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止播放
|
||||
*/
|
||||
export const stop = () => {
|
||||
setStop()
|
||||
setTimeout(() => {
|
||||
window.app_event.stop()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放、暂停播放切换
|
||||
*/
|
||||
export const togglePlay = () => {
|
||||
if (window.lx.isPlayedStop) window.lx.isPlayedStop = false
|
||||
if (isPlay.value) {
|
||||
pause()
|
||||
} else {
|
||||
play()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './action'
|
||||
export * from './timeoutStop'
|
||||
@@ -0,0 +1,99 @@
|
||||
import { ref, computed, ComputedRef } from '@common/utils/vueTools'
|
||||
import { isPlay } from '@renderer/store/player/state'
|
||||
import { appSetting } from '@renderer/store/setting'
|
||||
// import { interval, intervalCancel } from '@renderer/utils/ipc'
|
||||
import { stop } from './action'
|
||||
|
||||
const time = ref(-1)
|
||||
|
||||
|
||||
const timeoutTools: {
|
||||
isRunning: boolean
|
||||
// time: number
|
||||
interval: null | number
|
||||
timeout: NodeJS.Timeout | null
|
||||
endTime: number
|
||||
exit: () => void
|
||||
clearTimeout: () => void
|
||||
start: (_time: number) => void
|
||||
} = {
|
||||
isRunning: false,
|
||||
timeout: null,
|
||||
// time: -1,
|
||||
endTime: 0,
|
||||
interval: null,
|
||||
exit() {
|
||||
window.lx.isPlayedStop = true
|
||||
if (!appSetting['player.waitPlayEndStop'] && isPlay.value) {
|
||||
stop()
|
||||
}
|
||||
},
|
||||
clearTimeout() {
|
||||
if (this.interval) {
|
||||
window.clearInterval(this.interval)
|
||||
this.interval = null
|
||||
}
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout)
|
||||
this.timeout = null
|
||||
}
|
||||
|
||||
if (!this.isRunning) return
|
||||
// this.time = -1
|
||||
time.value = -1
|
||||
this.isRunning = false
|
||||
},
|
||||
start(_time: number) {
|
||||
this.clearTimeout()
|
||||
// this.time = _time
|
||||
time.value = _time
|
||||
this.isRunning = true
|
||||
this.endTime = performance.now() + _time * 1000
|
||||
|
||||
this.interval = window.setInterval(() => {
|
||||
// this.endTime = performance.now()
|
||||
// if (this.time > 0) {
|
||||
// this.time--
|
||||
// }
|
||||
time.value = Math.max(0, Math.round((this.endTime - performance.now()) / 1000))
|
||||
}, 1000)
|
||||
this.timeout = setTimeout(() => {
|
||||
this.timeout = null
|
||||
time.value = -1
|
||||
this.clearTimeout()
|
||||
this.exit()
|
||||
}, _time * 1000)
|
||||
},
|
||||
}
|
||||
|
||||
export const startTimeoutStop = (time: number) => {
|
||||
if (window.lx.isPlayedStop) window.lx.isPlayedStop = false
|
||||
timeoutTools.start(time)
|
||||
}
|
||||
export const stopTimeoutStop = () => {
|
||||
console.warn('stopTimeoutStop')
|
||||
if (window.lx.isPlayedStop) window.lx.isPlayedStop = false
|
||||
timeoutTools.clearTimeout()
|
||||
}
|
||||
|
||||
const formatTime = (time: number): string => {
|
||||
// let d = parseInt(time / 86400)
|
||||
// d = d ? d.toString() + ':' : ''
|
||||
// time = time % 86400
|
||||
let h: number | string = Math.trunc(time / 3600)
|
||||
h = h ? h.toString() + ':' : ''
|
||||
time = time % 3600
|
||||
const m = Math.trunc(time / 60).toString().padStart(2, '0')
|
||||
const s = Math.trunc(time % 60).toString().padStart(2, '0')
|
||||
return `${h}${m}:${s}`
|
||||
}
|
||||
export const useTimeout = () => {
|
||||
const timeLabel: ComputedRef<string> = computed(() => {
|
||||
return time.value > 0 ? formatTime(time.value) : ''
|
||||
})
|
||||
|
||||
return {
|
||||
time,
|
||||
timeLabel,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { toRaw, markRawList } from '@common/utils/vueTools'
|
||||
import { qualityList } from '@renderer/store'
|
||||
import { clearPlayedList } from '@renderer/store/player/action'
|
||||
import { appSetting } from '@renderer/store/setting'
|
||||
|
||||
export const getPlayType = (highQuality: boolean, musicInfo: LX.Music.MusicInfo | LX.Download.ListItem): LX.Quality | null => {
|
||||
if ('progress' in musicInfo || musicInfo.source == 'local') return null
|
||||
let type: LX.Quality = '128k'
|
||||
let list = qualityList.value[musicInfo.source]
|
||||
if (highQuality && musicInfo.meta._qualitys['320k'] && list && list.includes('320k')) type = '320k'
|
||||
return type
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤列表中已播放的歌曲
|
||||
*/
|
||||
export const filterList = async({ playedList, listId, list, playerMusicInfo }: {
|
||||
playedList: LX.Player.PlayMusicInfo[]
|
||||
listId: string
|
||||
list: Array<LX.Music.MusicInfo | LX.Download.ListItem>
|
||||
playerMusicInfo?: LX.Music.MusicInfo | LX.Download.ListItem
|
||||
}) => {
|
||||
// if (this.list.listName === null) return
|
||||
// console.log(isCheckFile)
|
||||
let { filteredList, canPlayList, playerIndex } = await window.lx.worker.main.filterMusicList({
|
||||
listId,
|
||||
list: list.map(m => toRaw(m)),
|
||||
playedList: toRaw(playedList),
|
||||
savePath: appSetting['download.savePath'],
|
||||
playerMusicInfo: toRaw(playerMusicInfo),
|
||||
})
|
||||
|
||||
if (!filteredList.length && playedList.length) {
|
||||
clearPlayedList()
|
||||
return { filteredList: markRawList(canPlayList), playerIndex }
|
||||
}
|
||||
return { filteredList: markRawList(filteredList), playerIndex }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user