Files
dootask/electron/electron-down.js
T

688 lines
24 KiB
JavaScript
Vendored

const {BrowserWindow, screen, shell, ipcMain} = require('electron')
const fs = require('fs');
const path = require('path');
const loger = require("electron-log");
const {default: electronDl, download, CancelError} = require("@dootask/electron-dl");
const utils = require("./lib/utils");
const {DownloadManager, DownloadStore} = require("./lib/download-manager");
const downloadManager = new DownloadManager();
let downloadWindow = null,
downloadLanguageCode = 'zh',
downloadWaiting = false;
function initialize(onStarted = null) {
// 下载配置
electronDl({
showBadge: false,
showProgressBar: false,
onStarted: (item) => {
downloadManager.add(item);
downloadWaiting = false;
syncDownloadItems();
if (typeof onStarted === 'function') {
onStarted(item)
}
},
onCancel: (item) => {
downloadManager.refresh(item.getSavePath())
syncDownloadItems();
},
onInterrupted: (item) => {
downloadManager.refresh(item.getSavePath());
syncDownloadItems();
// 尝试更新下载项的错误信息
downloadManager.updateError(item, {
language: downloadLanguageCode,
}).then(success => {
if (success) {
syncDownloadItems();
}
});
},
onProgress: (item) => {
downloadManager.refresh(item.path);
syncDownloadItems();
},
onCompleted: (item) => {
downloadManager.refresh(item.path);
syncDownloadItems();
}
});
// IPC
ipcMain.handle('downloadManager', async (event, {action, path}) => {
switch (action) {
case "get": {
return {
items: downloadManager.get(),
waiting: downloadWaiting,
};
}
case "pause": {
downloadManager.pause(path);
syncDownloadItems();
return true;
}
case "resume": {
downloadManager.resume(path);
syncDownloadItems();
return true;
}
case "cancel": {
downloadManager.cancel(path);
syncDownloadItems();
return true;
}
case "remove": {
downloadManager.remove(path);
syncDownloadItems();
return true;
}
case "removeAll": {
downloadManager.removeAll();
syncDownloadItems();
return true;
}
case "openFile": {
if (!fs.existsSync(path)) {
throw new Error('file not found');
}
return shell.openPath(path);
}
case "showFolder": {
if (!fs.existsSync(path)) {
throw new Error('file not found');
}
shell.showItemInFolder(path);
return true;
}
}
});
}
async function createDownload(window_, url, options = {}) {
downloadWaiting = true;
syncDownloadItems();
try {
return await download(window_, url, options);
} catch (error) {
// electron-dl rejects with CancelError when a download is cancelled; treat it as expected.
const isCancelError = (typeof CancelError === 'function' && error instanceof CancelError)
|| error?.name === 'CancelError';
if (!isCancelError) {
throw error;
}
return null;
} finally {
downloadWaiting = false;
syncDownloadItems();
}
}
function syncDownloadItems() {
// 同步下载项到渲染进程
if (downloadWindow) {
downloadWindow.webContents.send('download-items', {
items: downloadManager.get(),
waiting: downloadWaiting,
});
}
}
function getLanguageData(code) {
const packs = {
zh: {
// 语言设置
locale: 'zh-CN',
title: '下载管理器',
// 界面文本
searchPlaceholder: '搜索文件名或链接...',
noItems: '暂无任务',
noSearchResult: '未找到匹配的结果',
// 操作按钮
refresh: '刷新',
removeAll: "清空历史",
copyLink: '复制链接',
resume: '继续',
pause: '暂停',
cancel: '取消',
remove: '删除',
showInFolder: '显示在文件夹',
// 状态文本
progressing: '下载中',
completed: '已完成',
cancelled: '已取消',
interrupted: '失败',
paused: '已暂停',
// 成功消息
copied: "已复制",
refreshSuccess: '刷新成功',
// 确认对话框
confirmCancel: '确定要取消此下载任务并删除记录吗?',
confirmRemove: '确定要从历史记录中删除此项吗?',
confirmRemoveAll: '确定要清空下载历史吗?',
// 错误消息
copyFailed: '复制失败: ',
pauseFailed: '暂停失败: ',
resumeFailed: '继续失败: ',
removeFailed: '删除失败: ',
removeAllFailed: '清空失败: ',
openFailed: '打开文件失败: ',
showFailed: '显示文件失败: ',
},
'zh-CHT': {
locale: 'zh-TW',
title: '下載管理器',
// 界面文本
searchPlaceholder: '搜尋檔案名稱或連結...',
noItems: '暫無任務',
noSearchResult: '未找到匹配的結果',
// 操作按钮
refresh: '重新整理',
removeAll: "清空歷史",
copyLink: '複製連結',
resume: '繼續',
pause: '暫停',
cancel: '取消',
remove: '刪除',
showInFolder: '顯示在資料夾',
// 状态文本
progressing: '下載中',
completed: '已完成',
cancelled: '已取消',
interrupted: '失敗',
paused: '已暫停',
// 成功消息
copied: "已複製",
refreshSuccess: '重新整理成功',
// 确认对话框
confirmCancel: '確定要取消此下載任務並刪除記錄嗎?',
confirmRemove: '確定要從歷史記錄中刪除此項嗎?',
confirmRemoveAll: '確定要清空下載歷史嗎?',
// 错误消息
copyFailed: '複製失敗: ',
pauseFailed: '暫停失敗: ',
resumeFailed: '繼續失敗: ',
removeFailed: '刪除失敗: ',
removeAllFailed: '清空失敗: ',
openFailed: '開啟檔案失敗: ',
showFailed: '顯示檔案失敗: ',
},
en: {
locale: 'en-US',
title: 'Download Manager',
// 界面文本
searchPlaceholder: 'Search filename or link...',
noItems: 'No tasks',
noSearchResult: 'No matching results found',
// 操作按钮
refresh: 'Refresh',
removeAll: "Clear History",
copyLink: 'Copy Link',
resume: 'Resume',
pause: 'Pause',
cancel: 'Cancel',
remove: 'Remove',
showInFolder: 'Show in Folder',
// 状态文本
progressing: 'Downloading',
completed: 'Completed',
cancelled: 'Cancelled',
interrupted: 'Failed',
paused: 'Paused',
// 成功消息
copied: "Copied",
refreshSuccess: 'Refresh successful',
// 确认对话框
confirmCancel: 'Are you sure you want to cancel this download task and delete the record?',
confirmRemove: 'Are you sure you want to remove this item from history?',
confirmRemoveAll: 'Are you sure you want to clear download history?',
// 错误消息
copyFailed: 'Copy failed: ',
pauseFailed: 'Pause failed: ',
resumeFailed: 'Resume failed: ',
removeFailed: 'Remove failed: ',
removeAllFailed: 'Clear failed: ',
openFailed: 'Open file failed: ',
showFailed: 'Show file failed: ',
},
ko: {
locale: 'ko-KR',
title: '다운로드 관리자',
// 界面文本
searchPlaceholder: '파일명 또는 링크 검색...',
noItems: '작업 없음',
noSearchResult: '일치하는 결과를 찾을 수 없습니다',
// 操作按钮
refresh: '새로고침',
removeAll: "기록 지우기",
copyLink: '링크 복사',
resume: '계속',
pause: '일시정지',
cancel: '취소',
remove: '삭제',
showInFolder: '폴더에서 보기',
// 状态文本
progressing: '다운로드 중',
completed: '완료됨',
cancelled: '취소됨',
interrupted: '실패',
paused: '일시정지됨',
// 成功消息
copied: "복사됨",
refreshSuccess: '새로고침 성공',
// 确认对话框
confirmCancel: '이 다운로드 작업을 취소하고 기록을 삭제하시겠습니까?',
confirmRemove: '기록에서 이 항목을 삭제하시겠습니까?',
confirmRemoveAll: '다운로드 기록을 지우시겠습니까?',
// 错误消息
copyFailed: '복사 실패: ',
pauseFailed: '일시정지 실패: ',
resumeFailed: '계속 실패: ',
removeFailed: '삭제 실패: ',
removeAllFailed: '지우기 실패: ',
openFailed: '파일 열기 실패: ',
showFailed: '파일 표시 실패: ',
},
ja: {
locale: 'ja-JP',
title: 'ダウンロードマネージャー',
// 界面文本
searchPlaceholder: 'ファイル名またはリンクを検索...',
noItems: 'タスクがありません',
noSearchResult: '一致する結果が見つかりません',
// 操作按钮
refresh: '更新',
removeAll: "履歴をクリア",
copyLink: 'リンクをコピー',
resume: '再開',
pause: '一時停止',
cancel: 'キャンセル',
remove: '削除',
showInFolder: 'フォルダで表示',
// 状态文本
progressing: 'ダウンロード中',
completed: '完了',
cancelled: 'キャンセル済み',
interrupted: '失敗',
paused: '一時停止中',
// 成功消息
copied: "コピーしました",
refreshSuccess: '更新が完了しました',
// 确认对话框
confirmCancel: 'このダウンロードタスクをキャンセルして記録を削除しますか?',
confirmRemove: '履歴からこの項目を削除しますか?',
confirmRemoveAll: 'ダウンロード履歴をクリアしますか?',
// 错误消息
copyFailed: 'コピーに失敗しました: ',
pauseFailed: '一時停止に失敗しました: ',
resumeFailed: '再開に失敗しました: ',
removeFailed: '削除に失敗しました: ',
removeAllFailed: 'クリアに失敗しました: ',
openFailed: 'ファイルを開けませんでした: ',
showFailed: 'ファイルの表示に失敗しました: ',
},
de: {
locale: 'de-DE',
title: 'Download-Manager',
// 界面文本
searchPlaceholder: 'Dateiname oder Link suchen...',
noItems: 'Keine Aufgaben',
noSearchResult: 'Keine übereinstimmenden Ergebnisse gefunden',
// 操作按钮
refresh: 'Aktualisieren',
removeAll: "Verlauf löschen",
copyLink: 'Link kopieren',
resume: 'Fortsetzen',
pause: 'Pause',
cancel: 'Abbrechen',
remove: 'Entfernen',
showInFolder: 'Im Ordner anzeigen',
// 状态文本
progressing: 'Wird heruntergeladen',
completed: 'Abgeschlossen',
cancelled: 'Abgebrochen',
interrupted: 'Fehlgeschlagen',
paused: 'Pausiert',
// 成功消息
copied: "Kopiert",
refreshSuccess: 'Erfolgreich aktualisiert',
// 确认对话框
confirmCancel: 'Sind Sie sicher, dass Sie diese Download-Aufgabe abbrechen und den Eintrag löschen möchten?',
confirmRemove: 'Sind Sie sicher, dass Sie diesen Eintrag aus dem Verlauf entfernen möchten?',
confirmRemoveAll: 'Sind Sie sicher, dass Sie den Download-Verlauf löschen möchten?',
// 错误消息
copyFailed: 'Kopieren fehlgeschlagen: ',
pauseFailed: 'Pause fehlgeschlagen: ',
resumeFailed: 'Fortsetzen fehlgeschlagen: ',
removeFailed: 'Entfernen fehlgeschlagen: ',
removeAllFailed: 'Löschen fehlgeschlagen: ',
openFailed: 'Datei öffnen fehlgeschlagen: ',
showFailed: 'Datei anzeigen fehlgeschlagen: ',
},
fr: {
locale: 'fr-FR',
title: 'Gestionnaire de téléchargements',
// 界面文本
searchPlaceholder: 'Rechercher nom de fichier ou lien...',
noItems: 'Aucune tâche',
noSearchResult: 'Aucun résultat correspondant trouvé',
// 操作按钮
refresh: 'Actualiser',
removeAll: "Effacer l'historique",
copyLink: 'Copier le lien',
resume: 'Reprendre',
pause: 'Pause',
cancel: 'Annuler',
remove: 'Supprimer',
showInFolder: 'Afficher dans le dossier',
// 状态文本
progressing: 'Téléchargement en cours',
completed: 'Terminé',
cancelled: 'Annulé',
interrupted: 'Échoué',
paused: 'En pause',
// 成功消息
copied: "Copié",
refreshSuccess: 'Actualisation réussie',
// 确认对话框
confirmCancel: 'Êtes-vous sûr de vouloir annuler cette tâche de téléchargement et supprimer l\'enregistrement ?',
confirmRemove: 'Êtes-vous sûr de vouloir supprimer cet élément de l\'historique ?',
confirmRemoveAll: 'Êtes-vous sûr de vouloir effacer l\'historique des téléchargements ?',
// 错误消息
copyFailed: 'Échec de la copie : ',
pauseFailed: 'Échec de la pause : ',
resumeFailed: 'Échec de la reprise : ',
removeFailed: 'Échec de la suppression : ',
removeAllFailed: 'Échec de l\'effacement : ',
openFailed: 'Échec de l\'ouverture du fichier : ',
showFailed: 'Échec de l\'affichage du fichier : ',
},
id: {
locale: 'id-ID',
title: 'Manajer Unduhan',
// 界面文本
searchPlaceholder: 'Cari nama file atau tautan...',
noItems: 'Tidak ada tugas',
noSearchResult: 'Tidak ada hasil yang cocok ditemukan',
// 操作按钮
refresh: 'Segarkan',
removeAll: "Hapus Riwayat",
copyLink: 'Salin Tautan',
resume: 'Lanjutkan',
pause: 'Jeda',
cancel: 'Batal',
remove: 'Hapus',
showInFolder: 'Tampilkan di Folder',
// 状态文本
progressing: 'Mengunduh',
completed: 'Selesai',
cancelled: 'Dibatalkan',
interrupted: 'Gagal',
paused: 'Dijeda',
// 成功消息
copied: "Disalin",
refreshSuccess: 'Berhasil disegarkan',
// 确认对话框
confirmCancel: 'Apakah Anda yakin ingin membatalkan tugas unduhan ini dan menghapus catatan?',
confirmRemove: 'Apakah Anda yakin ingin menghapus item ini dari riwayat?',
confirmRemoveAll: 'Apakah Anda yakin ingin menghapus riwayat unduhan?',
// 错误消息
copyFailed: 'Gagal menyalin: ',
pauseFailed: 'Gagal menjeda: ',
resumeFailed: 'Gagal melanjutkan: ',
removeFailed: 'Gagal menghapus: ',
removeAllFailed: 'Gagal menghapus: ',
openFailed: 'Gagal membuka file: ',
showFailed: 'Gagal menampilkan file: ',
},
ru: {
locale: 'ru-RU',
title: 'Менеджер загрузок',
// 界面文本
searchPlaceholder: 'Поиск имени файла или ссылки...',
noItems: 'Нет задач',
noSearchResult: 'Совпадающих результатов не найдено',
// 操作按钮
refresh: 'Обновить',
removeAll: "Очистить историю",
copyLink: 'Копировать ссылку',
resume: 'Возобновить',
pause: 'Пауза',
cancel: 'Отмена',
remove: 'Удалить',
showInFolder: 'Показать в папке',
// 状态文本
progressing: 'Загружается',
completed: 'Завершено',
cancelled: 'Отменено',
interrupted: 'Ошибка',
paused: 'На паузе',
// 成功消息
copied: "Скопировано",
refreshSuccess: 'Успешно обновлено',
// 确认对话框
confirmCancel: 'Вы уверены, что хотите отменить эту задачу загрузки и удалить запись?',
confirmRemove: 'Вы уверены, что хотите удалить этот элемент из истории?',
confirmRemoveAll: 'Вы уверены, что хотите очистить историю загрузок?',
// 错误消息
copyFailed: 'Ошибка копирования: ',
pauseFailed: 'Ошибка паузы: ',
resumeFailed: 'Ошибка возобновления: ',
removeFailed: 'Ошибка удаления: ',
removeAllFailed: 'Ошибка очистки: ',
openFailed: 'Ошибка открытия файла: ',
showFailed: 'Ошибка отображения файла: ',
}
};
downloadLanguageCode = code;
return packs[code] || packs.zh;
}
async function open(language = 'zh', theme = 'light') {
// 获取语言包
const finalLanguage = getLanguageData(language);
// 如果窗口已存在,直接显示
if (downloadWindow) {
// 更新窗口数据
await updateWindow(language, theme)
// 显示窗口并聚焦
downloadWindow.show();
downloadWindow.focus();
return;
}
// 窗口默认参数
const downloadWindowOptions = {
width: 700,
height: 480,
minWidth: 500,
minHeight: 350,
center: true,
show: false,
autoHideMenuBar: true,
title: finalLanguage.title,
backgroundColor: utils.getDefaultBackgroundColor(),
webPreferences: {
preload: path.join(__dirname, 'electron-preload.js'),
webSecurity: true,
nodeIntegration: true,
contextIsolation: true,
}
}
// 恢复窗口位置
const downloadWindowBounds = DownloadStore.get('downloadWindowBounds', {});
if (
downloadWindowBounds.width !== undefined &&
downloadWindowBounds.height !== undefined &&
downloadWindowBounds.x !== undefined &&
downloadWindowBounds.y !== undefined
) {
// 获取所有显示器的可用区域
const displays = screen.getAllDisplays();
// 检查窗口是否在任意一个屏幕内
let isInScreen = false;
for (const display of displays) {
const area = display.workArea;
if (
downloadWindowBounds.x + downloadWindowBounds.width > area.x &&
downloadWindowBounds.x < area.x + area.width &&
downloadWindowBounds.y + downloadWindowBounds.height > area.y &&
downloadWindowBounds.y < area.y + area.height
) {
isInScreen = true;
break;
}
}
// 如果超出所有屏幕,则移动到主屏幕可见区域
if (!isInScreen) {
const primaryArea = screen.getPrimaryDisplay().workArea;
downloadWindowBounds.x = primaryArea.x + 50;
downloadWindowBounds.y = primaryArea.y + 50;
// 防止窗口太大超出屏幕
downloadWindowBounds.width = Math.min(downloadWindowBounds.width, primaryArea.width - 100);
downloadWindowBounds.height = Math.min(downloadWindowBounds.height, primaryArea.height - 100);
}
downloadWindowOptions.center = false;
downloadWindowOptions.width = downloadWindowBounds.width;
downloadWindowOptions.height = downloadWindowBounds.height;
downloadWindowOptions.x = downloadWindowBounds.x;
downloadWindowOptions.y = downloadWindowBounds.y;
}
// 创建窗口
downloadWindow = new BrowserWindow(downloadWindowOptions);
// 禁止修改窗口标题
downloadWindow.on('page-title-updated', (event) => {
event.preventDefault()
})
// 监听窗口关闭保存窗口位置
downloadWindow.on('close', () => {
const bounds = downloadWindow.getBounds();
DownloadStore.set('downloadWindowBounds', bounds);
});
// 监听窗口关闭事件
downloadWindow.on('closed', () => {
downloadWindow = null;
});
// 加载下载管理器页面
const htmlPath = path.join(__dirname, 'render', 'download', 'index.html');
const themeParam = (theme === 'dark' ? 'dark' : 'light');
await downloadWindow.loadFile(htmlPath, {query: {theme: themeParam}});
// 将语言包发送到渲染进程
downloadWindow.webContents.once('dom-ready', () => {
updateWindow(language, theme)
});
// 显示窗口
downloadWindow.show();
}
function close() {
if (downloadWindow) {
downloadWindow.close();
downloadWindow = null;
}
}
function destroy() {
if (downloadWindow) {
downloadWindow.destroy();
downloadWindow = null;
}
}
async function updateWindow(language, theme) {
if (downloadWindow) {
try {
const finalLanguage = getLanguageData(language);
downloadWindow.setTitle(finalLanguage.title);
downloadWindow.webContents.send('download-theme', theme);
downloadWindow.webContents.send('download-language', finalLanguage);
syncDownloadItems()
} catch (error) {
loger.error(error);
}
}
}
module.exports = {
initialize,
createDownload,
open,
close,
destroy,
updateWindow
}