新增“稍后播放”功能

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
{ {
"list_play": "Play", "list_play": "Play",
"list_play_later": "Play later",
"list_add_to": "Add to ...", "list_add_to": "Add to ...",
"list_download": "Download", "list_download": "Download",
"list_source_detail": "Song Page", "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_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", "tip_3": "Kugou source does not support opening with playlist ID, but supports Kugou code opening",
"play_all": "Play", "play_all": "Play",
"play_later": "Play later",
"add_all": "Collect" "add_all": "Collect"
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -156,9 +156,9 @@ const mutations = {
if (!targetList) return if (!targetList) return
targetList.list.splice(0, targetList.list.length) targetList.list.splice(0, targetList.list.length)
}, },
updateMusicInfo(state, { id, index, data }) { updateMusicInfo(state, { id, index, data, musicInfo = {} }) {
let targetList = allList[id] let targetList = allList[id]
if (!targetList) return if (!targetList) return Object.assign(musicInfo, data)
Object.assign(targetList.list[index], data) Object.assign(targetList.list[index], data)
}, },
createUserList(state, { name, id = `userlist_${Date.now()}`, list = [], source, sourceListId }) { 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 music from '../../utils/music'
import { getRandom, checkPath, assertApiSupport } from '../../utils'
// state // state
const state = { const state = {
@ -10,20 +12,101 @@ const state = {
changePlay: false, changePlay: false,
isShowPlayerDetail: false, isShowPlayerDetail: false,
playedList: [], playedList: [],
playMusicInfo: null,
tempPlayList: [],
} }
let urlRequest let urlRequest
let picRequest let picRequest
let lrcRequest 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 // getters
const getters = { const getters = {
list: state => state.listInfo.list, list: state => state.listInfo.list,
listId: state => state.listInfo.id,
changePlay: satte => satte.changePlay, 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, isShowPlayerDetail: state => state.isShowPlayerDetail,
playMusicInfo: state => state.playMusicInfo,
playedList: state => state.playedList, playedList: state => state.playedList,
tempPlayList: state => state.tempPlayList,
} }
// actions // actions
@ -78,6 +161,123 @@ const actions = {
return Promise.reject(err) 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 datas.musicInfo.tlrc = datas.tlyric
}, },
setList(state, { list, index }) { setList(state, { list, index }) {
state.playMusicInfo = {
musicInfo: list.list[index],
listId: list.id,
}
state.listInfo = list state.listInfo = list
state.playIndex = index state.playIndex = index
state.changePlay = true state.changePlay = true
// console.log(state.playMusicInfo)
if (state.playedList.length) this.commit('player/clearPlayedList') if (state.playedList.length) this.commit('player/clearPlayedList')
if (state.playedList.length) this.commit('player/clearTempPlayeList')
}, },
setPlayIndex(state, index) { setPlayIndex(state, index) {
state.playIndex = index state.playIndex = index
state.changePlay = true
// console.log(state.changePlay)
}, },
fixPlayIndex(state, index) { setChangePlay(state) {
state.playIndex = index state.changePlay = true
}, },
resetChangePlay(state) { resetChangePlay(state) {
state.changePlay = false state.changePlay = false
}, },
setPlayedList(state, item) { setPlayedList(state, item) {
// console.log(item)
if (state.playedList.includes(item)) return if (state.playedList.includes(item)) return
state.playedList.push(item) state.playedList.push(item)
}, },
@ -118,11 +323,35 @@ const mutations = {
state.playedList.splice(index, 1) state.playedList.splice(index, 1)
}, },
clearPlayedList(state) { clearPlayedList(state) {
state.playedList = [] state.playedList.splice(0, state.playedList.length)
}, },
visiblePlayerDetail(state, visible) { visiblePlayerDetail(state, visible) {
state.isShowPlayerDetail = 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 { export default {

View File

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

View File

@ -77,7 +77,7 @@ export default {
...mapActions('leaderboard', ['getBoardsList', 'getList']), ...mapActions('leaderboard', ['getBoardsList', 'getList']),
...mapActions('download', ['createDownload', 'createDownloadMultiple']), ...mapActions('download', ['createDownload', 'createDownloadMultiple']),
...mapMutations('list', ['listAdd', 'listAddMultiple']), ...mapMutations('list', ['listAdd', 'listAddMultiple']),
...mapMutations('player', ['setList']), ...mapMutations('player', ['setList', 'setTempPlayList']),
handleListBtnClick(info) { handleListBtnClick(info) {
switch (info.action) { switch (info.action) {
case 'download': case 'download':
@ -121,6 +121,14 @@ export default {
} }
this.testPlay(info.index) this.testPlay(info.index)
break 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': case 'search':
this.handleSearch(info.index) this.handleSearch(info.index)
break break

View File

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

View File

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

View File

@ -183,6 +183,7 @@ export default {
...mapMutations('list', ['listAdd', 'listAddMultiple', 'createUserList']), ...mapMutations('list', ['listAdd', 'listAddMultiple', 'createUserList']),
...mapMutations('player', { ...mapMutations('player', {
setPlayList: 'setList', setPlayList: 'setList',
setTempPlayList: 'setTempPlayList',
}), }),
listenEvent() { listenEvent() {
window.eventHub.$on('key_backspace_down', this.handle_key_backspace_down) window.eventHub.$on('key_backspace_down', this.handle_key_backspace_down)
@ -243,6 +244,14 @@ export default {
} }
this.testPlay(info.index) this.testPlay(info.index)
break 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': case 'search':
this.handleSearch(info.index) this.handleSearch(info.index)
break break