diff --git a/package-lock.json b/package-lock.json index ce0f5de1..957c905c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "lx-music-desktop", - "version": "0.10.0", + "version": "0.11.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -5296,9 +5296,9 @@ } }, "core-js": { - "version": "3.4.0", - "resolved": "https://registry.npm.taobao.org/core-js/download/core-js-3.4.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js%2Fdownload%2Fcore-js-3.4.0.tgz", - "integrity": "sha1-KepHhgF4nHLyl46buY9DVG+J06o=", + "version": "3.4.1", + "resolved": "https://registry.npm.taobao.org/core-js/download/core-js-3.4.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js%2Fdownload%2Fcore-js-3.4.1.tgz", + "integrity": "sha1-dt1oKEEpAKsnyM4LIuYRTXziGxg=", "dev": true }, "core-js-compat": { @@ -11101,11 +11101,6 @@ "lower-case": "^1.1.1" } }, - "node-downloader-helper": { - "version": "1.0.10", - "resolved": "https://registry.npm.taobao.org/node-downloader-helper/download/node-downloader-helper-1.0.10.tgz", - "integrity": "sha1-bt5ymVH45yl/HlbkHDgrH7DSPw0=" - }, "node-forge": { "version": "0.9.0", "resolved": "https://registry.npm.taobao.org/node-forge/download/node-forge-0.9.0.tgz?cache=0&sync_timestamp=1569524876130&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnode-forge%2Fdownload%2Fnode-forge-0.9.0.tgz", @@ -15342,9 +15337,9 @@ "dev": true }, "vuex": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/vuex/download/vuex-3.1.1.tgz", - "integrity": "sha1-DCZL/jDNvM+Wq52zF30hGCilkQ4=" + "version": "3.1.2", + "resolved": "https://registry.npm.taobao.org/vuex/download/vuex-3.1.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvuex%2Fdownload%2Fvuex-3.1.2.tgz", + "integrity": "sha1-ooY/QAWqc/JYflXD+t8/AfacfU0=" }, "vuex-electron": { "version": "1.0.3", diff --git a/package.json b/package.json index 9a61879c..cf7ec1dc 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,7 @@ "chalk": "^3.0.0", "changelog-parser": "^2.8.0", "copy-webpack-plugin": "^5.0.5", - "core-js": "^3.4.0", + "core-js": "^3.4.1", "cos-nodejs-sdk-v5": "^2.5.14", "cross-env": "^6.0.3", "css-loader": "^3.2.0", @@ -203,13 +203,12 @@ "flac-metadata": "^0.1.1", "js-htmlencode": "^0.3.0", "lrc-file-parser": "^0.1.14", - "node-downloader-helper": "^1.0.10", "node-id3": "^0.1.12", "request": "^2.88.0", "vue": "^2.6.10", "vue-electron": "^1.0.6", "vue-router": "^3.1.3", - "vuex": "^3.1.1", + "vuex": "^3.1.2", "vuex-electron": "^1.0.3", "vuex-router-sync": "^5.0.0" } diff --git a/publish/changeLog.md b/publish/changeLog.md index 44f50ca2..f051a5b7 100644 --- a/publish/changeLog.md +++ b/publish/changeLog.md @@ -1,9 +1,16 @@ +由于新下载库仍然没有完成,但下载功能已经可用,so 移除之前使用的第三方下载库,暂时把新下载库的下载模块直接加入本程序,若出现下载问题欢迎反馈! + ### 新增 -- 新增歌曲缓冲定时器,尝试用于解决网络正常但是歌曲缓冲过久的问题 -- 新增下载管理的任务状态分类 -- 添加**杀毒软件提示有病毒或恶意行为**的说明,可到**常见问题**拉到最后查看(常见问题可在开源地址找到) +- 新增下载功能对代理设置的支持,现在若在软件设置了代理服务器,下载功能也将会走代理网络了 ### 优化 -- 优化更新弹窗机制及其内容描述,对于可以自动更新的版本,现在可以看到软件的下载进度了 +- 新下载模块将对恢复下载的任务进行字节校验,用于解决下载进度超过100%后仍然下载的问题 +- 注意:目前仍然无法暂停处于**链接获取**状态中的任务 + +### 修复 + +- 修复下载列表歌曲状态分类列表操作Bug +- 修复歌曲封面下载失败时仍然执行嵌入封面操作导致报错的问题 +- 跳过重复添加**相同歌曲名与扩展名的歌曲**,例如你之前下载了A歌曲的128k音质,现在想要下载它的320k音质,但由于两者都是MP3格式,会因为重名导致之前的128k音质被覆盖但列表中仍然显示两种音质的问题(但实际上都是指向后面的320k音质) diff --git a/src/renderer/store/modules/download.js b/src/renderer/store/modules/download.js index 9be16982..a75be6d6 100644 --- a/src/renderer/store/modules/download.js +++ b/src/renderer/store/modules/download.js @@ -53,7 +53,7 @@ const getExt = type => { } } -const checkList = (list, musicInfo, type) => list.some(s => s.musicInfo.songmid === musicInfo.songmid && s.type === type) +const checkList = (list, musicInfo, type, ext) => list.some(s => s.musicInfo.songmid === musicInfo.songmid && (s.type === type || s.ext === ext)) const getStartTask = (list, downloadStatus, maxDownloadNum) => { let downloadCount = 0 @@ -121,11 +121,24 @@ const downloadLyric = (downloadInfo, filePath) => { }) } +const refreshUrl = function(commit, downloadInfo) { + commit('setStatusText', { downloadInfo, text: '链接失效,正在刷新链接' }) + getUrl(downloadInfo, true).then(result => { + commit('updateUrl', { downloadInfo, url: result.url }) + commit('setStatusText', { downloadInfo, text: '链接刷新成功' }) + dls[downloadInfo.key].refreshUrl(result.url) + dls[downloadInfo.key].start() + }).catch(err => { + console.log(err) + this.dispatch('download/startTask') + }) +} + // actions const actions = { createDownload({ state, rootState, commit }, { musicInfo, type }) { - if (checkList(state.list, musicInfo, type)) return let ext = getExt(type) + if (checkList(state.list, musicInfo, type, ext)) return const downloadInfo = { isComplate: false, status: state.downloadStatus.WAITING, @@ -146,6 +159,11 @@ const actions = { } downloadInfo.filePath = path.join(rootState.setting.download.savePath, downloadInfo.fileName) commit('addTask', downloadInfo) + try { // 删除同路径下的同名文件 + fs.unlinkSync(downloadInfo.filePath) + } catch (err) { + if (err.code !== 'ENOENT') return commit('setStatusText', { downloadInfo, text: '文件删除失败' }) + } if (dls[downloadInfo.key]) { dls[downloadInfo.key].stop().finally(() => { delete dls[downloadInfo.key] @@ -167,7 +185,7 @@ const actions = { if (!downloadInfo) downloadInfo = result // 开始任务 - commit('onDownload', downloadInfo) + commit('onStart', downloadInfo) commit('setStatusText', { downloadInfo, text: '任务初始化中' }) let msg = checkPath(rootState.setting.download.savePath) if (msg) return commit('setStatusText', '检查下载目录出错: ' + msg) @@ -178,12 +196,12 @@ const actions = { fileName: downloadInfo.fileName, method: 'get', override: true, - onEnd() { - if (downloadInfo.progress.progress != '100.00') { - delete dls[downloadInfo.key] - return this.dispatch('download/startTask', downloadInfo) - } - commit('onEnd', downloadInfo) + onCompleted() { + // if (downloadInfo.progress.progress != '100.00') { + // delete dls[downloadInfo.key] + // return this.dispatch('download/startTask', downloadInfo) + // } + commit('onCompleted', downloadInfo) _this.dispatch('download/startTask') const filePath = path.join(options.path, options.fileName) @@ -199,54 +217,40 @@ const actions = { _this.dispatch('download/startTask') return } - let code - if (err.message.includes('Response status was')) { - code = err.message.replace(/Response status was (\d+)$/, '$1') - } else if (err.code === 'ETIMEDOUT' || err.code == 'ENOTFOUND') { - code = err.code + if (err.code == 'ENOTFOUND') { + refreshUrl.call(_this, commit, downloadInfo) } else { console.log('Download failed, Attempting Retry') - dls[downloadInfo.key].resume() + dls[downloadInfo.key].start() commit('setStatusText', { downloadInfo, text: '正在重试' }) - return - } - switch (code) { - case '401': - case '403': - case '410': - case 'ETIMEDOUT': - case 'ENOTFOUND': - commit('setStatusText', { downloadInfo, text: '链接失效,正在刷新链接' }) - getUrl(downloadInfo, true).then(result => { - commit('updateUrl', { downloadInfo, url: result.url }) - commit('setStatusText', { downloadInfo, text: '链接刷新成功' }) - dls[downloadInfo.key].url = dls[downloadInfo.key].requestURL = result.url - dls[downloadInfo.key].__initProtocol(result.url) - dls[downloadInfo.key].resume() - }).catch(err => { - console.log(err) - _this.dispatch('download/startTask') - }) } }, - // onStateChanged(state) { - // console.log(state) - // }, - onDownload() { - commit('onDownload', downloadInfo) - console.log('on download') + onFail(response) { + commit('onError', downloadInfo) + + if (++tryNum[downloadInfo.key] > 2) { + _this.dispatch('download/startTask') + return + } + switch (response.statusCode) { + case 401: + case 403: + case 410: + refreshUrl.call(_this, commit, downloadInfo) + } + }, + onStart() { + commit('onStart', downloadInfo) + console.log('on start') }, onProgress(status) { commit('onProgress', { downloadInfo, status }) console.log(status) }, - onPause() { + onStop() { commit('pauseTask', downloadInfo) _this.dispatch('download/startTask') }, - onResume() { - commit('resumeTask', downloadInfo) - }, } commit('setStatusText', { downloadInfo, text: '获取URL中...' }) let p = options.url ? Promise.resolve() : getUrl(downloadInfo).then(result => { @@ -315,9 +319,6 @@ const mutations = { downloadInfo.status = state.downloadStatus.PAUSE downloadInfo.statusText = '暂停下载' }, - resumeTask(state, downloadInfo) { - downloadInfo.statusText = '开始下载' - }, setStatusText(state, { downloadInfo, index, text }) { // 设置状态文本 if (downloadInfo) { downloadInfo.statusText = text @@ -352,7 +353,7 @@ const mutations = { state.list[index].status = status } }, - onEnd(state, downloadInfo) { + onCompleted(state, downloadInfo) { downloadInfo.isComplate = true downloadInfo.status = state.downloadStatus.COMPLETED downloadInfo.statusText = '下载完成' @@ -361,7 +362,7 @@ const mutations = { downloadInfo.status = state.downloadStatus.ERROR downloadInfo.statusText = '任务出错' }, - onDownload(state, downloadInfo) { + onStart(state, downloadInfo) { downloadInfo.status = state.downloadStatus.RUN downloadInfo.statusText = '正在下载' }, diff --git a/src/renderer/utils/download/Downloader.js b/src/renderer/utils/download/Downloader.js new file mode 100644 index 00000000..fbeda582 --- /dev/null +++ b/src/renderer/utils/download/Downloader.js @@ -0,0 +1,306 @@ +import fs from 'fs' +import path from 'path' +import request from 'request' +import { EventEmitter } from 'events' +import { performance } from 'perf_hooks' +import { STATUS } from './util' + + +const defaultChunkInfo = { + path: null, + startByte: 0, + endByte: '', +} + +const defaultRequestOptions = { + method: 'GET', + headers: {}, +} +const defaultOptions = { + +} + +class Task extends EventEmitter { + /** + * + * @param {String} url download url + * @param {Object} chunkInfo + * @param {Object} options + */ + constructor(url, savePath, filename, options = {}) { + super() + + this.resumeLastChunk = null + this.downloadUrl = url + this.chunkInfo = Object.assign({}, defaultChunkInfo, { + path: path.join(savePath, filename), + startByte: 0, + }) + if (!this.chunkInfo.endByte) this.chunkInfo.endByte = '' + + this.options = Object.assign({}, defaultOptions, options) + + this.requestOptions = Object.assign({}, defaultRequestOptions, this.options.requestOptions || {}) + if (!this.requestOptions.headers) this.requestOptions.headers = {} + + this.progress = { + total: 0, + downloaded: 0, + speed: 0, + } + this.statsEstimate = { + time: 0, + bytes: 0, + prevBytes: 0, + } + this.status = STATUS.idle + } + + __init() { + this.status = STATUS.init + const { path, startByte, endByte } = this.chunkInfo + if (startByte) this.requestOptions.headers.range = `bytes=${startByte}-${endByte}` + return new Promise((resolve, reject) => { + if (!path) return resolve() + fs.stat(path, (errStat, stats) => { + if (errStat) { + if (errStat.code !== 'ENOENT') { + this.__handleError(errStat) + reject(errStat) + return + } + } else if (stats.size >= 10) { + fs.open(path, 'r', (errOpen, fd) => { + if (errOpen) { + this.__handleError(errOpen) + reject(errOpen) + return + } + fs.read(fd, Buffer.alloc(10), 0, 10, stats.size - 10, (errRead, bytesRead, buffer) => { + if (errRead) { + this.__handleError(errRead) + reject(errRead) + return + } + fs.close(fd, errClose => { + if (errClose) { + this.__handleError(errClose) + reject(errClose) + return + } + + // resume download + // console.log(buffer) + this.resumeLastChunk = buffer + this.progress.downloaded = stats.size + this.requestOptions.headers.range = `bytes=${stats.size - 10}-${endByte || ''}` + resolve() + }) + }) + }) + return + } + resolve() + }) + }) + } + + __httpFetch(url, options) { + // console.log(options) + this.request = request(url, options) + .on('response', response => { + if (response.statusCode !== 200 && response.statusCode !== 206) { + this.status = STATUS.failed + this.emit('fail', response) + this.__closeRequest() + this.__closeWriteStream() + return + } + this.emit('response', response) + try { + this.__initDownload(response) + } catch (error) { + return this.__handleError(error) + } + this.status = STATUS.running + response + .on('data', this.__handleWriteData.bind(this)) + .on('error', err => this.__handleError(err)) + .on('end', () => this.__handleComplete()) + }) + .on('error', err => this.__handleError(err)) + .on('close', () => this.__closeWriteStream()) + } + + __initDownload(response) { + this.progress.total = parseInt(response.headers['content-length'] || 0) + let options = {} + let isResumable = this.options.forceResume || response.headers['accept-ranges'] !== 'none' + if (isResumable) { + options.flags = 'a' + if (this.progress.downloaded) this.progress.total -= 10 + } else { + if (this.chunkInfo.startByte > 0) return this.__handleError(new Error('The resource cannot be resumed download.')) + } + this.progress.total += this.progress.downloaded + this.statsEstimate.prevBytes = this.progress.downloaded + if (!this.chunkInfo.path) return this.__handleError(new Error('Chunk save Path is not set.')) + this.ws = fs.createWriteStream(this.chunkInfo.path, options) + + this.ws.on('finish', () => this.__closeWriteStream()) + this.ws.on('error', async err => { + await this.__handleError(err) + fs.unlink(this.chunkInfo.path, () => this.__handleError(err)) + }) + } + + __handleComplete() { + if (this.status == STATUS.error) return + this.__closeWriteStream().then(() => { + if (this.progress.downloaded == this.progress.total) { + this.status = STATUS.completed + this.emit('completed') + } else { + this.status = STATUS.stopped + this.emit('stop') + } + }) + console.log('end') + } + + __handleError(error) { + if (this.status == STATUS.error) return + this.status = STATUS.error + this.__closeRequest() + this.__closeWriteStream() + this.emit('error', error) + } + + __closeWriteStream() { + return new Promise((resolve, reject) => { + if (!this.ws) return resolve() + console.log('close write stream') + this.ws.close(err => { + if (err) { + this.status = STATUS.error + this.emit('error', err) + reject(err) + return + } + this.ws = null + resolve() + }) + }) + } + + __closeRequest() { + if (!this.request) return + console.log('close request') + this.request.abort() + this.request = null + } + + __handleWriteData(chunk) { + if (this.resumeLastChunk) { + chunk = this.__handleDiffChunk(chunk) + if (!chunk) { + this.__handleError(new Error('Resume failed, response chunk does not match.')) + this.stop() + return + } + } + // console.log('data', chunk) + if (this.status == STATUS.stopped || this.ws == null) return console.log('cancel write') + this.__calculateProgress(chunk.length) + this.ws.write(chunk, err => { + if (!err) return + console.log(err) + this.__handleError(err) + this.stop() + }) + } + + __handleDiffChunk(chunk) { + // console.log('diff', chunk) + let resumeLastChunkLen = this.resumeLastChunk.length + let chunkLen = chunk.length + let isOk + if (chunkLen >= resumeLastChunkLen) { + isOk = chunk.slice(0, resumeLastChunkLen).toString('hex') === this.resumeLastChunk.toString('hex') + if (!isOk) return null + + this.resumeLastChunk = null + return chunk.slice(resumeLastChunkLen) + } else { + isOk = chunk.slice(0, chunkLen).toString('hex') === this.resumeLastChunk.slice(0, chunkLen).toString('hex') + if (!isOk) return null + this.resumeLastChunk = this.resumeLastChunk.slice(chunkLen) + return chunk.slice(chunkLen) + } + } + + __handleStop() { + return new Promise((resolve, reject) => { + if (this.request) { + this.request.abort() + this.request = null + } + if (this.ws) { + this.ws.close(err => { + if (err) { + reject(err) + this.emit('error', err) + return + } + this.ws = null + resolve() + }) + } else { + resolve() + } + }) + } + + __calculateProgress(receivedBytes) { + const currentTime = performance.now() + const elaspsedTime = currentTime - this.statsEstimate.time + + const progress = this.progress + progress.downloaded += receivedBytes + progress.progress = progress.total ? (progress.downloaded / progress.total) * 100 : -1 + + + // emit the progress every second or if finished + if (progress.downloaded === progress.total || elaspsedTime > 1000) { + this.statsEstimate.time = currentTime + this.statsEstimate.bytes = progress.downloaded - this.statsEstimate.prevBytes + this.statsEstimate.prevBytes = progress.downloaded + this.emit('progress', { + total: progress.total, + downloaded: progress.downloaded, + progress: progress.progress, + speed: this.statsEstimate.bytes, + }) + } + } + + async start() { + this.status = STATUS.running + await this.__init() + this.__httpFetch(this.downloadUrl, this.requestOptions) + this.emit('start') + } + + async stop() { + if (this.status === STATUS.stopped) return + this.status = STATUS.stopped + await this.__handleStop() + this.emit('stop') + } + + refreshUrl(url) { + this.downloadUrl = url + } +} + +export default Task diff --git a/src/renderer/utils/download/index.js b/src/renderer/utils/download/index.js index 40dd7b42..bc5c8114 100644 --- a/src/renderer/utils/download/index.js +++ b/src/renderer/utils/download/index.js @@ -1,6 +1,6 @@ -import { DownloaderHelper } from 'node-downloader-helper' +import Downloader from './Downloader' // import { pauseResumeTimer } from './util' -import { sizeFormate } from '../index' +import { sizeFormate, getProxyInfo } from '../index' import { debugDownload } from '../env' // these are the default options @@ -21,38 +21,34 @@ export default ({ fileName, method = 'get', headers, - override, forceResume, // resumeTime = 5000, - onEnd = () => {}, + onCompleted = () => {}, onError = () => {}, - onStateChanged = () => {}, - onDownload = () => {}, - onPause = () => {}, - onResume = () => {}, + onFail = () => {}, + onStart = () => {}, + onStop = () => {}, onProgress = () => {}, - resumeInfo, } = {}) => { - const dl = new DownloaderHelper(url, path, { - fileName, - method, - headers, - override, + const dl = new Downloader(url, path, fileName, { + requestOptions: { + method, + headers, + proxy: getProxyInfo(), + }, + forceResume, }) - dl.on('end', () => { - onEnd() + dl.on('completed', () => { + onCompleted() debugDownload && console.log('Download Completed') }).on('error', err => { if (err.message === 'socket hang up') return onError(err) debugDownload && console.error('Something happend', err) - }).on('stateChanged', state => { - onStateChanged(state) - debugDownload && console.log('State: ', state) - }).on('download', () => { - onDownload() + }).on('start', () => { + onStart() // pauseResumeTimer(dl, resumeTime) }).on('progress', stats => { const progress = stats.progress.toFixed(2) @@ -68,24 +64,17 @@ export default ({ const total = sizeFormate(stats.total) console.log(`${speed}/s - ${progress}% [${downloaded}/${total}]`) } - }).on('pause', () => { - onPause() + }).on('stop', () => { + onStop() debugDownload && console.log('paused') - }).on('resume', () => { - onResume() - debugDownload && console.log('resume') + }).on('fail', resp => { + onFail(resp) + debugDownload && console.log('fail') }) debugDownload && console.log('Downloading: ', url) - if (resumeInfo) { - dl.__total = resumeInfo.totalFileSize // <--- Workaround - // dl.__filePath = resumeInfo.filePath // <--- Workaround - dl.__isResumable = true // <--- Workaround - dl.resume() - } else { - dl.start() - } + dl.start() return dl } diff --git a/src/renderer/utils/download/util.js b/src/renderer/utils/download/util.js index 140e5077..0553de28 100644 --- a/src/renderer/utils/download/util.js +++ b/src/renderer/utils/download/util.js @@ -1,24 +1,11 @@ -import { DH_STATES } from 'node-downloader-helper' - -export const pauseResumeTimer = (_dl, wait) => { - setTimeout(() => { - if (_dl.state === DH_STATES.FINISHED || _dl.state === DH_STATES.FAILED) { - return - } - - _dl - .pause() - .then(() => console.log(`Paused for ${wait / 1000} seconds`)) - .then(() => - setTimeout(() => { - if (!_dl.isResumable()) { - console.warn( - "This URL doesn't support resume, it will start from the beginning", - ) - } - return _dl.resume() - }, wait), - ) - }, wait) +exports.STATUS = { + idle: 'IDLE', + init: 'INIT', + running: 'RUNNING', + paused: 'PAUSED', + stopped: 'STOPPED', + completed: 'COMPLETED', + error: 'ERROR', + failed: 'FAILED', } diff --git a/src/renderer/utils/index.js b/src/renderer/utils/index.js index 9f76af52..1c90cf50 100644 --- a/src/renderer/utils/index.js +++ b/src/renderer/utils/index.js @@ -374,3 +374,8 @@ export const clearCache = () => rendererInvoke('clearCache') * @param {*} height */ export const setWindowSize = (width, height) => rendererSend('setWindowSize', { width, height }) + + +export const getProxyInfo = () => window.globalObj.proxy.enable + ? `http://${window.globalObj.proxy.username}:${window.globalObj.proxy.password}@${window.globalObj.proxy.host}:${window.globalObj.proxy.port};` + : undefined diff --git a/src/renderer/utils/request.js b/src/renderer/utils/request.js index bb46bc7c..4fecad68 100644 --- a/src/renderer/utils/request.js +++ b/src/renderer/utils/request.js @@ -4,6 +4,7 @@ import { debugRequest } from './env' import { requestMsg } from './message' import { bHh } from './music/options' import { deflateRawSync } from 'zlib' +import { getProxyInfo } from './index' // import fs from 'fs' const defaultHeaders = { @@ -219,10 +220,6 @@ export const http_jsonp = (url, options, callback) => { }) } -const getProxyInfo = () => window.globalObj.proxy.enable - ? `http://${window.globalObj.proxy.username}:${window.globalObj.proxy.password}@${window.globalObj.proxy.host}:${window.globalObj.proxy.port};` - : undefined - const regx = /(?:\d\w)+/g const fetchData = (url, method, { diff --git a/src/renderer/views/Download.vue b/src/renderer/views/Download.vue index 1a52913f..23aad5ee 100644 --- a/src/renderer/views/Download.vue +++ b/src/renderer/views/Download.vue @@ -80,9 +80,11 @@ export default { return this.listId == 'download' }, playListIndex() { - if (this.listId != 'download') return - let path = this.list[this.playIndex].filePath - return this.showList.findIndex(i => i.filePath == path) + if (this.listId != 'download' || !this.list.length) return + let info = this.list[this.playIndex] + if (!info) return -1 + let key = info.key + return this.showList.findIndex(i => i.key == key) }, showList() { switch (this.tabId) { @@ -120,16 +122,16 @@ export default { ...mapMutations('player', ['setList']), ...mapMutations('download', ['pauseTask']), handlePauseTask(index) { - let info = this.showList[index] + let info = this.list[index] let dl = this.dls[info.key] - dl ? dl.pause() : this.pauseTask(info) + dl ? dl.stop() : this.pauseTask(info) console.log('pause') }, handleStartTask(index) { console.log('start') - let info = this.showList[index] + let info = this.list[index] let dl = this.dls[info.key] - dl ? dl.resume() : this.startTask(info) + dl ? dl.start() : this.startTask(info) }, handleDoubleClick(index) { if ( @@ -145,7 +147,9 @@ export default { this.clickIndex = -1 }, handleClick(index) { - let info = this.showList[index] + const key = this.showList[index].key + index = this.list.findIndex(i => i.key === key) + let info = this.list[index] if (info.isComplate) { this.handlePlay(index) } else if (info.status === this.downloadStatus.RUN) { @@ -155,26 +159,28 @@ export default { } }, handlePlay(index) { - if (!checkPath(this.showList[index].filePath)) return - let path = this.showList[index].filePath + if (!checkPath(this.list[index].filePath)) return + let path = this.list[index].filePath this.setList({ list: this.list, listId: 'download', index: this.list.findIndex(i => i.filePath === path) }) }, handleListBtnClick(info) { + const key = this.showList[info.index].key + let index = this.list.findIndex(i => i.key === key) switch (info.action) { case 'play': - this.handlePlay(info.index) + this.handlePlay(index) break case 'start': - this.handleStartTask(info.index) + this.handleStartTask(index) break case 'pause': - this.handlePauseTask(info.index) + this.handlePauseTask(index) break case 'remove': - this.removeTask(info.index) + this.removeTask(index) break case 'file': - this.handleOpenFolder(info.index) + this.handleOpenFolder(index) break } }, @@ -190,7 +196,7 @@ export default { case 'start': this.selectdData.forEach(item => { if (item.isComplate || item.status == this.downloadStatus.RUN) return - let index = this.showList.indexOf(item) + let index = this.list.indexOf(item) if (index < 0) return this.handleStartTask(index) }) @@ -200,13 +206,13 @@ export default { 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.showList.indexOf(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.showList.indexOf(item) + let index = this.list.indexOf(item) if (index < 0) return this.handlePauseTask(index) }) @@ -219,7 +225,7 @@ export default { this.resetSelect() }, handleOpenFolder(index) { - let path = this.showList[index].filePath + let path = this.list[index].filePath if (!checkPath(path)) return openDirInExplorer(path) }, diff --git a/src/renderer/views/Setting.vue b/src/renderer/views/Setting.vue index eaef6610..809e457b 100644 --- a/src/renderer/views/Setting.vue +++ b/src/renderer/views/Setting.vue @@ -78,7 +78,7 @@ div.scroll(:class="$style.setting") material-checkbox(id="setting_download_isDownloadLrc" v-model="current_setting.download.isDownloadLrc" label="是否启用") dt 网络设置 dd - h3 代理设置(歌曲下载暂不支持代理) + h3 代理设置 div p material-checkbox(id="setting_network_proxy_enable" v-model="current_setting.network.proxy.enable" @change="handleProxyChange('enable')" label="是否启用") @@ -108,7 +108,7 @@ div.scroll(:class="$style.setting") material-btn(:class="[$style.btn, $style.gapLeft]" min @click="handleExportAllData") 导出 dt 其他 dd - h3 缓存大小(清理缓存后图片等资源将需要重新下载) + h3 缓存大小(清理缓存后图片等资源将需要重新下载,不建议清除,软件会自动将大小维持在200M左右) div p | 软件已使用缓存大小: