import path from 'path' import music from '../../utils/music' import { getRandom, checkPath, getLyric as getStoreLyric, setLyric, setMusicUrl, getMusicUrl as getStoreMusicUrl, assertApiSupport, } from '../../utils' // state const state = { listInfo: { list: [], id: null, }, playIndex: -1, changePlay: false, playedList: [], playMusicInfo: null, tempPlayList: [], } 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.fileName) if (!await checkPath(filePath) || !item.isComplate || /\.ape$/.test(filePath)) continue canPlayList.push(item) // 排除已播放音乐 let index = filteredPlayedList.findIndex(m => (m.songmid || m.musicInfo.songmid) == item.musicInfo.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 || m.musicInfo.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) }) }) } let prevListPlayIndex // getters const getters = { list: state => state.listInfo.list, changePlay: satte => satte.changePlay, playInfo(state) { if (state.playMusicInfo == null) return { listId: null, playIndex: -1, playListId: null, listPlayIndex: -1, isPlayList: false, musicInfo: null } const playListId = state.listInfo.id let listId = state.playMusicInfo.listId const isTempPlay = !!state.playMusicInfo.isTempPlay const isPlayList = listId === playListId let playIndex = -1 let listPlayIndex = Math.min(state.playIndex, state.listInfo.list.length - 1) if (listId != '__temp__') { if (state.playMusicInfo.musicInfo.key) { const currentKey = state.playMusicInfo.musicInfo.key if (isPlayList) { playIndex = state.listInfo.list.findIndex(m => m.key == currentKey) if (!isTempPlay) listPlayIndex = playIndex } else if (listId == 'download') { playIndex = window.downloadList.findIndex(m => m.key == currentKey) } } else { const currentSongmid = state.playMusicInfo.musicInfo.songmid || state.playMusicInfo.musicInfo.musicInfo.songmid if (isPlayList) { playIndex = state.listInfo.list.findIndex(m => m.songmid == currentSongmid) if (!isTempPlay) listPlayIndex = playIndex } else { let list = window.allList[listId] if (list) playIndex = list.list.findIndex(m => m.songmid == currentSongmid) } } } if (listPlayIndex >= 0) prevListPlayIndex = listPlayIndex // if (listPlayIndex < 0) { // let length = state.listInfo.list.length // if (length) { // let index = Math.min(prevListPlayIndex, 0) // if (index > length - 1) index = length - 1 // listPlayIndex = prevListPlayIndex = index // } // } else { // prevListPlayIndex = listPlayIndex // } // console.log({ // listId, // playIndex, // playListId, // listPlayIndex, // isPlayList, // isTempPlay, // // musicInfo: state.playMusicInfo.musicInfo, // }) console.log(state.playMusicInfo) return { listId, playIndex, playListId, listPlayIndex, isPlayList, isTempPlay, musicInfo: state.playMusicInfo.musicInfo, } }, playMusicInfo: state => state.playMusicInfo, playedList: state => state.playedList, tempPlayList: state => state.tempPlayList, } // 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) { // if (picRequest && picRequest.cancelHttp) picRequest.cancelHttp() // picRequest = music[musicInfo.source].getPic(musicInfo) return getPic.call(this, musicInfo).then(url => { // picRequest = null commit('getPic', { musicInfo, url }) }).catch(err => { // picRequest = null return Promise.reject(err) }) }, async getLrc({ commit, state }, musicInfo) { const lrcInfo = await getStoreLyric(musicInfo) // 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 && musicInfo.source != 'kg') || lrcInfo.lxlyric != null) 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 = state.listInfo.id const currentList = state.listInfo.list const playInfo = getters.playInfo if (state.playedList.length) { let currentSongmid if (state.playMusicInfo.isTempPlay) { const musicInfo = currentList[playInfo.listPlayIndex] if (musicInfo) currentSongmid = musicInfo.songmid || musicInfo.musicInfo.songmid } else { currentSongmid = state.playMusicInfo.musicInfo.songmid || state.playMusicInfo.musicInfo.musicInfo.songmid } // 从已播放列表移除播放列表已删除的歌曲 let index for (index = state.playedList.findIndex(m => (m.musicInfo.songmid || m.musicInfo.musicInfo.songmid) === currentSongmid) - 1; index > -1; index--) { const playMusicInfo = state.playedList[index] const currentSongmid = playMusicInfo.musicInfo.songmid || playMusicInfo.musicInfo.musicInfo.songmid if (playMusicInfo.listId == currentListId && !currentList.some(m => (m.songmid || m.musicInfo.songmid) === currentSongmid)) { commit('removePlayedList', index) continue } break } if (index > -1) { commit('setPlayMusicInfo', state.playedList[index]) return } } let filteredList = await filterList({ listInfo: state.listInfo, playedList: state.playedList, savePath: rootState.setting.download.savePath, commit, }) if (!filteredList.length) return commit('setPlayMusicInfo', null) let listPlayIndex = playInfo.listPlayIndex const currentListLength = state.listInfo.list.length - 1 if (listPlayIndex == -1 && currentListLength) { listPlayIndex = prevListPlayIndex >= currentListLength ? 0 : prevListPlayIndex + 1 } let currentIndex = listPlayIndex if (currentIndex < 0) currentIndex = 0 let nextIndex = currentIndex if (!playInfo.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, }) }, async playNext({ state, rootState, commit, getters }) { if (state.tempPlayList.length) { const playMusicInfo = state.tempPlayList[0] commit('removeTempPlayList', 0) commit('setPlayMusicInfo', playMusicInfo) return } const currentListId = state.listInfo.id const currentList = state.listInfo.list const playInfo = getters.playInfo if (state.playedList.length) { let currentSongmid if (state.playMusicInfo.isTempPlay) { const musicInfo = currentList[playInfo.listPlayIndex] if (musicInfo) currentSongmid = musicInfo.songmid || musicInfo.musicInfo.songmid } else { currentSongmid = state.playMusicInfo.musicInfo.songmid || state.playMusicInfo.musicInfo.musicInfo.songmid } // 从已播放列表移除播放列表已删除的歌曲 let index for (index = state.playedList.findIndex(m => (m.musicInfo.songmid || m.musicInfo.musicInfo.songmid) === currentSongmid) + 1; index < state.playedList.length; index++) { const playMusicInfo = state.playedList[index] const currentSongmid = playMusicInfo.musicInfo.songmid || playMusicInfo.musicInfo.musicInfo.songmid if (playMusicInfo.listId == currentListId && !currentList.some(m => (m.songmid || m.musicInfo.songmid) === currentSongmid)) { commit('removePlayedList', index) continue } break } if (index < state.playedList.length) { commit('setPlayMusicInfo', state.playedList[index]) return } } let filteredList = await filterList({ listInfo: state.listInfo, playedList: state.playedList, savePath: rootState.setting.download.savePath, commit, }) if (!filteredList.length) return commit('setPlayMusicInfo', null) let listPlayIndex = playInfo.listPlayIndex const currentListLength = state.listInfo.list.length - 1 if (listPlayIndex == -1 && currentListLength) { listPlayIndex = prevListPlayIndex > currentListLength ? currentListLength : prevListPlayIndex - 1 } const currentIndex = listPlayIndex 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, }) }, } // mitations const mutations = { setUrl(state, { musicInfo, type, url }) { setMusicUrl(musicInfo, type, url) }, getPic(state, datas) { datas.musicInfo.img = datas.url }, 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, { list, index }) { if (!(list && list.list && list.list[index])) return state.playMusicInfo = { musicInfo: list.list[index], listId: list.id, } state.listInfo = list state.playIndex = index state.changePlay = true // console.log(state.playMusicInfo) if (state.playedList.length) this.commit('player/clearPlayedList') if (state.tempPlayList.length) this.commit('player/clearTempPlayeList') }, setPlayIndex(state, index) { state.playIndex = index }, setChangePlay(state) { state.changePlay = true }, resetChangePlay(state) { state.changePlay = false }, setPlayedList(state, item) { // console.log(item) if (state.playedList.includes(item)) return state.playedList.push(item) }, removePlayedList(state, index) { state.playedList.splice(index, 1) }, clearPlayedList(state) { state.playedList.splice(0, state.playedList.length) }, setTempPlayList(state, list) { state.tempPlayList.push(...list.map(({ musicInfo, listId }) => ({ musicInfo, listId, isTempPlay: true }))) if (!state.playMusicInfo) this.commit('player/playNext') }, removeTempPlayList(state, index) { state.tempPlayList.splice(index, 1) }, clearTempPlayeList(state) { state.tempPlayList.splice(0, state.tempPlayList.length) }, setPlayMusicInfo(state, playMusicInfo) { let playIndex = state.playIndex if (playMusicInfo == null) { playIndex = -1 } else { let listId = playMusicInfo.listId if (listId != '__temp__' && !playMusicInfo.isTempPlay && listId === state.listInfo.id) { const currentSongmid = playMusicInfo.musicInfo.songmid || playMusicInfo.musicInfo.musicInfo.songmid playIndex = state.listInfo.list.findIndex(m => (m.songmid || m.musicInfo.songmid) == currentSongmid) } } state.playMusicInfo = playMusicInfo state.playIndex = playIndex state.changePlay = true }, } export default { namespaced: true, state, getters, actions, mutations, }