优化任务下载状态显示

pull/1761/head
lyswhut 2023-12-30 12:31:18 +08:00
parent 2337a3e8a3
commit 1de087eac7
11 changed files with 52 additions and 8 deletions

View File

@ -21,6 +21,7 @@
- 优化搜索框交互逻辑,防止鼠标操作时意外搜索候选列表的内容 - 优化搜索框交互逻辑,防止鼠标操作时意外搜索候选列表的内容
- 添加对wy源某些歌曲有问题的歌词进行修复 - 添加对wy源某些歌曲有问题的歌词进行修复
- 改进本地音乐在线信息的匹配机制 - 改进本地音乐在线信息的匹配机制
- 优化任务下载状态显示,现在下载时若数据传输完成但数据写入未完成时会显示相应的状态
### 修复 ### 修复

View File

@ -21,6 +21,7 @@ declare global {
speed: string speed: string
downloaded: number downloaded: number
total: number total: number
writeQueue: number
} }
interface DownloadTaskActionBase <A> { interface DownloadTaskActionBase <A> {
@ -50,6 +51,7 @@ declare global {
total: number total: number
progress: number progress: number
speed: string speed: string
writeQueue: number
metadata: { metadata: {
musicInfo: LX.Music.MusicInfoOnline musicInfo: LX.Music.MusicInfoOnline
url: string | null url: string | null

View File

@ -8,6 +8,7 @@ import { request, type Options as RequestOptions } from './request'
export interface Options { export interface Options {
forceResume: boolean forceResume: boolean
timeout: number
requestOptions: RequestOptions requestOptions: RequestOptions
} }
@ -23,6 +24,7 @@ const defaultRequestOptions: Options['requestOptions'] = {
} }
const defaultOptions: Options = { const defaultOptions: Options = {
forceResume: true, forceResume: true,
timeout: 20_000,
requestOptions: { ...defaultRequestOptions }, requestOptions: { ...defaultRequestOptions },
} }
@ -41,6 +43,7 @@ class Task extends EventEmitter {
private redirectNum = 0 private redirectNum = 0
private dataWriteQueueLength = 0 private dataWriteQueueLength = 0
private closeWaiting = false private closeWaiting = false
private timeout: null | NodeJS.Timeout = null
constructor(url: string, savePath: string, filename: string, options: Partial<Options> = {}) { constructor(url: string, savePath: string, filename: string, options: Partial<Options> = {}) {
@ -69,6 +72,8 @@ class Task extends EventEmitter {
this.progress.speed = 0 this.progress.speed = 0
this.dataWriteQueueLength = 0 this.dataWriteQueueLength = 0
this.closeWaiting = false this.closeWaiting = false
this.__clearTimeout()
this.__startTimeout()
if (startByte) this.requestOptions.headers!.range = `bytes=${startByte}-${endByte}` if (startByte) this.requestOptions.headers!.range = `bytes=${startByte}-${endByte}`
if (!path) return if (!path) return
@ -144,6 +149,7 @@ class Task extends EventEmitter {
} }
this.status = STATUS.failed this.status = STATUS.failed
this.emit('fail', response) this.emit('fail', response)
this.__clearTimeout()
this.__closeRequest() this.__closeRequest()
void this.__closeWriteStream() void this.__closeWriteStream()
return return
@ -156,6 +162,7 @@ class Task extends EventEmitter {
return return
} }
this.status = STATUS.running this.status = STATUS.running
this.__startTimeout()
response response
.on('data', this.__handleWriteData.bind(this)) .on('data', this.__handleWriteData.bind(this))
.on('error', err => { this.__handleError(err) }) .on('error', err => { this.__handleError(err) })
@ -222,6 +229,7 @@ class Task extends EventEmitter {
__handleComplete() { __handleComplete() {
if (this.status == STATUS.error) return if (this.status == STATUS.error) return
this.__clearTimeout()
void this.__closeWriteStream().then(() => { void this.__closeWriteStream().then(() => {
if (this.progress.downloaded == this.progress.total) { if (this.progress.downloaded == this.progress.total) {
this.status = STATUS.completed this.status = STATUS.completed
@ -237,6 +245,7 @@ class Task extends EventEmitter {
__handleError(error: Error) { __handleError(error: Error) {
if (this.status == STATUS.error) return if (this.status == STATUS.error) return
this.status = STATUS.error this.status = STATUS.error
this.__clearTimeout()
this.__closeRequest() this.__closeRequest()
void this.__closeWriteStream() void this.__closeWriteStream()
if (error.message == 'aborted') return if (error.message == 'aborted') return
@ -304,9 +313,11 @@ class Task extends EventEmitter {
return return
} }
this.dataWriteQueueLength++ this.dataWriteQueueLength++
this.__startTimeout()
this.__calculateProgress(chunk.length) this.__calculateProgress(chunk.length)
this.ws.write(chunk, err => { this.ws.write(chunk, err => {
this.dataWriteQueueLength-- this.dataWriteQueueLength--
if (this.status == STATUS.running) this.__calculateProgress(0)
if (err) { if (err) {
console.log(err) console.log(err)
this.__handleError(err) this.__handleError(err)
@ -322,24 +333,38 @@ class Task extends EventEmitter {
let chunkLen = chunk.length let chunkLen = chunk.length
let isOk let isOk
if (chunkLen >= resumeLastChunkLen) { 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 if (!isOk) return null
this.resumeLastChunk = null this.resumeLastChunk = null
return chunk.slice(resumeLastChunkLen) return chunk.subarray(resumeLastChunkLen)
} else { } 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 if (!isOk) return null
this.resumeLastChunk = this.resumeLastChunk!.slice(chunkLen) this.resumeLastChunk = this.resumeLastChunk!.subarray(chunkLen)
return chunk.slice(chunkLen) return chunk.subarray(chunkLen)
} }
} }
async __handleStop() { async __handleStop() {
this.__clearTimeout()
this.__closeRequest() this.__closeRequest()
return this.__closeWriteStream() 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) { __calculateProgress(receivedBytes: number) {
const currentTime = performance.now() const currentTime = performance.now()
const elaspsedTime = currentTime - this.statsEstimate.time const elaspsedTime = currentTime - this.statsEstimate.time
@ -350,7 +375,7 @@ class Task extends EventEmitter {
// emit the progress every second or if finished // 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.time = currentTime
this.statsEstimate.bytes = progress.downloaded - this.statsEstimate.prevBytes this.statsEstimate.bytes = progress.downloaded - this.statsEstimate.prevBytes
this.statsEstimate.prevBytes = progress.downloaded this.statsEstimate.prevBytes = progress.downloaded
@ -359,6 +384,7 @@ class Task extends EventEmitter {
downloaded: progress.downloaded, downloaded: progress.downloaded,
progress: progress.progress, progress: progress.progress,
speed: this.statsEstimate.bytes, speed: this.statsEstimate.bytes,
writeQueue: this.dataWriteQueueLength,
}) })
} }
} }

View File

@ -74,6 +74,7 @@ export const createDownload = ({
speed, speed,
downloaded: stats.downloaded, downloaded: stats.downloaded,
total: stats.total, total: stats.total,
writeQueue: stats.writeQueue,
}) })
// if (debugDownload) { // if (debugDownload) {
// const downloaded = sizeFormate(stats.downloaded) // const downloaded = sizeFormate(stats.downloaded)

View File

@ -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_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_start": "start download",
"download_status_url_geting": "Getting music link...", "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?", "duplicate_list_tip": "You have favorited this list [{name}] before, do you need to update the songs in it?",
"export": "Export", "export": "Export",
"fullscreen_exit": "Exit Full Screen", "fullscreen_exit": "Exit Full Screen",

View File

@ -71,6 +71,7 @@
"download_status_error_write": "歌曲保存位置被占用或没有写入权限,请尝试更改歌曲保存目录或重启软件或重启电脑,错误详情:", "download_status_error_write": "歌曲保存位置被占用或没有写入权限,请尝试更改歌曲保存目录或重启软件或重启电脑,错误详情:",
"download_status_start": "开始下载", "download_status_start": "开始下载",
"download_status_url_geting": "音乐链接获取中...", "download_status_url_geting": "音乐链接获取中...",
"download_status_write_queue": "数据写入中({num}",
"duplicate_list_tip": "你之前已收藏过该列表 [{name}],是否需要更新里面的歌曲?", "duplicate_list_tip": "你之前已收藏过该列表 [{name}],是否需要更新里面的歌曲?",
"export": "导出", "export": "导出",
"fullscreen_exit": "退出全屏", "fullscreen_exit": "退出全屏",

View File

@ -71,6 +71,7 @@
"download_status_error_write": "歌曲儲存位置被佔用或沒有寫入權限,請嘗試變更歌曲儲存目錄或重新啟動軟體或重新啟動電腦,錯誤詳情:", "download_status_error_write": "歌曲儲存位置被佔用或沒有寫入權限,請嘗試變更歌曲儲存目錄或重新啟動軟體或重新啟動電腦,錯誤詳情:",
"download_status_start": "開始下載", "download_status_start": "開始下載",
"download_status_url_geting": "音樂連結獲取中...", "download_status_url_geting": "音樂連結獲取中...",
"download_status_write_queue": "資料寫入中({num}",
"duplicate_list_tip": "你之前已收藏過該清單 [{name}],是否需要更新裡面的歌曲?", "duplicate_list_tip": "你之前已收藏過該清單 [{name}],是否需要更新裡面的歌曲?",
"export": "匯出", "export": "匯出",
"fullscreen_exit": "退出全螢幕", "fullscreen_exit": "退出全螢幕",

View File

@ -41,6 +41,7 @@ const initDownloadList = () => {
total: item.progress_total, total: item.progress_total,
progress: item.progress_total ? parseInt((item.progress_downloaded / item.progress_total).toFixed(2)) * 100 : 0, progress: item.progress_total ? parseInt((item.progress_downloaded / item.progress_total).toFixed(2)) * 100 : 0,
speed: '', speed: '',
writeQueue: 0,
metadata: { metadata: {
musicInfo, musicInfo,
url: item.url, url: item.url,

View File

@ -82,10 +82,17 @@ const updateFilePath = (downloadInfo: LX.Download.ListItem, filePath: string) =>
} }
const setProgress = (downloadInfo: LX.Download.ListItem, progress: LX.Download.ProgressInfo) => { const setProgress = (downloadInfo: LX.Download.ListItem, progress: LX.Download.ProgressInfo) => {
downloadInfo.progress = progress.progress
downloadInfo.total = progress.total downloadInfo.total = progress.total
downloadInfo.downloaded = progress.downloaded 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]) throttleUpdateTask([downloadInfo])
} }
@ -248,6 +255,7 @@ const handleStartTask = async(downloadInfo: LX.Download.ListItem) => {
setStatus(downloadInfo, DOWNLOAD_STATUS.RUN) setStatus(downloadInfo, DOWNLOAD_STATUS.RUN)
break break
case 'complete': case 'complete':
downloadInfo.progress = 100
saveMeta(downloadInfo) saveMeta(downloadInfo)
downloadLyric(downloadInfo) downloadLyric(downloadInfo)
void window.lx.worker.download.removeTask(downloadInfo.id) void window.lx.worker.download.removeTask(downloadInfo.id)

View File

@ -205,6 +205,7 @@ const createTask = async(downloadInfo: LX.Download.ListItem, savePath: string, s
downloadInfo.downloaded = status.downloaded downloadInfo.downloaded = status.downloaded
downloadInfo.progress = status.progress downloadInfo.progress = status.progress
downloadInfo.speed = status.speed downloadInfo.speed = status.speed
downloadInfo.writeQueue = status.writeQueue
sendAction(downloadInfo.id, { action: 'progress', data: status }) sendAction(downloadInfo.id, { action: 'progress', data: status })
// console.log(status) // console.log(status)
}, },

View File

@ -80,6 +80,7 @@ export const createDownloadInfo = (musicInfo: LX.Music.MusicInfoOnline, type: LX
total: 0, total: 0,
progress: 0, progress: 0,
speed: '', speed: '',
writeQueue: 0,
metadata: { metadata: {
musicInfo, musicInfo,
url: null, url: null,