优化任务下载状态显示
parent
2337a3e8a3
commit
1de087eac7
|
@ -21,6 +21,7 @@
|
|||
- 优化搜索框交互逻辑,防止鼠标操作时意外搜索候选列表的内容
|
||||
- 添加对wy源某些歌曲有问题的歌词进行修复
|
||||
- 改进本地音乐在线信息的匹配机制
|
||||
- 优化任务下载状态显示,现在下载时若数据传输完成但数据写入未完成时会显示相应的状态
|
||||
|
||||
### 修复
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ declare global {
|
|||
speed: string
|
||||
downloaded: number
|
||||
total: number
|
||||
writeQueue: number
|
||||
}
|
||||
|
||||
interface DownloadTaskActionBase <A> {
|
||||
|
@ -50,6 +51,7 @@ declare global {
|
|||
total: number
|
||||
progress: number
|
||||
speed: string
|
||||
writeQueue: number
|
||||
metadata: {
|
||||
musicInfo: LX.Music.MusicInfoOnline
|
||||
url: string | null
|
||||
|
|
|
@ -8,6 +8,7 @@ import { request, type Options as RequestOptions } from './request'
|
|||
|
||||
export interface Options {
|
||||
forceResume: boolean
|
||||
timeout: number
|
||||
requestOptions: RequestOptions
|
||||
}
|
||||
|
||||
|
@ -23,6 +24,7 @@ const defaultRequestOptions: Options['requestOptions'] = {
|
|||
}
|
||||
const defaultOptions: Options = {
|
||||
forceResume: true,
|
||||
timeout: 20_000,
|
||||
requestOptions: { ...defaultRequestOptions },
|
||||
}
|
||||
|
||||
|
@ -41,6 +43,7 @@ class Task extends EventEmitter {
|
|||
private redirectNum = 0
|
||||
private dataWriteQueueLength = 0
|
||||
private closeWaiting = false
|
||||
private timeout: null | NodeJS.Timeout = null
|
||||
|
||||
|
||||
constructor(url: string, savePath: string, filename: string, options: Partial<Options> = {}) {
|
||||
|
@ -69,6 +72,8 @@ class Task extends EventEmitter {
|
|||
this.progress.speed = 0
|
||||
this.dataWriteQueueLength = 0
|
||||
this.closeWaiting = false
|
||||
this.__clearTimeout()
|
||||
this.__startTimeout()
|
||||
if (startByte) this.requestOptions.headers!.range = `bytes=${startByte}-${endByte}`
|
||||
|
||||
if (!path) return
|
||||
|
@ -144,6 +149,7 @@ class Task extends EventEmitter {
|
|||
}
|
||||
this.status = STATUS.failed
|
||||
this.emit('fail', response)
|
||||
this.__clearTimeout()
|
||||
this.__closeRequest()
|
||||
void this.__closeWriteStream()
|
||||
return
|
||||
|
@ -156,6 +162,7 @@ class Task extends EventEmitter {
|
|||
return
|
||||
}
|
||||
this.status = STATUS.running
|
||||
this.__startTimeout()
|
||||
response
|
||||
.on('data', this.__handleWriteData.bind(this))
|
||||
.on('error', err => { this.__handleError(err) })
|
||||
|
@ -222,6 +229,7 @@ class Task extends EventEmitter {
|
|||
|
||||
__handleComplete() {
|
||||
if (this.status == STATUS.error) return
|
||||
this.__clearTimeout()
|
||||
void this.__closeWriteStream().then(() => {
|
||||
if (this.progress.downloaded == this.progress.total) {
|
||||
this.status = STATUS.completed
|
||||
|
@ -237,6 +245,7 @@ class Task extends EventEmitter {
|
|||
__handleError(error: Error) {
|
||||
if (this.status == STATUS.error) return
|
||||
this.status = STATUS.error
|
||||
this.__clearTimeout()
|
||||
this.__closeRequest()
|
||||
void this.__closeWriteStream()
|
||||
if (error.message == 'aborted') return
|
||||
|
@ -304,9 +313,11 @@ class Task extends EventEmitter {
|
|||
return
|
||||
}
|
||||
this.dataWriteQueueLength++
|
||||
this.__startTimeout()
|
||||
this.__calculateProgress(chunk.length)
|
||||
this.ws.write(chunk, err => {
|
||||
this.dataWriteQueueLength--
|
||||
if (this.status == STATUS.running) this.__calculateProgress(0)
|
||||
if (err) {
|
||||
console.log(err)
|
||||
this.__handleError(err)
|
||||
|
@ -322,24 +333,38 @@ class Task extends EventEmitter {
|
|||
let chunkLen = chunk.length
|
||||
let isOk
|
||||
if (chunkLen >= resumeLastChunkLen) {
|
||||
isOk = chunk.slice(0, resumeLastChunkLen).toString('hex') === this.resumeLastChunk!.toString('hex')
|
||||
isOk = chunk.subarray(0, resumeLastChunkLen).toString('hex') === this.resumeLastChunk!.toString('hex')
|
||||
if (!isOk) return null
|
||||
|
||||
this.resumeLastChunk = null
|
||||
return chunk.slice(resumeLastChunkLen)
|
||||
return chunk.subarray(resumeLastChunkLen)
|
||||
} else {
|
||||
isOk = chunk.slice(0, chunkLen).toString('hex') === this.resumeLastChunk!.slice(0, chunkLen).toString('hex')
|
||||
isOk = chunk.subarray(0, chunkLen).toString('hex') === this.resumeLastChunk!.subarray(0, chunkLen).toString('hex')
|
||||
if (!isOk) return null
|
||||
this.resumeLastChunk = this.resumeLastChunk!.slice(chunkLen)
|
||||
return chunk.slice(chunkLen)
|
||||
this.resumeLastChunk = this.resumeLastChunk!.subarray(chunkLen)
|
||||
return chunk.subarray(chunkLen)
|
||||
}
|
||||
}
|
||||
|
||||
async __handleStop() {
|
||||
this.__clearTimeout()
|
||||
this.__closeRequest()
|
||||
return this.__closeWriteStream()
|
||||
}
|
||||
|
||||
private __clearTimeout() {
|
||||
if (!this.timeout) return
|
||||
clearTimeout(this.timeout)
|
||||
this.timeout = null
|
||||
}
|
||||
|
||||
private __startTimeout() {
|
||||
this.__clearTimeout()
|
||||
this.timeout = setTimeout(() => {
|
||||
this.__handleError(new Error('download timeout'))
|
||||
}, this.options.timeout)
|
||||
}
|
||||
|
||||
__calculateProgress(receivedBytes: number) {
|
||||
const currentTime = performance.now()
|
||||
const elaspsedTime = currentTime - this.statsEstimate.time
|
||||
|
@ -350,7 +375,7 @@ class Task extends EventEmitter {
|
|||
|
||||
|
||||
// emit the progress every second or if finished
|
||||
if (progress.downloaded === progress.total || elaspsedTime > 1000) {
|
||||
if ((progress.downloaded === progress.total && this.dataWriteQueueLength == 0) || elaspsedTime > 1000) {
|
||||
this.statsEstimate.time = currentTime
|
||||
this.statsEstimate.bytes = progress.downloaded - this.statsEstimate.prevBytes
|
||||
this.statsEstimate.prevBytes = progress.downloaded
|
||||
|
@ -359,6 +384,7 @@ class Task extends EventEmitter {
|
|||
downloaded: progress.downloaded,
|
||||
progress: progress.progress,
|
||||
speed: this.statsEstimate.bytes,
|
||||
writeQueue: this.dataWriteQueueLength,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ export const createDownload = ({
|
|||
speed,
|
||||
downloaded: stats.downloaded,
|
||||
total: stats.total,
|
||||
writeQueue: stats.writeQueue,
|
||||
})
|
||||
// if (debugDownload) {
|
||||
// const downloaded = sizeFormate(stats.downloaded)
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
"download_status_error_write": "The song save location is occupied or does not have write permission, please try to change the song save directory or restart the software or restart the computer, the error details:",
|
||||
"download_status_start": "start download",
|
||||
"download_status_url_geting": "Getting music link...",
|
||||
"download_status_write_queue": "Data is being written ({num})",
|
||||
"duplicate_list_tip": "You have favorited this list [{name}] before, do you need to update the songs in it?",
|
||||
"export": "Export",
|
||||
"fullscreen_exit": "Exit Full Screen",
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
"download_status_error_write": "歌曲保存位置被占用或没有写入权限,请尝试更改歌曲保存目录或重启软件或重启电脑,错误详情:",
|
||||
"download_status_start": "开始下载",
|
||||
"download_status_url_geting": "音乐链接获取中...",
|
||||
"download_status_write_queue": "数据写入中({num})",
|
||||
"duplicate_list_tip": "你之前已收藏过该列表 [{name}],是否需要更新里面的歌曲?",
|
||||
"export": "导出",
|
||||
"fullscreen_exit": "退出全屏",
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
"download_status_error_write": "歌曲儲存位置被佔用或沒有寫入權限,請嘗試變更歌曲儲存目錄或重新啟動軟體或重新啟動電腦,錯誤詳情:",
|
||||
"download_status_start": "開始下載",
|
||||
"download_status_url_geting": "音樂連結獲取中...",
|
||||
"download_status_write_queue": "資料寫入中({num})",
|
||||
"duplicate_list_tip": "你之前已收藏過該清單 [{name}],是否需要更新裡面的歌曲?",
|
||||
"export": "匯出",
|
||||
"fullscreen_exit": "退出全螢幕",
|
||||
|
|
|
@ -41,6 +41,7 @@ const initDownloadList = () => {
|
|||
total: item.progress_total,
|
||||
progress: item.progress_total ? parseInt((item.progress_downloaded / item.progress_total).toFixed(2)) * 100 : 0,
|
||||
speed: '',
|
||||
writeQueue: 0,
|
||||
metadata: {
|
||||
musicInfo,
|
||||
url: item.url,
|
||||
|
|
|
@ -82,10 +82,17 @@ const updateFilePath = (downloadInfo: LX.Download.ListItem, filePath: string) =>
|
|||
}
|
||||
|
||||
const setProgress = (downloadInfo: LX.Download.ListItem, progress: LX.Download.ProgressInfo) => {
|
||||
downloadInfo.progress = progress.progress
|
||||
downloadInfo.total = progress.total
|
||||
downloadInfo.downloaded = progress.downloaded
|
||||
downloadInfo.speed = progress.speed
|
||||
downloadInfo.writeQueue = progress.writeQueue
|
||||
if (progress.progress == 100) {
|
||||
downloadInfo.speed = ''
|
||||
downloadInfo.progress = 99.99
|
||||
setStatusText(downloadInfo, window.i18n.t('download_status_write_queue', { num: progress.writeQueue }))
|
||||
} else {
|
||||
downloadInfo.speed = progress.speed
|
||||
downloadInfo.progress = progress.progress
|
||||
}
|
||||
throttleUpdateTask([downloadInfo])
|
||||
}
|
||||
|
||||
|
@ -248,6 +255,7 @@ const handleStartTask = async(downloadInfo: LX.Download.ListItem) => {
|
|||
setStatus(downloadInfo, DOWNLOAD_STATUS.RUN)
|
||||
break
|
||||
case 'complete':
|
||||
downloadInfo.progress = 100
|
||||
saveMeta(downloadInfo)
|
||||
downloadLyric(downloadInfo)
|
||||
void window.lx.worker.download.removeTask(downloadInfo.id)
|
||||
|
|
|
@ -205,6 +205,7 @@ const createTask = async(downloadInfo: LX.Download.ListItem, savePath: string, s
|
|||
downloadInfo.downloaded = status.downloaded
|
||||
downloadInfo.progress = status.progress
|
||||
downloadInfo.speed = status.speed
|
||||
downloadInfo.writeQueue = status.writeQueue
|
||||
sendAction(downloadInfo.id, { action: 'progress', data: status })
|
||||
// console.log(status)
|
||||
},
|
||||
|
|
|
@ -80,6 +80,7 @@ export const createDownloadInfo = (musicInfo: LX.Music.MusicInfoOnline, type: LX
|
|||
total: 0,
|
||||
progress: 0,
|
||||
speed: '',
|
||||
writeQueue: 0,
|
||||
metadata: {
|
||||
musicInfo,
|
||||
url: null,
|
||||
|
|
Loading…
Reference in New Issue