perf: 优化下载工具

This commit is contained in:
kuaifan 2025-08-15 06:25:07 +08:00
parent eecc6c9e53
commit b05046af29
8 changed files with 55 additions and 42 deletions

2
electron/build.js vendored
View File

@ -8,7 +8,7 @@ const yauzl = require('yauzl');
const axios = require('axios'); const axios = require('axios');
const FormData =require('form-data'); const FormData =require('form-data');
const tar = require('tar'); const tar = require('tar');
const utils = require('./utils'); const utils = require('./lib/utils');
const config = require('../package.json') const config = require('../package.json')
const env = require('dotenv').config({ path: './.env' }) const env = require('dotenv').config({ path: './.env' })
const argv = process.argv; const argv = process.argv;

View File

@ -1,15 +1,15 @@
const {BrowserWindow, screen, shell, ipcMain} = require('electron') const {BrowserWindow, screen, shell, ipcMain} = require('electron')
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const Store = require("electron-store");
const loger = require("electron-log"); const loger = require("electron-log");
const {default: electronDl, download} = require("@dootask/electron-dl"); const {default: electronDl, download} = require("@dootask/electron-dl");
const utils = require("./utils"); const utils = require("./lib/utils");
const {DownloadManager} = require("./utils/download"); const {DownloadManager, DownloadStore} = require("./lib/download-manager");
const store = new Store();
const downloadManager = new DownloadManager(); const downloadManager = new DownloadManager();
let downloadWindow = null;
let downloadWindow = null,
downloadLanguageCode = 'zh';
function initialize(onStarted= null) { function initialize(onStarted= null) {
// 下载配置 // 下载配置
@ -32,7 +32,9 @@ function initialize(onStarted= null) {
downloadManager.refresh(item.getSavePath()); downloadManager.refresh(item.getSavePath());
syncDownloadItems(); syncDownloadItems();
// 尝试更新下载项的错误信息 // 尝试更新下载项的错误信息
downloadManager.updateError(item).then(success => { downloadManager.updateError(item, {
language: downloadLanguageCode,
}).then(success => {
if (success) { if (success) {
syncDownloadItems(); syncDownloadItems();
} }
@ -112,11 +114,7 @@ function syncDownloadItems() {
} }
} }
function getLanguagePack(codeOrPack) { function getLanguageData(code) {
if (codeOrPack && typeof codeOrPack === 'object') {
return codeOrPack;
}
const code = (codeOrPack || 'zh').toString();
const packs = { const packs = {
zh: { zh: {
// 语言设置 // 语言设置
@ -516,12 +514,13 @@ function getLanguagePack(codeOrPack) {
showFailed: 'Ошибка отображения файла: ', showFailed: 'Ошибка отображения файла: ',
} }
}; };
downloadLanguageCode = code;
return packs[code] || packs.zh; return packs[code] || packs.zh;
} }
async function open(language = 'zh', theme = 'light') { async function open(language = 'zh', theme = 'light') {
// 获取语言包 // 获取语言包
const finalLanguage = getLanguagePack(language); const finalLanguage = getLanguageData(language);
// 如果窗口已存在,直接显示 // 如果窗口已存在,直接显示
if (downloadWindow) { if (downloadWindow) {
@ -553,7 +552,7 @@ async function open(language = 'zh', theme = 'light') {
} }
// 恢复窗口位置 // 恢复窗口位置
const downloadWindowBounds = store.get('downloadWindowBounds', {}); const downloadWindowBounds = DownloadStore.get('downloadWindowBounds', {});
if ( if (
downloadWindowBounds.width !== undefined && downloadWindowBounds.width !== undefined &&
downloadWindowBounds.height !== undefined && downloadWindowBounds.height !== undefined &&
@ -585,9 +584,9 @@ async function open(language = 'zh', theme = 'light') {
downloadWindowBounds.width = Math.min(downloadWindowBounds.width, primaryArea.width - 100); downloadWindowBounds.width = Math.min(downloadWindowBounds.width, primaryArea.width - 100);
downloadWindowBounds.height = Math.min(downloadWindowBounds.height, primaryArea.height - 100); downloadWindowBounds.height = Math.min(downloadWindowBounds.height, primaryArea.height - 100);
} }
downloadWindowOptions.center = false;
downloadWindowOptions.width = downloadWindowBounds.width; downloadWindowOptions.width = downloadWindowBounds.width;
downloadWindowOptions.height = downloadWindowBounds.height; downloadWindowOptions.height = downloadWindowBounds.height;
downloadWindowOptions.center = false;
downloadWindowOptions.x = downloadWindowBounds.x; downloadWindowOptions.x = downloadWindowBounds.x;
downloadWindowOptions.y = downloadWindowBounds.y; downloadWindowOptions.y = downloadWindowBounds.y;
} }
@ -603,7 +602,7 @@ async function open(language = 'zh', theme = 'light') {
// 监听窗口关闭保存窗口位置 // 监听窗口关闭保存窗口位置
downloadWindow.on('close', () => { downloadWindow.on('close', () => {
const bounds = downloadWindow.getBounds(); const bounds = downloadWindow.getBounds();
store.set('downloadWindowBounds', bounds); DownloadStore.set('downloadWindowBounds', bounds);
}); });
// 监听窗口关闭事件 // 监听窗口关闭事件
@ -642,7 +641,7 @@ function destroy() {
async function updateWindow(language, theme) { async function updateWindow(language, theme) {
if (downloadWindow) { if (downloadWindow) {
try { try {
const finalLanguage = getLanguagePack(language); const finalLanguage = getLanguageData(language);
downloadWindow.setTitle(finalLanguage.title); downloadWindow.setTitle(finalLanguage.title);
downloadWindow.webContents.send('download-theme', theme); downloadWindow.webContents.send('download-theme', theme);
downloadWindow.webContents.send('download-language', finalLanguage); downloadWindow.webContents.send('download-language', finalLanguage);

View File

@ -9,7 +9,7 @@ const {
const fs = require('fs') const fs = require('fs')
const url = require('url') const url = require('url')
const request = require("request"); const request = require("request");
const utils = require('./utils') const utils = require('./lib/utils')
const MAILTO_PREFIX = "mailto:"; const MAILTO_PREFIX = "mailto:";

10
electron/electron.js vendored
View File

@ -38,7 +38,7 @@ const Screenshots = require("electron-screenshots-tool").Screenshots;
const PDFDocument = require('pdf-lib').PDFDocument; const PDFDocument = require('pdf-lib').PDFDocument;
// 本地模块和配置 // 本地模块和配置
const utils = require('./utils'); const utils = require('./lib/utils');
const config = require('./package.json'); const config = require('./package.json');
const electronDown = require("./electron-down"); const electronDown = require("./electron-down");
const electronMenu = require("./electron-menu"); const electronMenu = require("./electron-menu");
@ -305,7 +305,7 @@ function createMainWindow() {
webSecurity: true, webSecurity: true,
nodeIntegration: true, nodeIntegration: true,
contextIsolation: true, contextIsolation: true,
nativeWindowOpen: true backgroundThrottling: false,
} }
}) })
@ -456,7 +456,6 @@ function preCreateChildWindow() {
webSecurity: true, webSecurity: true,
nodeIntegration: true, nodeIntegration: true,
contextIsolation: true, contextIsolation: true,
nativeWindowOpen: true
} }
}); });
@ -514,7 +513,6 @@ function createChildWindow(args) {
webSecurity: true, webSecurity: true,
nodeIntegration: true, nodeIntegration: true,
contextIsolation: true, contextIsolation: true,
nativeWindowOpen: true
}, webPreferences), }, webPreferences),
}, config) }, config)
if (options.parent) { if (options.parent) {
@ -763,9 +761,8 @@ function createWebTabWindow(args) {
webSecurity: true, webSecurity: true,
nodeIntegration: true, nodeIntegration: true,
contextIsolation: true, contextIsolation: true,
nativeWindowOpen: true
}, },
}, userConf.get('webTabWindow', {}))) }, userConf.get('webTabWindow') || {}))
const originalClose = webTabWindow.close; const originalClose = webTabWindow.close;
webTabWindow.close = function() { webTabWindow.close = function() {
@ -1869,7 +1866,6 @@ function exportVsdx(event, args, directFinalize) {
webSecurity: true, webSecurity: true,
nodeIntegration: true, nodeIntegration: true,
contextIsolation: true, contextIsolation: true,
nativeWindowOpen: true
}, },
}) })

