lx-music-desktop/src/renderer/store/modules/player.js

449 lines
14 KiB
JavaScript

import path from 'path'
import music from '../../utils/music'
import {
getRandom,
checkPath,
getLyric as getStoreLyric,
setLyric,
setMusicUrl,
getMusicUrl as getStoreMusicUrl,
assertApiSupport,
} from '@renderer/utils'
import { player as eventPlayerNames, list as eventListNames } from '@renderer/event/names'
import {
setPlayList,
setPlayMusicInfo,
playedList,
addPlayedList,
removePlayedList,
clearPlayedList,
tempPlayList,
addTempPlayList,
removeTempPlayList,
clearTempPlayeList,
playInfo,
playMusicInfo,
} from '@renderer/core/share/player'
import { tempList, updateList } from '@renderer/core/share/list'
import { getList } from '@renderer/core/share/utils'
// state
const state = {
}
const playMusic = () => {
if (global.isPlayedStop) global.isPlayedStop = false
window.eventHub.emit(eventPlayerNames.playMusic)
}
const filterList = async({ playedList, listInfo, savePath, commit }) => {
// if (this.list.listName === null) return
let list
let canPlayList = []
const filteredPlayedList = playedList.filter(({ listId, isTempPlay }) => listInfo.id === listId && !isTempPlay).map(({ musicInfo }) => musicInfo)
if (listInfo.id == 'download') {
list = []
for (const item of listInfo.list) {
const filePath = path.join(savePath, item.metadata.fileName)
if (!await checkPath(filePath) || !item.isComplate || /\.ape$/.test(filePath)) continue
canPlayList.push(item)
// 排除已播放音乐
let index = filteredPlayedList.findIndex(m => m.songmid == item.songmid)
if (index > -1) {
filteredPlayedList.splice(index, 1)
continue
}
list.push(item)
}
} else {
list = listInfo.list.filter(s => {
// if (!assertApiSupport(s.source)) return false
canPlayList.push(s)
let index = filteredPlayedList.findIndex(m => m.songmid == s.songmid)
if (index > -1) {
filteredPlayedList.splice(index, 1)
return false
}
return true
})
}
if (!list.length && playedList.length) {
commit('clearPlayedList')
return canPlayList
}
return list
}
const getMusicUrl = function(musicInfo, type, onToggleSource, retryedSource = [], originMusic) {
// console.log(musicInfo.source)
if (!originMusic) originMusic = musicInfo
let reqPromise
try {
reqPromise = music[musicInfo.source].getMusicUrl(musicInfo, type).promise
} catch (err) {
reqPromise = Promise.reject(err)
}
return reqPromise.catch(err => {
if (!retryedSource.includes(musicInfo.source)) retryedSource.push(musicInfo.source)
onToggleSource()
return this.dispatch('list/getOtherSource', originMusic).then(otherSource => {
console.log('find otherSource', otherSource)
if (otherSource.length) {
for (const item of otherSource) {
if (retryedSource.includes(item.source) || !assertApiSupport(item.source)) continue
console.log('try toggle to: ', item.source, item.name, item.singer, item.interval)
return getMusicUrl.call(this, item, type, onToggleSource, retryedSource, originMusic)
}
}
return Promise.reject(err)
})
})
}
const getPic = function(musicInfo, retryedSource = [], originMusic) {
// console.log(musicInfo.source)
if (!originMusic) originMusic = musicInfo
let reqPromise
try {
reqPromise = music[musicInfo.source].getPic(musicInfo).promise
} catch (err) {
reqPromise = Promise.reject(err)
}
return reqPromise.catch(err => {
if (!retryedSource.includes(musicInfo.source)) retryedSource.push(musicInfo.source)
return this.dispatch('list/getOtherSource', originMusic).then(otherSource => {
console.log('find otherSource', otherSource)
if (otherSource.length) {
for (const item of otherSource) {
if (retryedSource.includes(item.source)) continue
console.log('try toggle to: ', item.source, item.name, item.singer, item.interval)
return getPic.call(this, item, retryedSource, originMusic)
}
}
return Promise.reject(err)
})
})
}
const getLyric = function(musicInfo, retryedSource = [], originMusic) {
if (!originMusic) originMusic = musicInfo
let reqPromise
try {
reqPromise = music[musicInfo.source].getLyric(musicInfo).promise
} catch (err) {
reqPromise = Promise.reject(err)
}
return reqPromise.catch(err => {
if (!retryedSource.includes(musicInfo.source)) retryedSource.push(musicInfo.source)
return this.dispatch('list/getOtherSource', originMusic).then(otherSource => {
console.log('find otherSource', otherSource)
if (otherSource.length) {
for (const item of otherSource) {
if (retryedSource.includes(item.source)) continue
console.log('try toggle to: ', item.source, item.name, item.singer, item.interval)
return getLyric.call(this, item, retryedSource, originMusic)
}
}
return Promise.reject(err)
})
})
}
// getters
const getters = {
}
// actions
const actions = {
async getUrl({ commit, state }, { musicInfo, type, isRefresh, onToggleSource = () => {} }) {
// if (!musicInfo._types[type]) {
// // 兼容旧版酷我源搜索列表过滤128k音质的bug
// if (!(musicInfo.source == 'kw' && type == '128k')) throw new Error('该歌曲没有可播放的音频')
// // return Promise.reject(new Error('该歌曲没有可播放的音频'))
// }
const cachedUrl = await getStoreMusicUrl(musicInfo, type)
if (cachedUrl && !isRefresh) return cachedUrl
return getMusicUrl.call(this, musicInfo, type, onToggleSource).then(({ url }) => {
commit('setUrl', { musicInfo, url, type })
return url
}).catch(err => {
return Promise.reject(err)
})
},
getPic({ commit, state }, { musicInfo, listId }) {
// if (picRequest && picRequest.cancelHttp) picRequest.cancelHttp()
// picRequest = music[musicInfo.source].getPic(musicInfo)
return getPic.call(this, musicInfo).then(url => {
// picRequest = null
commit('setPic', { musicInfo, url, listId })
}).catch(err => {
// picRequest = null
return Promise.reject(err)
})
},
async getLrc({ commit, state }, musicInfo) {
const lrcInfo = await getStoreLyric(musicInfo)
// lrcInfo = {}
// if (lrcRequest && lrcRequest.cancelHttp) lrcRequest.cancelHttp()
if (lrcInfo.lyric && lrcInfo.tlyric != null) {
// if (musicInfo.lrc.startsWith('\ufeff[id:$00000000]')) {
// let str = musicInfo.lrc.replace('\ufeff[id:$00000000]\n', '')
// commit('setLrc', { musicInfo, lyric: str, tlyric: musicInfo.tlrc, lxlyric: musicInfo.tlrc })
// } else if (musicInfo.lrc.startsWith('[id:$00000000]')) {
// let str = musicInfo.lrc.replace('[id:$00000000]\n', '')
// commit('setLrc', { musicInfo, lyric: str, tlyric: musicInfo.tlrc, lxlyric: musicInfo.tlrc })
// }
if (lrcInfo.lxlyric == null) {
switch (musicInfo.source) {
case 'kg':
case 'kw':
break
default:
return lrcInfo
}
} else return lrcInfo
}
// lrcRequest = music[musicInfo.source].getLyric(musicInfo)
return getLyric.call(this, musicInfo).then(({ lyric, tlyric, lxlyric }) => {
// lrcRequest = null
commit('setLrc', { musicInfo, lyric, tlyric, lxlyric })
return { lyric, tlyric, lxlyric }
}).catch(err => {
// lrcRequest = null
return Promise.reject(err)
})
},
async playPrev({ state, rootState, commit, getters }) {
const currentListId = playInfo.playListId
const currentList = getList(currentListId)
if (playedList.length) {
let currentSongmid
if (playMusicInfo.isTempPlay) {
const musicInfo = currentList[playInfo.listPlayIndex]
if (musicInfo) currentSongmid = musicInfo.songmid
} else {
currentSongmid = playMusicInfo.musicInfo.songmid
}
// 从已播放列表移除播放列表已删除的歌曲
let index
for (index = playedList.findIndex(m => m.musicInfo.songmid === currentSongmid) - 1; index > -1; index--) {
const playMusicInfo = playedList[index]
const currentSongmid = playMusicInfo.musicInfo.songmid
if (playMusicInfo.listId == currentListId && !currentList.some(m => m.songmid === currentSongmid)) {
commit('removePlayedList', index)
continue
}
break
}
if (index > -1) {
commit('setPlayMusicInfo', playedList[index])
playMusic()
return
}
}
let filteredList = await filterList({
listInfo: { id: currentListId, list: currentList },
playedList,
savePath: rootState.setting.download.savePath,
commit,
})
if (!filteredList.length) return commit('setPlayMusicInfo', { listId: null, musicInfo: null })
let currentIndex = filteredList.indexOf(currentList[playInfo.listPlayIndex])
if (currentIndex == -1 && filteredList.length) currentIndex = 0
let nextIndex = currentIndex
if (!playMusicInfo.isTempPlay) {
switch (rootState.setting.player.togglePlayMethod) {
case 'random':
nextIndex = getRandom(0, filteredList.length)
break
case 'listLoop':
case 'list':
nextIndex = currentIndex === 0 ? filteredList.length - 1 : currentIndex - 1
break
case 'singleLoop':
break
default:
nextIndex = -1
return
}
if (nextIndex < 0) return
}
commit('setPlayMusicInfo', {
musicInfo: filteredList[nextIndex],
listId: currentListId,
})
playMusic()
},
async playNext({ state, rootState, commit, getters }) {
if (tempPlayList.length) {
const playMusicInfo = tempPlayList[0]
commit('removeTempPlayList', 0)
commit('setPlayMusicInfo', playMusicInfo)
playMusic()
return
}
// console.log(playInfo.playListId)
const currentListId = playInfo.playListId
const currentList = getList(currentListId)
if (playedList.length) {
let currentSongmid
if (playMusicInfo.isTempPlay) {
const musicInfo = currentList[playInfo.listPlayIndex]
if (musicInfo) currentSongmid = musicInfo.songmid
} else {
currentSongmid = playMusicInfo.musicInfo.songmid
}
// 从已播放列表移除播放列表已删除的歌曲
let index
for (index = playedList.findIndex(m => m.musicInfo.songmid === currentSongmid) + 1; index < playedList.length; index++) {
const playMusicInfo = playedList[index]
const currentSongmid = playMusicInfo.musicInfo.songmid
if (playMusicInfo.listId == currentListId && !currentList.some(m => m.songmid === currentSongmid)) {
commit('removePlayedList', index)
continue
}
break
}
if (index < playedList.length) {
commit('setPlayMusicInfo', playedList[index])
playMusic()
return
}
}
let filteredList = await filterList({
listInfo: { id: currentListId, list: currentList },
playedList,
savePath: rootState.setting.download.savePath,
commit,
})
if (!filteredList.length) return commit('setPlayMusicInfo', { listId: null, musicInfo: null })
let currentIndex = filteredList.indexOf(currentList[playInfo.listPlayIndex])
if (currentIndex == -1 && filteredList.length) currentIndex = 0
let nextIndex = currentIndex
switch (rootState.setting.player.togglePlayMethod) {
case 'listLoop':
nextIndex = currentIndex === filteredList.length - 1 ? 0 : currentIndex + 1
break
case 'random':
nextIndex = getRandom(0, filteredList.length)
break
case 'list':
nextIndex = currentIndex === filteredList.length - 1 ? -1 : currentIndex + 1
break
case 'singleLoop':
break
default:
nextIndex = -1
return
}
if (nextIndex < 0) return
commit('setPlayMusicInfo', {
musicInfo: filteredList[nextIndex],
listId: currentListId,
})
playMusic()
},
}
// mitations
const mutations = {
setUrl(state, { musicInfo, type, url }) {
setMusicUrl(musicInfo, type, url)
},
setPic(state, datas) {
datas.musicInfo.img = datas.url
this.commit('list/updateMusicInfo', {
listId: datas.listId,
id: datas.musicInfo.songmid,
data: { img: datas.url },
musicInfo: datas.musicInfo,
})
},
setLrc(state, datas) {
// datas.musicInfo.lrc = datas.lyric
// datas.musicInfo.tlrc = datas.tlyric
// datas.musicInfo.lxlrc = datas.lxlyric
setLyric(datas.musicInfo, {
lyric: datas.lyric,
tlyric: datas.tlyric,
lxlyric: datas.lxlyric,
})
},
setList(state, { listId, index }) {
const list = getList(listId)
const musicInfo = list[index]
if (!musicInfo) return
setPlayList(listId)
setPlayMusicInfo(listId, musicInfo)
if (playedList.length) this.commit('player/clearPlayedList')
if (tempPlayList.length) this.commit('player/clearTempPlayeList')
playMusic()
},
setTempList(state, { list, id, index }) {
updateList({ id: tempList.id, meta: { id }, list })
this.commit('player/setList', {
listId: tempList.id,
index,
})
window.eventHub.emit(eventListNames.listChange, [tempList.id])
},
updateTempList(state, { id, list }) {
updateList({ id: tempList.id, meta: { id }, list })
window.eventHub.emit(eventListNames.listChange, [tempList.id])
},
// setPlayIndex(state, index) {
// state.playIndex = index
// },
setPlayedList(state, item) {
// console.log(item)
addPlayedList(item)
},
removePlayedList(state, index) {
removePlayedList(index)
},
clearPlayedList(state) {
clearPlayedList()
},
setTempPlayList(state, list) {
addTempPlayList(list)
if (!playMusicInfo.musicInfo) this.dispatch('player/playNext')
},
removeTempPlayList(state, index) {
removeTempPlayList(index)
},
clearTempPlayeList(state) {
clearTempPlayeList()
},
setPlayMusicInfo(state, { listId, musicInfo, isTempPlay }) {
setPlayMusicInfo(listId, musicInfo, isTempPlay)
},
}
export default {
namespaced: true,
state,
getters,
actions,
mutations,
}