优化下载列表流畅度

pull/225/head
lyswhut 2020-04-29 19:18:53 +08:00
parent d8a3466914
commit 015c17e2dc
2 changed files with 178 additions and 110 deletions

View File

@ -21,13 +21,13 @@ const state = {
const dls = {} const dls = {}
const tryNum = {} const tryNum = {}
let isRuningActionTask = false
const filterFileName = /[\\/:*?#"<>|]/g const filterFileName = /[\\/:*?#"<>|]/g
// getters // getters
const getters = { const getters = {
list: state => state.list || [], list: state => state.list || [],
dls: () => dls || {},
downloadStatus: state => state.downloadStatus, downloadStatus: state => state.downloadStatus,
} }
@ -57,6 +57,8 @@ const getExt = type => {
return 'ape' return 'ape'
case 'flac': case 'flac':
return 'flac' return 'flac'
case 'wav':
return 'wav'
} }
} }
@ -69,15 +71,79 @@ const getStartTask = (list, downloadStatus, maxDownloadNum) => {
return downloadCount < maxDownloadNum && waitList.length > 0 && waitList.shift() return downloadCount < maxDownloadNum && waitList.length > 0 && waitList.shift()
} }
const addTask = (list, type, store) => { const awaitRequestAnimationFrame = () => new Promise(resolve => window.requestAnimationFrame(() => resolve()))
window.requestAnimationFrame(() => {
const addTasks = async(store, list, type) => {
if (list.length == 0) return
let num = 5
while (num-- > 0) {
let item = list.shift() let item = list.shift()
store.dispatch('download/createDownload', { if (!item) return
await store.dispatch('createDownload', {
musicInfo: item, musicInfo: item,
type: getMusicType(item, type), type: getMusicType(item, type),
}) })
if (list.length) addTask(list, type, store) }
}) await awaitRequestAnimationFrame()
await addTasks(store, list, type)
}
const removeTasks = async(store, list) => {
let num = 50
while (num-- > 0) {
let item = list.pop()
if (!item) return
let index = store.state.list.indexOf(item)
if (index < 0) continue
await store.dispatch('removeTask', index)
}
await awaitRequestAnimationFrame()
await removeTasks(store, list)
}
const startTasks = async(store, list) => {
let num = 10
while (num-- > 0) {
let item = list.shift()
if (!item) return
if (item.isComplate || item.status == state.downloadStatus.RUN || item.status == state.downloadStatus.WAITING) continue
let index = store.state.list.indexOf(item)
if (index < 0) continue
store.dispatch('startTask', item)
}
await awaitRequestAnimationFrame()
await startTasks(store, list)
}
const pauseTasks = async(store, list, runs = []) => {
let num = 10
let index
let stateList = store.state.list
while (num-- > 0) {
let item = list.shift()
if (item.isComplate) continue
if (item) {
switch (item.status) {
case state.downloadStatus.RUN:
runs.push(item)
continue
case state.downloadStatus.WAITING:
index = stateList.indexOf(item)
if (index < 0) return
await store.dispatch('pauseTask', index)
continue
default:
continue
}
} else {
for (const item of runs) {
index = stateList.indexOf(item)
if (index < 0) return
await store.dispatch('pauseTask', index)
}
}
}
await awaitRequestAnimationFrame()
await pauseTasks(store, list, runs)
} }
const getUrl = (downloadInfo, isRefresh) => { const getUrl = (downloadInfo, isRefresh) => {
@ -142,7 +208,11 @@ const refreshUrl = function(commit, downloadInfo) {
const dl = dls[downloadInfo.key] const dl = dls[downloadInfo.key]
if (!dl) return if (!dl) return
dl.refreshUrl(result.url) dl.refreshUrl(result.url)
dl.start() dl.start().catch(err => {
commit('onError', downloadInfo)
commit('setStatusText', { downloadInfo, text: err.message })
this.dispatch('download/startTask')
})
}).catch(err => { }).catch(err => {
// console.log(err) // console.log(err)
commit('onError', downloadInfo) commit('onError', downloadInfo)
@ -168,7 +238,7 @@ const deleteFile = path => new Promise((resolve, reject) => {
// actions // actions
const actions = { const actions = {
async createDownload({ state, rootState, commit }, { musicInfo, type }) { async createDownload({ state, rootState, commit, dispatch }, { musicInfo, type }) {
let ext = getExt(type) let ext = getExt(type)
if (checkList(state.list, musicInfo, type, ext)) return if (checkList(state.list, musicInfo, type, ext)) return
const downloadInfo = { const downloadInfo = {
@ -199,28 +269,21 @@ const actions = {
if (dls[downloadInfo.key]) { if (dls[downloadInfo.key]) {
dls[downloadInfo.key].stop().finally(() => { dls[downloadInfo.key].stop().finally(() => {
delete dls[downloadInfo.key] delete dls[downloadInfo.key]
this.dispatch('download/startTask', downloadInfo) dispatch('startTask', downloadInfo)
}) })
} else { } else {
// console.log(downloadInfo) // console.log(downloadInfo)
this.dispatch('download/startTask', downloadInfo) dispatch('startTask', downloadInfo)
} }
}, },
createDownloadMultiple({ state, rootState }, { list, type }) { async createDownloadMultiple(store, { list, type }) {
if (!list.length) return if (!list.length) return
addTask([...list], type, this) if (isRuningActionTask) return
isRuningActionTask = true
await addTasks(store, [...list], type)
isRuningActionTask = false
}, },
async startTask({ commit, state, rootState }, downloadInfo) { async handleStartTask({ commit, dispatch, rootState }, downloadInfo) {
// 检查是否可以开始任务
if (downloadInfo && downloadInfo != state.downloadStatus.WAITING) commit('setStatus', { downloadInfo, status: state.downloadStatus.WAITING })
let result = getStartTask(state.list, state.downloadStatus, rootState.setting.download.maxDownloadNum)
if (!result) return
if (!downloadInfo) downloadInfo = result
commit('updateFilePath', {
downloadInfo,
filePath: path.join(rootState.setting.download.savePath, downloadInfo.fileName),
})
// 开始任务 // 开始任务
commit('onStart', downloadInfo) commit('onStart', downloadInfo)
commit('setStatusText', { downloadInfo, text: '任务初始化中' }) commit('setStatusText', { downloadInfo, text: '任务初始化中' })
@ -239,10 +302,10 @@ const actions = {
onCompleted() { onCompleted() {
// if (downloadInfo.progress.progress != '100.00') { // if (downloadInfo.progress.progress != '100.00') {
// delete dls[downloadInfo.key] // delete dls[downloadInfo.key]
// return this.dispatch('download/startTask', downloadInfo) // return dispatch('startTask', downloadInfo)
// } // }
commit('onCompleted', downloadInfo) commit('onCompleted', downloadInfo)
_this.dispatch('download/startTask') dispatch('startTask')
saveMeta(downloadInfo, downloadInfo.filePath, rootState.setting.download.isEmbedPic) saveMeta(downloadInfo, downloadInfo.filePath, rootState.setting.download.isEmbedPic)
if (rootState.setting.download.isDownloadLrc) downloadLyric(downloadInfo, downloadInfo.filePath) if (rootState.setting.download.isDownloadLrc) downloadLyric(downloadInfo, downloadInfo.filePath)
@ -252,7 +315,7 @@ const actions = {
// console.log(tryNum[downloadInfo.key]) // console.log(tryNum[downloadInfo.key])
if (++tryNum[downloadInfo.key] > 2) { if (++tryNum[downloadInfo.key] > 2) {
commit('onError', downloadInfo) commit('onError', downloadInfo)
_this.dispatch('download/startTask') dispatch('startTask')
return return
} }
if (err.code == 'ENOTFOUND') { if (err.code == 'ENOTFOUND') {
@ -266,7 +329,7 @@ const actions = {
onFail(response) { onFail(response) {
if (++tryNum[downloadInfo.key] > 2) { if (++tryNum[downloadInfo.key] > 2) {
commit('onError', downloadInfo) commit('onError', downloadInfo)
_this.dispatch('download/startTask') dispatch('startTask')
return return
} }
switch (response.statusCode) { switch (response.statusCode) {
@ -286,7 +349,7 @@ const actions = {
}, },
onStop() { onStop() {
commit('pauseTask', downloadInfo) commit('pauseTask', downloadInfo)
_this.dispatch('download/startTask') dispatch('startTask')
}, },
} }
commit('setStatusText', { downloadInfo, text: '获取URL中...' }) commit('setStatusText', { downloadInfo, text: '获取URL中...' })
@ -302,47 +365,89 @@ const actions = {
// console.log(err.message) // console.log(err.message)
commit('onError', downloadInfo) commit('onError', downloadInfo)
commit('setStatusText', { downloadInfo, text: err.message }) commit('setStatusText', { downloadInfo, text: err.message })
this.dispatch('download/startTask') dispatch('startTask')
}) })
}, },
// startTaskMultiple({ state, rootState }, list) { async removeTask({ commit, state, dispatch }, index) {
// },
removeTask({ commit, state }, index) {
let info = state.list[index] let info = state.list[index]
if (state.list[index].status == state.downloadStatus.RUN) {
if (dls[info.key]) { if (dls[info.key]) {
dls[info.key].stop().finally(() => { if (info.status == state.downloadStatus.RUN) {
try {
await dls[info.key].stop()
} catch (_) {}
}
delete dls[info.key] delete dls[info.key]
})
}
} }
commit('removeTask', index) commit('removeTask', index)
if (dls[info.key]) delete dls[info.key] if (info.status != state.downloadStatus.COMPLETED) {
;(info.status != state.downloadStatus.COMPLETED ? deleteFile(info.filePath) : Promise.resolve()).finally(() => { try {
this.dispatch('download/startTask') await deleteFile(info.filePath)
}) } catch (_) {}
}
switch (info.status) {
case state.downloadStatus.RUN:
case state.downloadStatus.WAITING:
await dispatch('startTask')
}
}, },
async removeTaskMultiple({ commit, rootState, state }, list) { async removeTasks(store, list) {
list.forEach(item => { let { rootState, state } = store
let index = state.list.indexOf(item) if (isRuningActionTask) return
if (index < 0) return isRuningActionTask = true
// this.dispatch('download/removeTask', index) await removeTasks(store, [...list])
if (state.list[index].status == state.downloadStatus.RUN) {
if (dls[item.key]) {
dls[item.key].stop().finally(() => {
delete dls[item.key]
})
}
}
commit('removeTask', index)
if (dls[item.key]) delete dls[item.key]
})
let result = getStartTask(state.list, state.downloadStatus, rootState.setting.download.maxDownloadNum) let result = getStartTask(state.list, state.downloadStatus, rootState.setting.download.maxDownloadNum)
while (result) { while (result) {
this.dispatch('download/startTask', result) store.dispatch('startTask', result)
result = getStartTask(state.list, state.downloadStatus, rootState.setting.download.maxDownloadNum) result = getStartTask(state.list, state.downloadStatus, rootState.setting.download.maxDownloadNum)
} }
isRuningActionTask = false
},
async startTask({ state, rootState, commit, dispatch }, downloadInfo) {
// 检查是否可以开始任务
let result = getStartTask(state.list, state.downloadStatus, rootState.setting.download.maxDownloadNum)
if (result) {
if (!downloadInfo || downloadInfo.isComplate || downloadInfo.status == state.downloadStatus.RUN) downloadInfo = result
} else {
if (downloadInfo) commit('setStatus', { downloadInfo, status: state.downloadStatus.WAITING })
return
}
let dl = dls[downloadInfo.key]
if (dl) {
commit('updateFilePath', {
downloadInfo,
filePath: path.join(rootState.setting.download.savePath, downloadInfo.fileName),
})
dl.updateSaveInfo(rootState.setting.download.savePath, downloadInfo.fileName)
try {
await dl.start()
} catch (_) {}
} else {
await dispatch('handleStartTask', downloadInfo)
}
},
async startTasks(store, list) {
if (isRuningActionTask) return
isRuningActionTask = true
await startTasks(store, [...list])
isRuningActionTask = false
},
async pauseTask({ state, commit }, index) {
let item = state.list[index]
if (item.isComplate) return
let dl = dls[item.key]
if (dl) {
try {
await dl.stop()
} catch (_) {}
}
commit('pauseTask', item)
},
async pauseTasks(store, list) {
if (isRuningActionTask) return
isRuningActionTask = true
await pauseTasks(store, [...list])
isRuningActionTask = false
}, },
} }

View File

@ -79,7 +79,7 @@ export default {
}, },
computed: { computed: {
...mapGetters(['setting']), ...mapGetters(['setting']),
...mapGetters('download', ['list', 'dls', 'downloadStatus']), ...mapGetters('download', ['list', 'downloadStatus']),
...mapGetters('player', ['listId', 'playIndex']), ...mapGetters('player', ['listId', 'playIndex']),
isPlayList() { isPlayList() {
return this.listId == 'download' return this.listId == 'download'
@ -126,9 +126,8 @@ export default {
this.unlistenEvent() this.unlistenEvent()
}, },
methods: { methods: {
...mapActions('download', ['removeTask', 'removeTaskMultiple', 'startTask']), ...mapActions('download', ['removeTask', 'removeTasks', 'startTask', 'startTasks', 'pauseTask', 'pauseTasks']),
...mapMutations('player', ['setList']), ...mapMutations('player', ['setList']),
...mapMutations('download', ['pauseTask', 'updateFilePath']),
listenEvent() { listenEvent() {
window.eventHub.$on('shift_down', this.handle_shift_down) window.eventHub.$on('shift_down', this.handle_shift_down)
window.eventHub.$on('shift_up', this.handle_shift_up) window.eventHub.$on('shift_up', this.handle_shift_up)
@ -166,27 +165,6 @@ export default {
handle_mod_a_up() { handle_mod_a_up() {
if (this.keyEvent.isADown) this.keyEvent.isADown = false if (this.keyEvent.isADown) this.keyEvent.isADown = false
}, },
handlePauseTask(index) {
let info = this.list[index]
let dl = this.dls[info.key]
dl ? dl.stop() : this.pauseTask(info)
console.log('pause')
},
handleStartTask(index) {
console.log('start')
let info = this.list[index]
let dl = this.dls[info.key]
if (dl) {
this.updateFilePath({
downloadInfo: info,
filePath: path.join(this.setting.download.savePath, info.fileName),
})
dl.updateSaveInfo(this.setting.download.savePath, info.fileName)
dl.start()
} else {
this.startTask(info)
}
},
handleDoubleClick(event, index) { handleDoubleClick(event, index) {
if (event.target.classList.contains('select')) return if (event.target.classList.contains('select')) return
@ -268,17 +246,18 @@ export default {
this.setList({ list: this.list, listId: 'download', index: this.list.findIndex(i => i.key === targetSong.key) }) this.setList({ list: this.list, listId: 'download', index: this.list.findIndex(i => i.key === targetSong.key) })
}, },
handleListBtnClick(info) { handleListBtnClick(info) {
const key = this.showList[info.index].key let item = this.showList[info.index]
const key = item.key
let index = this.list.findIndex(i => i.key === key) let index = this.list.findIndex(i => i.key === key)
switch (info.action) { switch (info.action) {
case 'play': case 'play':
this.handlePlay(index) this.handlePlay(index)
break break
case 'start': case 'start':
this.handleStartTask(index) this.startTask(item)
break break
case 'pause': case 'pause':
this.handlePauseTask(index) this.pauseTask(index)
break break
case 'remove': case 'remove':
this.removeTask(index) this.removeTask(index)
@ -300,38 +279,22 @@ export default {
node.classList.add('active') node.classList.add('active')
} }
}, },
handleFlowBtnClick(action) { async handleFlowBtnClick(action) {
let selectdData = [...this.selectdData]
this.removeAllSelect()
await this.$nextTick()
switch (action) { switch (action) {
case 'start': case 'start':
this.selectdData.forEach(item => { this.startTasks(selectdData)
if (item.isComplate || item.status == this.downloadStatus.RUN) return
let index = this.list.indexOf(item)
if (index < 0) return
this.handleStartTask(index)
})
break break
case 'pause': { case 'pause':
let runs = [] this.pauseTasks(selectdData)
this.selectdData.forEach(item => {
if (item.isComplate || item.status == this.downloadStatus.PAUSE) return
if (item.status == this.downloadStatus.RUN) return runs.push(item)
let index = this.list.indexOf(item)
if (index < 0) return
this.handlePauseTask(index)
})
runs.forEach(item => {
if (item.isComplate || item.status == this.downloadStatus.PAUSE) return
let index = this.list.indexOf(item)
if (index < 0) return
this.handlePauseTask(index)
})
break break
}
case 'remove': case 'remove':
this.removeTaskMultiple(this.selectdData) this.removeTasks(selectdData)
break break
} }
this.removeAllSelect()
}, },
async handleOpenFolder(index) { async handleOpenFolder(index) {
let path = this.list[index].filePath let path = this.list[index].filePath