View File

@ -1,7 +1,7 @@
const path = require("path"); const path = require("path");
const loger = require("electron-log"); const loger = require("electron-log");
const Store = require('electron-store'); const Store = require('electron-store');
const utils = require("./index"); const utils = require("./utils");
const store = new Store({ const store = new Store({
name: 'download-manager', name: 'download-manager',
defaults: { defaults: {
@ -9,9 +9,20 @@ const store = new Store({
} }
}); });
const DownloadStore = {
get(key, defaultValue) {
return store.get(key, defaultValue);
},
set(key, value) {
store.set(key, value);
},
};
class DownloadManager { class DownloadManager {
static key = 'downloadHistory';
constructor() { constructor() {
const history = store.get('downloadHistory', []); const history = DownloadStore.get(DownloadManager.key, []);
if (utils.isArray(history)) { if (utils.isArray(history)) {
this.downloadHistory = history.map(item => ({ this.downloadHistory = history.map(item => ({
...item, ...item,
@ -66,7 +77,7 @@ class DownloadManager {
if (this.downloadHistory.length > 1000) { if (this.downloadHistory.length > 1000) {
this.downloadHistory = this.downloadHistory.slice(0, 1000); this.downloadHistory = this.downloadHistory.slice(0, 1000);
} }
store.set('downloadHistory', this.downloadHistory); DownloadStore.set(DownloadManager.key, this.downloadHistory);
} }
/** /**
@ -99,14 +110,15 @@ class DownloadManager {
return; return;
} }
Object.assign(item, this.convert(downloadItem)) Object.assign(item, this.convert(downloadItem))
store.set('downloadHistory', this.downloadHistory); DownloadStore.set(DownloadManager.key, this.downloadHistory);
} }
/** /**
* 尝试更新下载项的错误信息 * 尝试更新下载项的错误信息
* @param {Electron.DownloadItem} downloadItem * @param {Electron.DownloadItem} downloadItem
* @param {Object} headers
*/ */
async updateError(downloadItem) { async updateError(downloadItem, headers = {}) {
const urls = downloadItem.getURLChain() const urls = downloadItem.getURLChain()
const url = urls.length > 0 ? urls[0] : downloadItem.getURL() const url = urls.length > 0 ? urls[0] : downloadItem.getURL()
const path = downloadItem.getSavePath() const path = downloadItem.getSavePath()
@ -119,6 +131,7 @@ class DownloadManager {
try { try {
const res = await fetch(url, { const res = await fetch(url, {
method: 'HEAD', method: 'HEAD',
headers,
}) })
let error = null let error = null
if (res.headers.get('X-Error-Message-Base64')) { if (res.headers.get('X-Error-Message-Base64')) {
@ -128,7 +141,7 @@ class DownloadManager {
} }
if (error) { if (error) {
Object.assign(item, {error}); Object.assign(item, {error});
store.set('downloadHistory', this.downloadHistory); DownloadStore.set(DownloadManager.key, this.downloadHistory);
return true; return true;
} }
} catch { } catch {
@ -209,7 +222,7 @@ class DownloadManager {
if (index > -1) { if (index > -1) {
this.cancel(path); this.cancel(path);
this.downloadHistory.splice(index, 1); this.downloadHistory.splice(index, 1);
store.set('downloadHistory', this.downloadHistory); DownloadStore.set(DownloadManager.key, this.downloadHistory);
} }
} }
@ -219,8 +232,8 @@ class DownloadManager {
removeAll() { removeAll() {
this.cancelAll(); this.cancelAll();
this.downloadHistory = []; this.downloadHistory = [];
store.set('downloadHistory', []); DownloadStore.set(DownloadManager.key, []);
} }
} }
module.exports = {DownloadManager}; module.exports = {DownloadStore, DownloadManager};

View File

@ -77,9 +77,9 @@
"output": "dist" "output": "dist"
}, },
"files": [ "files": [
"lib/**/*",
"render/**/*", "render/**/*",
"public/**/*", "public/**/*",
"utils/**/*",
"electron-down.js", "electron-down.js",
"electron-menu.js", "electron-menu.js",
"electron-preload.js", "electron-preload.js",

View File

@ -226,6 +226,18 @@
}, },
methods: { methods: {
async sendAsync(action, args = {}) {
try {
return await electron?.sendAsync("downloadManager", {
action,
...args
});
} catch (e) {
e.message = `${e.message}`.replace(/Error invoking remote method 'downloadManager': Error:\s+/, '');
throw e;
}
},
async copyUrl({url, urls}) { async copyUrl({url, urls}) {
try { try {
await navigator.clipboard.writeText(urls.length > 0 ? urls[0] : url); await navigator.clipboard.writeText(urls.length > 0 ? urls[0] : url);
@ -446,13 +458,6 @@
}); });
}, },
sendAsync(action, args = {}) {
return electron?.sendAsync("downloadManager", {
action,
...args
});
},
showToast(message, type = 'success') { showToast(message, type = 'success') {
if (this.toast.timer) { if (this.toast.timer) {
clearTimeout(this.toast.timer); clearTimeout(this.toast.timer);