新增“稍后播放”功能

pull/453/head
lyswhut 2021-01-21 14:39:37 +08:00
parent 43b06a686b
commit 085e45a50f
25 changed files with 435 additions and 218 deletions

View File

@ -1,6 +1,7 @@
### 新增
- 搜索界面新增搜索状态的提示
- 新增“稍后播放”功能,可在歌曲列表右键菜单使用
### 优化

View File

@ -34,7 +34,7 @@ div(:class="$style.player")
div(:class="$style.titleBtn" @click='addMusicTo' :tips="$t('core.player.add_music_to')")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='80%' viewBox='0 0 512 512' space='preserve')
use(xlink:href='#icon-add-2')
//- div(:class="$style.playBtn" @click='handleNext' tips="")
//- div(:class="$style.playBtn" @click='playNext' tips="")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 291.063 291.064' space='preserve')
use(xlink:href='#icon-sound')
@ -49,7 +49,7 @@ div(:class="$style.player")
span(style="margin: 0 5px;") /
span {{maxPlayTimeStr}}
div(:class="$style.right")
div(:class="$style.playBtn" @click='handlePrev' :tips="$t('core.player.prev')" style="transform: rotate(180deg);")
div(:class="$style.playBtn" @click='playPrev' :tips="$t('core.player.prev')" style="transform: rotate(180deg);")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
use(xlink:href='#icon-nextMusic')
div(:class="$style.playBtn" :tips="isPlay ? $t('core.player.pause') : $t('core.player.play')" @click='togglePlay')
@ -57,7 +57,7 @@ div(:class="$style.player")
use(xlink:href='#icon-pause')
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve')
use(xlink:href='#icon-play')
div(:class="$style.playBtn" @click='handleNext' :tips="$t('core.player.next')")
div(:class="$style.playBtn" @click='playNext' :tips="$t('core.player.next')")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
use(xlink:href='#icon-nextMusic')
//- transition(enter-active-class="animated lightSpeedIn"
@ -90,7 +90,6 @@ import { rendererSend, rendererOn, NAMES } from '../../../common/ipc'
import { formatPlayTime2, getRandom, checkPath, setTitle, clipboardWriteText, debounce, throttle, assertApiSupport } from '../../utils'
import { mapGetters, mapActions, mapMutations } from 'vuex'
import { requestMsg } from '../../utils/message'
import { isMac } from '../../../common/utils'
import { player as eventPlayerNames } from '../../../common/hotKey'
import musicSdk from '@renderer/utils/music'
import path from 'path'
@ -107,7 +106,6 @@ const playNextModes = [
export default {
data() {
return {
show: true,
volume: 0,
nowPlayTime: 0,
maxPlayTime: 0,
@ -123,7 +121,6 @@ export default {
singer: '',
album: '',
},
targetSong: null,
pregessWidth: 0,
lyric: {
lines: [],
@ -133,7 +130,6 @@ export default {
delayNextTimeout: null,
restorePlayTime: 0,
retryNum: 0,
isMac,
volumeEvent: {
isMsDown: false,
msDownX: 0,
@ -149,10 +145,19 @@ export default {
},
computed: {
...mapGetters(['setting']),
...mapGetters('player', ['list', 'playIndex', 'changePlay', 'listId', 'isShowPlayerDetail', 'playedList']),
...mapGetters('player', ['list', 'changePlay', 'playMusicInfo', 'fixPlayIndex', 'isShowPlayerDetail', 'playInfo', 'playedList']),
// pic() {
// return this.musicInfo.img ? this.musicInfo.img : ''
// },
listId() { // ID
return this.playInfo.listId
},
playIndex() { //
return this.playInfo.playIndex
},
targetSong() {
return this.playInfo.musicInfo
},
title() {
return this.musicInfo.name
? this.setting.download.fileName.replace('歌名', this.musicInfo.name).replace('歌手', this.musicInfo.singer)
@ -247,38 +252,19 @@ export default {
if (!n) return
this.resetChangePlay()
if (window.restorePlayInfo) {
let musicInfo = this.targetSong = this.list[window.restorePlayInfo.index]
this.musicInfo.songmid = musicInfo.songmid
this.musicInfo.singer = musicInfo.singer
this.musicInfo.name = musicInfo.name
this.musicInfo.album = musicInfo.albumName
this.setImg(musicInfo)
this.setLrc(musicInfo)
this.nowPlayTime = this.restorePlayTime = window.restorePlayInfo.time
this.maxPlayTime = window.restorePlayInfo.maxTime || 0
this.handleUpdateWinLyricInfo('music_info', {
songmid: this.musicInfo.songmid,
singer: this.musicInfo.singer,
name: this.musicInfo.name,
album: this.musicInfo.album,
})
this.$nextTick(() => {
this.sendProgressEvent(this.progress, 'paused')
})
if (this.setting.player.togglePlayMethod == 'random') this.setPlayedList(musicInfo)
this.handleRestorePlay(window.restorePlayInfo)
window.restorePlayInfo = null
return
}
// console.log('changePlay')
this.handleRemoveMusic()
if (this.playIndex < 0) return
this.stopPlay()
if (!this.playInfo.musicInfo) return
this.play()
},
'setting.player.togglePlayMethod'(n) {
audio.loop = n === 'singleLoop'
if (this.playedList.length) this.clearPlayedList()
if (n == 'random' && this.playIndex > -1) this.setPlayedList(this.list[this.playIndex])
if (n == 'random') this.setPlayedList(this.playMusicInfo)
},
'setting.player.isMute'(n) {
audio.muted = n
@ -297,13 +283,13 @@ export default {
if (index < 0) {
// console.log(this.playIndex)
if (n.length) {
this.fixPlayIndex(this.playIndex - 1)
this.handleNext()
this.setPlayIndex(this.playInfo.listPlayIndex - 1)
this.playNext()
} else {
this.setPlayIndex(-1)
this.setPlayMusicInfo(null)
}
} else {
this.fixPlayIndex(index)
this.setPlayIndex(index)
}
// console.log(this.playIndex)
}
@ -317,6 +303,7 @@ export default {
},
nowPlayTime(n, o) {
if (Math.abs(n - o) > 2) this.isActiveTransition = true
if (this.playInfo.isTempPlay) return
this.savePlayInfo({
time: n,
maxTime: this.maxPlayTime,
@ -327,16 +314,14 @@ export default {
},
},
methods: {
...mapActions('player', ['getUrl', 'getPic', 'getLrc']),
...mapActions('player', ['getUrl', 'getPic', 'getLrc', 'playPrev', 'playNext']),
...mapMutations('player', [
'setPlayMusicInfo',
'setPlayIndex',
'fixPlayIndex',
'resetChangePlay',
'visiblePlayerDetail',
'clearPlayedList',
'setPlayedList',
'removePlayedList',
'setList',
]),
...mapMutations(['setVolume', 'setPlayNextMode', 'setVisibleDesktopLyric', 'setLockDesktopLyric']),
...mapMutations('list', ['updateMusicInfo']),
@ -345,8 +330,8 @@ export default {
let eventHub = window.eventHub
let name = action == 'on' ? '$on' : '$off'
eventHub[name](eventPlayerNames.toggle_play.action, this.togglePlay)
eventHub[name](eventPlayerNames.next.action, this.handleNext)
eventHub[name](eventPlayerNames.prev.action, this.handlePrev)
eventHub[name](eventPlayerNames.next.action, this.playNext)
eventHub[name](eventPlayerNames.prev.action, this.playPrev)
eventHub[name](eventPlayerNames.volume_up.action, this.handleSetVolumeUp)
eventHub[name](eventPlayerNames.volume_down.action, this.handleSetVolumeDown)
eventHub[name](eventPlayerNames.volume_mute.action, this.handleSetVolumeMute)
@ -377,7 +362,7 @@ export default {
console.log('播放完毕')
this.stopPlay()
this.status = this.statusText = this.$t('core.player.end')
this.handleNext()
this.playNext()
})
audio.addEventListener('error', () => {
// console.log('code', audio.error)
@ -389,7 +374,7 @@ export default {
// console.log(this.retryNum)
if (!this.restorePlayTime) this.restorePlayTime = audio.currentTime //
this.retryNum++
this.setUrl(this.list[this.playIndex], true)
this.setUrl(this.targetSong, true)
this.status = this.statusText = this.$t('core.player.refresh_url')
return
}
@ -407,7 +392,9 @@ export default {
audio.currentTime = this.restorePlayTime
this.restorePlayTime = 0
}
if (!this.targetSong.interval && this.listId != 'download') this.updateMusicInfo({ id: this.listId, index: this.playIndex, data: { interval: formatPlayTime2(this.maxPlayTime) } })
if (!this.targetSong.interval && this.listId != 'download') {
this.updateMusicInfo({ id: this.listId, index: this.playIndex, data: { interval: formatPlayTime2(this.maxPlayTime) }, musicInfo: this.targetSong })
}
})
audio.addEventListener('loadstart', () => {
console.log('loadstart')
@ -470,10 +457,11 @@ export default {
this.handleRegisterEvent('on')
},
async play() {
console.log('play', this.playIndex)
this.clearDelayNextTimeout()
let targetSong = this.targetSong = this.list[this.playIndex]
if (this.setting.player.togglePlayMethod == 'random') this.setPlayedList(targetSong)
const targetSong = this.targetSong
if (this.setting.player.togglePlayMethod == 'random') this.setPlayedList(this.playMusicInfo)
this.retryNum = 0
this.restorePlayTime = 0
@ -481,7 +469,7 @@ export default {
const filePath = path.join(this.setting.download.savePath, targetSong.fileName)
// console.log(filePath)
if (!await checkPath(filePath) || !targetSong.isComplate || /\.ape$/.test(filePath)) {
return this.list.length == 1 ? null : this.handleNext()
return this.list.length == 1 ? null : this.playNext()
}
this.musicInfo.songmid = targetSong.musicInfo.songmid
this.musicInfo.singer = targetSong.musicInfo.singer
@ -492,7 +480,7 @@ export default {
this.setImg(targetSong.musicInfo)
this.setLrc(targetSong.musicInfo)
} else {
if (!this.assertApiSupport(targetSong.source)) return this.handleNext()
if (!this.assertApiSupport(targetSong.source)) return this.playNext()
this.musicInfo.songmid = targetSong.songmid
this.musicInfo.singer = targetSong.singer
this.musicInfo.name = targetSong.name
@ -519,120 +507,10 @@ export default {
this.clearDelayNextTimeout()
this.delayNextTimeout = setTimeout(() => {
this.delayNextTimeout = null
this.handleNext()
this.playNext()
}, 5000)
},
async filterList() {
// if (this.list.listName === null) return
let list
let playedList = [...this.playedList]
if (this.listId == 'download') {
list = []
for (const item of this.list) {
const filePath = path.join(this.setting.download.savePath, item.fileName)
if (!await checkPath(filePath) || !item.isComplate || /\.ape$/.test(filePath)) continue
let index = playedList.indexOf(item)
if (index > -1) {
playedList.splice(index, 1)
continue
}
list.push(item)
}
} else {
list = this.list.filter(s => {
let index = playedList.indexOf(s)
if (index > -1) {
playedList.splice(index, 1)
return false
}
return this.assertApiSupport(s.source)
})
}
if (!list.length && this.playedList.length) {
this.clearPlayedList()
return this.filterList()
}
return list
},
async handlePrev() {
// console.log(playIndex)
if (this.setting.player.togglePlayMethod == 'random' && this.playedList.length) {
let index = this.playedList.indexOf(this.targetSong)
index -= 1
while (true) {
if (index > -1) {
let listIndex = this.list.indexOf(this.playedList[index])
if (listIndex < 0) {
this.removePlayedList(index)
continue
}
this.setPlayIndex(listIndex)
return
}
break
}
}
let list = await this.filterList()
if (!list.length) return this.setPlayIndex(-1)
let playIndex = list.indexOf(this.list[this.playIndex])
let index
switch (this.setting.player.togglePlayMethod) {
case 'random':
index = this.hanldeListRandom(list, playIndex)
break
case 'listLoop':
case 'list':
index = playIndex === 0 ? list.length - 1 : playIndex - 1
break
default:
return
}
if (index < 0) return
index = this.list.indexOf(list[index])
this.setPlayIndex(index)
},
async handleNext() {
// if (this.list.listName === null) return
// eslint-disable-next-line no-debugger
if (this.setting.player.togglePlayMethod == 'random' && this.playedList.length) {
let index = this.playedList.indexOf(this.targetSong)
index += 1
while (true) {
if (index < this.playedList.length) {
let listIndex = this.list.indexOf(this.playedList[index])
if (listIndex < 0) {
this.removePlayedList(index)
continue
}
this.setPlayIndex(listIndex)
return
}
break
}
}
let list = await this.filterList()
if (!list.length) return this.setPlayIndex(-1)
let playIndex = list.indexOf(this.list[this.playIndex])
// console.log(playIndex)
let index
switch (this.setting.player.togglePlayMethod) {
case 'listLoop':
index = playIndex === list.length - 1 ? 0 : playIndex + 1
break
case 'random':
index = this.hanldeListRandom(list, playIndex)
break
case 'list':
index = playIndex === list.length - 1 ? -1 : playIndex + 1
break
default:
return
}
if (index < 0) return
index = this.list.indexOf(list[index])
this.setPlayIndex(index)
},
hanldeListRandom(list, index) {
return getRandom(0, list.length)
},
@ -674,7 +552,7 @@ export default {
togglePlay() {
if (!audio.src) {
if (this.restorePlayTime != null) {
if (!this.assertApiSupport(this.targetSong.source)) return this.handleNext()
if (!this.assertApiSupport(this.targetSong.source)) return this.playNext()
this.setUrl(this.targetSong)
}
return
@ -714,7 +592,7 @@ export default {
this.status = this.statusText = 'Try toggle source...'
return (originMusic.otherSource && originMusic.otherSource.length ? Promise.resolve(originMusic.otherSource) : musicSdk.findMusic(originMusic)).then(res => {
this.updateMusicInfo({ id: this.listId, index: this.playIndex, data: { otherSource: res } })
this.updateMusicInfo({ id: this.listId, index: this.playIndex, data: { otherSource: res }, musicInfo: originMusic })
return res
}).then(otherSource => {
console.log('find otherSource', otherSource)
@ -825,13 +703,13 @@ export default {
this.setProgressWidth()
},
handleToMusicLocation() {
if (!this.listId || this.listId == 'download') return
if (!this.listId || this.listId == '__temp__' || this.listId == 'download') return
if (this.playIndex == -1) return
this.$router.push({
path: 'list',
query: {
id: this.listId,
scrollIndex: this.playIndex,
scrollIndex: this.playInfo.playIndex,
},
})
},
@ -846,7 +724,7 @@ export default {
startLoadingTimeout() {
// console.log('start load timeout')
this.loadingTimeout = setTimeout(() => {
this.handleNext()
this.playNext()
}, 20000)
},
clearLoadingTimeout() {
@ -865,7 +743,7 @@ export default {
if (skipTime > this.maxPlayTime) skipTime = (this.maxPlayTime - audio.currentTime) / 2
if (skipTime - this.mediaBuffer.playTime < 1 || this.maxPlayTime - skipTime < 1) {
this.mediaBuffer.playTime = 0
this.handleNext()
this.playNext()
return
}
this.startBuffering()
@ -925,13 +803,13 @@ export default {
handlePlayDetailAction({ type, data }) {
switch (type) {
case 'prev':
this.handlePrev()
this.playPrev()
break
case 'togglePlay':
this.togglePlay()
break
case 'next':
this.handleNext()
this.playNext()
break
case 'progress':
this.setProgress(data)
@ -972,6 +850,28 @@ export default {
if (!this.musicInfo.songmid) return
this.isShowAddMusicTo = true
},
handleRestorePlay(restorePlayInfo) {
let musicInfo = this.list[restorePlayInfo.index]
this.musicInfo.songmid = musicInfo.songmid
this.musicInfo.singer = musicInfo.singer
this.musicInfo.name = musicInfo.name
this.musicInfo.album = musicInfo.albumName
this.setImg(musicInfo)
this.setLrc(musicInfo)
this.nowPlayTime = this.restorePlayTime = restorePlayInfo.time
this.maxPlayTime = restorePlayInfo.maxTime || 0
this.handleUpdateWinLyricInfo('music_info', {
songmid: this.musicInfo.songmid,
singer: this.musicInfo.singer,
name: this.musicInfo.name,
album: this.musicInfo.album,
})
this.$nextTick(() => {
this.sendProgressEvent(this.progress, 'paused')
})
if (this.setting.player.togglePlayMethod == 'random') this.setPlayedList({ listId: restorePlayInfo.listId, musicInfo: musicInfo })
},
},
}
</script>

View File

@ -114,6 +114,11 @@ export default {
action: 'download',
disabled: !this.listMenu.itemMenuControl.download,
},
{
name: this.$t('material.song_list.list_play_later'),
action: 'playLater',
disabled: !this.listMenu.itemMenuControl.playLater,
},
{
name: this.$t('material.song_list.list_search'),
action: 'search',
@ -173,6 +178,7 @@ export default {
itemMenuControl: {
play: true,
addTo: true,
playLater: true,
download: true,
search: true,
sourceDetail: true,
@ -335,6 +341,7 @@ export default {
handleListItemRigthClick(event, index) {
this.listMenu.itemMenuControl.sourceDetail = !!musicSdk[this.list[index].source].getMusicDetailPageUrl
this.listMenu.itemMenuControl.play =
this.listMenu.itemMenuControl.playLater =
this.listMenu.itemMenuControl.download =
this.assertApiSupport(this.list[index].source)
let dom_selected = this.$refs.dom_tbody.querySelector('tr.selected')

View File

@ -1,5 +1,6 @@
{
"list_play": "Play",
"list_play_later": "Play later",
"list_add_to": "Add to ...",
"list_download": "Download",
"list_search": "Search",

View File

@ -1,5 +1,6 @@
{
"menu_play": "Play",
"menu_play_later": "Play later",
"menu_start": "Start task",
"menu_pause": "Pause Task",
"menu_file": "Locate File",

View File

@ -7,6 +7,7 @@
"lists_sync": "Sync",
"lists_remove": "Remove",
"list_play": "Play",
"list_play_later": "Play later",
"list_copy_name": "Copy name",
"list_add_to": "Add to ...",
"list_move_to": "Move to ...",

View File

@ -1,5 +1,6 @@
{
"list_play": "Play",
"list_play_later": "Play later",
"list_add_to": "Add to ...",
"list_download": "Download",
"list_source_detail": "Song Page",

View File

@ -8,5 +8,6 @@
"tip_2": "If you encounter a link to a playlist that cannot be opened, welcome feedback",
"tip_3": "Kugou source does not support opening with playlist ID, but supports Kugou code opening",
"play_all": "Play",
"play_later": "Play later",
"add_all": "Collect"
}

View File

@ -1,5 +1,6 @@
{
"list_play": "播放",
"list_play_later": "稍后播放",
"list_add_to": "添加到...",
"list_download": "下载",
"list_source_detail": "歌曲详情页",

View File

@ -1,5 +1,6 @@
{
"menu_play": "播放",
"menu_play_later": "稍后播放",
"menu_start": "开始任务",
"menu_pause": "暂停任务",
"menu_file": "定位文件",

View File

@ -7,6 +7,7 @@
"lists_sync": "同步",
"lists_remove": "删除",
"list_play": "播放",
"list_play_later": "稍后播放",
"list_copy_name": "复制歌曲名",
"list_source_detail": "歌曲详情页",
"list_add_to": "添加到...",

View File

@ -1,5 +1,6 @@
{
"list_play": "播放",
"list_play_later": "稍后播放",
"list_add_to": "添加到...",
"list_download": "下载",
"list_source_detail": "歌曲详情页",

View File

@ -8,5 +8,6 @@
"tip_2": "若遇到无法打开的歌单链接,欢迎反馈",
"tip_3": "酷狗源不支持用歌单ID打开但支持酷狗码打开",
"play_all": "播放",
"play_later": "稍后播放",
"add_all": "收藏"
}

View File

@ -1,5 +1,6 @@
{
"list_play": "播放",
"list_play_later": "稍後播放",
"list_add_to": "添加到...",
"list_download": "下載",
"list_search": "搜索",

View File

@ -1,5 +1,6 @@
{
"menu_play": "播放",
"menu_play_later": "稍後播放",
"menu_start": "開始任務",
"menu_pause": "暫停任務",
"menu_file": "定位文件",

View File

@ -7,6 +7,7 @@
"lists_sync": "同步",
"lists_remove": "刪除",
"list_play": "播放",
"list_play_later": "稍後播放",
"list_copy_name": "複製歌曲名",
"list_add_to": "添加到...",
"list_move_to": "移動到...",

View File

@ -1,5 +1,6 @@
{
"list_play": "播放",
"list_play_later": "稍後播放",
"list_add_to": "添加到...",
"list_download": "下載",
"list_source_detail": "歌曲詳情頁",

View File

@ -8,5 +8,6 @@
"tip_2": "若遇到無法打開的歌單鏈接,歡迎反饋",
"tip_3": "酷狗源不支持用歌單ID打開但支持酷狗碼打開",
"play_all": "播放",
"play_later": "稍後播放",
"add_all": "收藏"
}

View File

@ -156,9 +156,9 @@ const mutations = {
if (!targetList) return
targetList.list.splice(0, targetList.list.length)
},
updateMusicInfo(state, { id, index, data }) {
updateMusicInfo(state, { id, index, data, musicInfo = {} }) {
let targetList = allList[id]
if (!targetList) return
if (!targetList) return Object.assign(musicInfo, data)
Object.assign(targetList.list[index], data)
},
createUserList(state, { name, id = `userlist_${Date.now()}`, list = [], source, sourceListId }) {

View File

@ -1,4 +1,6 @@
import path from 'path'
import music from '../../utils/music'
import { getRandom, checkPath, assertApiSupport } from '../../utils'
// state
const state = {
@ -10,20 +12,101 @@ const state = {
changePlay: false,
isShowPlayerDetail: false,
playedList: [],
playMusicInfo: null,
tempPlayList: [],
}
let urlRequest
let picRequest
let lrcRequest
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.indexOf(item)
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.indexOf(s)
if (index > -1) {
filteredPlayedList.splice(index, 1)
return false
}
return true
})
}
if (!list.length && playedList.length) {
commit('clearPlayedList')
return canPlayList
}
return list
}
// getters
const getters = {
list: state => state.listInfo.list,
listId: state => state.listInfo.id,
changePlay: satte => satte.changePlay,
playIndex: state => state.playIndex,
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 = state.playIndex
if (listId != '__temp__') {
if (isPlayList) {
playIndex = state.listInfo.list.indexOf(state.playMusicInfo.musicInfo)
if (!isTempPlay) listPlayIndex = playIndex
} else {
let list = window.allList[listId]
if (list) playIndex = list.list.indexOf(state.playMusicInfo.musicInfo)
}
}
// console.log({
// listId,
// playIndex,
// playListId,
// listPlayIndex,
// isPlayList,
// isTempPlay,
// musicInfo: state.playMusicInfo.musicInfo,
// })
return {
listId,
playIndex,
playListId,
listPlayIndex,
isPlayList,
isTempPlay,
musicInfo: state.playMusicInfo.musicInfo,
}
},
isShowPlayerDetail: state => state.isShowPlayerDetail,
playMusicInfo: state => state.playMusicInfo,
playedList: state => state.playedList,
tempPlayList: state => state.tempPlayList,
}
// actions
@ -78,6 +161,123 @@ const actions = {
return Promise.reject(err)
})
},
async playPrev({ state, rootState, commit, getters }) {
const currentListId = state.listInfo.id
const currentList = state.listInfo.list
if (state.playedList.length) {
// 从已播放列表移除播放列表已删除的歌曲
let index
for (index = state.playedList.indexOf(state.playMusicInfo) - 1; index > -1; index--) {
const playMusicInfo = state.playedList[index]
if (playMusicInfo.listId == currentListId && !currentList.includes(playMusicInfo.musicInfo)) {
commit('removePlayedList', index)
continue
}
break
}
if (index > -1) {
commit('setPlayMusicInfo', state.playedList[index])
return
}
}
let list = await filterList({
listInfo: state.listInfo,
playedList: state.playedList,
savePath: rootState.setting.download.savePath,
commit,
})
if (!list.length) return commit('setPlayMusicInfo', null)
const playInfo = getters.playInfo
const currentIndex = playInfo.listPlayIndex
let nextIndex = currentIndex
if (!playInfo.isTempPlay) {
switch (rootState.setting.player.togglePlayMethod) {
case 'random':
nextIndex = getRandom(0, list.length)
break
case 'listLoop':
case 'list':
nextIndex = currentIndex === 0 ? list.length - 1 : currentIndex - 1
break
case 'singleLoop':
break
default:
nextIndex = -1
return
}
if (nextIndex < 0) return
}
commit('setPlayMusicInfo', {
musicInfo: list[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
if (state.playedList.length) {
// 从已播放列表移除播放列表已删除的歌曲
let index
for (index = state.playedList.indexOf(state.playMusicInfo) + 1; index < state.playedList.length; index++) {
const playMusicInfo = state.playedList[index]
if (playMusicInfo.listId == currentListId && !currentList.includes(playMusicInfo.musicInfo)) {
commit('removePlayedList', index)
continue
}
break
}
if (index < state.playedList.length) {
commit('setPlayMusicInfo', state.playedList[index])
return
}
}
let list = await filterList({
listInfo: state.listInfo,
playedList: state.playedList,
savePath: rootState.setting.download.savePath,
commit,
})
if (!list.length) return commit('setPlayMusicInfo', null)
const playInfo = getters.playInfo
const currentIndex = playInfo.listPlayIndex
let nextIndex = currentIndex
// if (!playInfo.isTempPlay) {
switch (rootState.setting.player.togglePlayMethod) {
case 'listLoop':
nextIndex = currentIndex === list.length - 1 ? 0 : currentIndex + 1
break
case 'random':
nextIndex = getRandom(0, list.length)
break
case 'list':
nextIndex = currentIndex === list.length - 1 ? -1 : currentIndex + 1
break
case 'singleLoop':
break
default:
nextIndex = -1
return
}
if (nextIndex < 0) return
// }
commit('setPlayMusicInfo', {
musicInfo: list[nextIndex],
listId: currentListId,
})
},
}
@ -94,23 +294,28 @@ const mutations = {
datas.musicInfo.tlrc = datas.tlyric
},
setList(state, { list, index }) {
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.playedList.length) this.commit('player/clearTempPlayeList')
},
setPlayIndex(state, index) {
state.playIndex = index
state.changePlay = true
// console.log(state.changePlay)
},
fixPlayIndex(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)
},
@ -118,11 +323,35 @@ const mutations = {
state.playedList.splice(index, 1)
},
clearPlayedList(state) {
state.playedList = []
state.playedList.splice(0, state.playedList.length)
},
visiblePlayerDetail(state, visible) {
state.isShowPlayerDetail = visible
},
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__' && listId === state.listInfo.id) playIndex = state.listInfo.list.indexOf(state.playMusicInfo.musicInfo)
}
state.playMusicInfo = playMusicInfo
state.playIndex = playIndex
state.changePlay = true
},
}
export default {

View File

@ -45,7 +45,7 @@ export default {
return {
clickTime: window.performance.now(),
clickIndex: -1,
selectdData: [],
selectedData: [],
isShowDownloadMultiple: false,
tabId: 'all',
keyEvent: {
@ -59,6 +59,7 @@ export default {
play: true,
start: true,
pause: true,
playLater: true,
file: true,
search: true,
remove: true,
@ -74,13 +75,13 @@ export default {
computed: {
...mapGetters(['setting']),
...mapGetters('download', ['list', 'downloadStatus']),
...mapGetters('player', ['listId', 'playIndex']),
...mapGetters('player', ['playInfo']),
isPlayList() {
return this.listId == 'download'
return this.playInfo.listId == 'download'
},
playListIndex() {
if (this.listId != 'download' || !this.list.length) return
let info = this.list[this.playIndex]
if (this.playInfo.listId != 'download' || !this.list.length) return
let info = this.list[this.playInfo.playIndex]
if (!info) return -1
let key = info.key
return this.showList.findIndex(i => i.key == key)
@ -140,6 +141,11 @@ export default {
action: 'pause',
hide: !this.listMenu.itemMenuControl.pause,
},
{
name: this.$t('view.download.menu_play_later'),
action: 'playLater',
hide: !this.listMenu.itemMenuControl.playLater,
},
{
name: this.$t('view.download.menu_file'),
action: 'file',
@ -229,7 +235,7 @@ export default {
},
handleSelectData(event, clickIndex) {
if (this.keyEvent.isShiftDown) {
if (this.selectdData.length) {
if (this.selectedData.length) {
let lastSelectIndex = this.lastSelectIndex
this.removeAllSelect()
if (lastSelectIndex != clickIndex) {
@ -240,8 +246,8 @@ export default {
clickIndex = temp
isNeedReverse = true
}
this.selectdData = this.showList.slice(lastSelectIndex, clickIndex + 1)
if (isNeedReverse) this.selectdData.reverse()
this.selectedData = this.showList.slice(lastSelectIndex, clickIndex + 1)
if (isNeedReverse) this.selectedData.reverse()
let nodes = this.$refs.dom_tbody.childNodes
do {
nodes[lastSelectIndex].classList.add('active')
@ -250,24 +256,24 @@ export default {
}
} else {
event.currentTarget.classList.add('active')
this.selectdData.push(this.showList[clickIndex])
this.selectedData.push(this.showList[clickIndex])
this.lastSelectIndex = clickIndex
}
} else if (this.keyEvent.isModDown) {
this.lastSelectIndex = clickIndex
let item = this.showList[clickIndex]
let index = this.selectdData.indexOf(item)
let index = this.selectedData.indexOf(item)
if (index < 0) {
this.selectdData.push(item)
this.selectedData.push(item)
event.currentTarget.classList.add('active')
} else {
this.selectdData.splice(index, 1)
this.selectedData.splice(index, 1)
event.currentTarget.classList.remove('active')
}
} else if (this.selectdData.length) this.removeAllSelect()
} else if (this.selectedData.length) this.removeAllSelect()
},
removeAllSelect() {
this.selectdData = []
this.selectedData = []
let dom_tbody = this.$refs.dom_tbody
if (!dom_tbody) return
let nodes = dom_tbody.querySelectorAll('.active')
@ -306,6 +312,14 @@ export default {
case 'remove':
this.removeTask(item)
break
case 'playLater':
if (this.selectedData.length) {
this.setTempPlayList(this.selectedData.map(s => ({ listId: 'download', musicInfo: s })))
this.removeAllSelect()
} else {
this.setTempPlayList([{ listId: 'download', musicInfo: item }])
}
break
case 'file':
this.handleOpenFolder(item.filePath)
break
@ -316,7 +330,7 @@ export default {
},
handleSelectAllData() {
this.removeAllSelect()
this.selectdData = [...this.showList]
this.selectedData = [...this.showList]
let nodes = this.$refs.dom_tbody.childNodes
for (const node of nodes) {
@ -324,19 +338,19 @@ export default {
}
},
// async handleFlowBtnClick(action) {
// let selectdData = [...this.selectdData]
// let selectedData = [...this.selectedData]
// this.removeAllSelect()
// await this.$nextTick()
// switch (action) {
// case 'start':
// this.startTasks(selectdData)
// this.startTasks(selectedData)
// break
// case 'pause':
// this.pauseTasks(selectdData)
// this.pauseTasks(selectedData)
// break
// case 'remove':
// this.removeTasks(selectdData)
// this.removeTasks(selectedData)
// break
// }
// },
@ -353,7 +367,7 @@ export default {
})
},
handleTabChange() {
this.selectdData = []
this.selectedData = []
},
handleListItemRigthClick(event, index) {
this.listMenu.itemMenuControl.sourceDetail = !!musicSdk[this.showList[index].musicInfo.source].getMusicDetailPageUrl
@ -368,16 +382,19 @@ export default {
let item = this.showList[index]
if (item.isComplate) {
this.listMenu.itemMenuControl.play =
this.listMenu.itemMenuControl.playLater =
this.listMenu.itemMenuControl.file = true
this.listMenu.itemMenuControl.start =
this.listMenu.itemMenuControl.pause = false
} else if (item.status === this.downloadStatus.ERROR || item.status === this.downloadStatus.PAUSE) {
this.listMenu.itemMenuControl.play =
this.listMenu.itemMenuControl.pause =
this.listMenu.itemMenuControl.file = false
this.listMenu.itemMenuControl.start = true
// } else if (item.status === this.downloadStatus.ERROR || item.status === this.downloadStatus.PAUSE) {
// this.listMenu.itemMenuControl.play =
// this.listMenu.itemMenuControl.playLater =
// this.listMenu.itemMenuControl.pause =
// this.listMenu.itemMenuControl.file = false
// this.listMenu.itemMenuControl.start = true
} else {
this.listMenu.itemMenuControl.play =
this.listMenu.itemMenuControl.playLater =
this.listMenu.itemMenuControl.start =
this.listMenu.itemMenuControl.file = false
this.listMenu.itemMenuControl.pause = true
@ -407,10 +424,10 @@ export default {
if (item) this.handlePlay(item)
break
case 'start':
if (this.selectdData.length) {
let selectdData = [...this.selectdData]
if (this.selectedData.length) {
let selectedData = [...this.selectedData]
this.removeAllSelect()
this.startTasks(selectdData)
this.startTasks(selectedData)
} else {
item = this.showList[index]
if (item) this.startTask(item)
@ -420,10 +437,10 @@ export default {
}
break
case 'pause':
if (this.selectdData.length) {
let selectdData = [...this.selectdData]
if (this.selectedData.length) {
let selectedData = [...this.selectedData]
this.removeAllSelect()
this.pauseTasks(selectdData)
this.pauseTasks(selectedData)
} else {
item = this.showList[index]
if (item) this.pauseTask(item)
@ -443,10 +460,10 @@ export default {
if (item) this.handleSearch(item.musicInfo)
break
case 'remove':
if (this.selectdData.length) {
let selectdData = [...this.selectdData]
if (this.selectedData.length) {
let selectedData = [...this.selectedData]
this.removeAllSelect()
this.removeTasks(selectdData)
this.removeTasks(selectedData)
} else {
item = this.showList[index]
if (item) this.removeTask(item)

View File

@ -77,7 +77,7 @@ export default {
...mapActions('leaderboard', ['getBoardsList', 'getList']),
...mapActions('download', ['createDownload', 'createDownloadMultiple']),
...mapMutations('list', ['listAdd', 'listAddMultiple']),
...mapMutations('player', ['setList']),
...mapMutations('player', ['setList', 'setTempPlayList']),
handleListBtnClick(info) {
switch (info.action) {
case 'download':
@ -121,6 +121,14 @@ export default {
}
this.testPlay(info.index)
break
case 'playLater':
if (this.selectedData.length) {
this.setTempPlayList(this.selectedData.map(s => ({ listId: '__temp__', musicInfo: s })))
this.resetSelect()
} else {
this.setTempPlayList([{ listId: '__temp__', musicInfo: this.list[info.index] }])
}
break
case 'search':
this.handleSearch(info.index)
break

View File

@ -37,7 +37,7 @@
table
tbody(@contextmenu.capture="handleContextMenu" ref="dom_tbody")
tr(v-for='(item, index) in list' :key='item.songmid' :id="'mid_' + item.songmid" @contextmenu="handleListItemRigthClick($event, index)"
@click="handleDoubleClick($event, index)" :class="[isPlayList && playIndex === index ? $style.active : '', assertApiSupport(item.source) ? null : $style.disabled]")
@click="handleDoubleClick($event, index)" :class="[isPlayList && playInfo.playIndex === index ? $style.active : '', assertApiSupport(item.source) ? null : $style.disabled]")
td.nobreak.center(style="width: 5%; padding-left: 3px; padding-right: 3px;" :class="$style.noSelect" @click.stop) {{index + 1}}
td.break
span.select {{item.name}}
@ -122,6 +122,7 @@ export default {
isShowItemMenu: false,
itemMenuControl: {
play: true,
playLater: true,
copyName: true,
addTo: true,
moveTo: true,
@ -145,12 +146,12 @@ export default {
computed: {
...mapGetters(['userInfo', 'setting']),
...mapGetters('list', ['isInitedList', 'defaultList', 'loveList', 'userList']),
...mapGetters('player', {
playerListId: 'listId',
playIndex: 'playIndex',
}),
...mapGetters('player', ['playInfo']),
playerListId() {
return this.playInfo.listId
},
isPlayList() {
return this.playerListId == this.listId
return this.playInfo.listId == this.listId
},
list() {
return this.listData.list
@ -223,6 +224,11 @@ export default {
action: 'download',
disabled: !this.listMenu.itemMenuControl.download,
},
{
name: this.$t('view.list.list_play_later'),
action: 'playLater',
disabled: !this.listMenu.itemMenuControl.playLater,
},
{
name: this.$t('view.list.list_add_to'),
action: 'addTo',
@ -355,6 +361,7 @@ export default {
...mapActions('download', ['createDownload', 'createDownloadMultiple']),
...mapMutations('player', {
setPlayList: 'setList',
setTempPlayList: 'setTempPlayList',
}),
listenEvent() {
window.eventHub.$on('key_shift_down', this.handle_key_shift_down)
@ -726,6 +733,7 @@ export default {
handleListItemRigthClick(event, index) {
this.listMenu.itemMenuControl.sourceDetail = !!musicSdk[this.list[index].source].getMusicDetailPageUrl
this.listMenu.itemMenuControl.play =
this.listMenu.itemMenuControl.playLater =
this.listMenu.itemMenuControl.download =
this.assertApiSupport(this.list[index].source)
let dom_selected = this.$refs.dom_tbody.querySelector('tr.selected')
@ -789,6 +797,14 @@ export default {
case 'play':
this.testPlay(index)
break
case 'playLater':
if (this.selectdListDetailData.length) {
this.setTempPlayList(this.selectdListDetailData.map(s => ({ listId: this.listId, musicInfo: s })))
this.removeAllSelectListDetail()
} else {
this.setTempPlayList([{ listId: this.listId, musicInfo: this.list[index] }])
}
break
case 'copyName':
minfo = this.list[index]
clipboardWriteText(this.setting.download.fileName.replace('歌名', minfo.name).replace('歌手', minfo.singer))

View File

@ -93,6 +93,7 @@ export default {
isShowItemMenu: false,
itemMenuControl: {
play: true,
playLater: true,
addTo: true,
download: true,
sourceDetail: true,
@ -181,6 +182,11 @@ export default {
action: 'download',
disabled: !this.listMenu.itemMenuControl.download,
},
{
name: this.$t('view.search.list_play_later'),
action: 'playLater',
disabled: !this.listMenu.itemMenuControl.playLater,
},
{
name: this.$t('view.search.list_add_to'),
action: 'addTo',
@ -206,7 +212,7 @@ export default {
...mapActions('download', ['createDownload', 'createDownloadMultiple']),
...mapMutations('search', ['clearList', 'setPage', 'removeHistory', 'clearHistory']),
...mapMutations('list', ['listAdd', 'listAddMultiple']),
...mapMutations('player', ['setList']),
...mapMutations('player', ['setList', 'setTempPlayList']),
...mapActions('hotSearch', {
getHotSearch: 'getList',
}),
@ -283,6 +289,14 @@ export default {
case 'play':
this.testPlay(info.index)
break
case 'playLater':
if (this.selectedData.length) {
this.setTempPlayList(this.selectedData.map(s => ({ listId: '__temp__', musicInfo: s })))
this.resetSelect()
} else {
this.setTempPlayList([{ listId: '__temp__', musicInfo: this.list[info.index] }])
}
break
case 'listAdd':
this.musicInfo = this.listInfo.list[info.index]
this.$nextTick(() => {
@ -432,6 +446,7 @@ export default {
handleListItemRigthClick(event, index) {
this.listMenu.itemMenuControl.sourceDetail = !!musicSdk[this.listInfo.list[index].source].getMusicDetailPageUrl
this.listMenu.itemMenuControl.play =
this.listMenu.itemMenuControl.playLater =
this.listMenu.itemMenuControl.download =
this.assertApiSupport(this.listInfo.list[index].source)
let dom_selected = this.$refs.dom_tbody.querySelector('tr.selected')

View File

@ -183,6 +183,7 @@ export default {
...mapMutations('list', ['listAdd', 'listAddMultiple', 'createUserList']),
...mapMutations('player', {
setPlayList: 'setList',
setTempPlayList: 'setTempPlayList',
}),
listenEvent() {
window.eventHub.$on('key_backspace_down', this.handle_key_backspace_down)
@ -243,6 +244,14 @@ export default {
}
this.testPlay(info.index)
break
case 'playLater':
if (this.selectedData.length) {
this.setTempPlayList(this.selectedData.map(s => ({ listId: '__temp__', musicInfo: s })))
this.resetSelect()
} else {
this.setTempPlayList([{ listId: '__temp__', musicInfo: this.listDetail.list[info.index] }])
}
break
case 'search':
this.handleSearch(info.index)
break