diff --git a/CONTRIBUTING-CN.md b/CONTRIBUTING-CN.md index ab96412d6..651c6e9a1 100644 --- a/CONTRIBUTING-CN.md +++ b/CONTRIBUTING-CN.md @@ -4,7 +4,7 @@ ## 🌍 翻译指南 -首先你要确定一个语言的英文简写作为 **locale**,如 en-US,这个 locale 值请严格参考 [Electron 的 Locales 文档](https://www.electronjs.org/docs/api/app#appgetlocale) +首先你要确定一个语言的英文简写作为 **locale**,如 en-US,这个 locale 值请严格参考 [Electron 的 Locales 文档](https://www.electronjs.org/docs/api/app#appgetlocale) 和 [Chromium 源代码](https://source.chromium.org/chromium/chromium/src/+/main:ui/base/l10n/l10n_util.cc)。 Motrix 的国际化分两部分: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 92dab3501..31815aa9e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ Before you start contributing, make sure you already understand [GitHub flow](ht ## 🌍 Translation Guide -First you need to determine the English abbreviation of a language as **locale**, such as en-US, this locale value should strictly refer to the [electron's documentation](https://www.electronjs.org/docs/api/app#appgetlocale). +First you need to determine the English abbreviation of a language as **locale**, such as en-US, this locale value should strictly refer to the [Electron's Documentation](https://www.electronjs.org/docs/api/app#appgetlocale) and [Chromium Source Code](https://source.chromium.org/chromium/chromium/src/+/main:ui/base/l10n/l10n_util.cc). The internationalization of Motrix is divided into two parts: diff --git a/README-CN.md b/README-CN.md index 1d1da205d..f79fffda0 100644 --- a/README-CN.md +++ b/README-CN.md @@ -206,6 +206,7 @@ yarn run build | ja | 日本語 | ✔️ [@hbkrkzk](https://github.com/hbkrkzk) | | ko | 한국어 | ✔️ [@KOZ39](https://github.com/KOZ39) | | nb | Norsk Bokmål | ✔️ [@rubjo](https://github.com/rubjo) | +| nl | Nederlands | ✔️ [@nickbouwhuis](https://github.com/nickbouwhuis) | | pl | Polski | ✔️ [@KanarekLife](https://github.com/KanarekLife) | | pt-BR | Portuguese (Brazil) | ✔️ [@andrenoberto](https://github.com/andrenoberto) | | ro | Română | ✔️ [@alyn3d](https://github.com/alyn3d) | diff --git a/extra/darwin/arm64/engine/aria2.conf b/extra/darwin/arm64/engine/aria2.conf index 1a4384f87..d538e5e41 100644 --- a/extra/darwin/arm64/engine/aria2.conf +++ b/extra/darwin/arm64/engine/aria2.conf @@ -38,8 +38,6 @@ max-file-not-found=5 max-tries=5 # aria2 does not split less than 2*SIZE byte range. min-split-size=1M -# Set user agent for HTTP(S) downloads. -user-agent=Transmission/3.00 # Send Accept: deflate, gzip request header http-accept-gzip=true diff --git a/extra/darwin/x64/engine/aria2.conf b/extra/darwin/x64/engine/aria2.conf index 3c4dc5d64..b5574fd66 100644 --- a/extra/darwin/x64/engine/aria2.conf +++ b/extra/darwin/x64/engine/aria2.conf @@ -38,8 +38,6 @@ max-file-not-found=5 max-tries=5 # aria2 does not split less than 2*SIZE byte range. min-split-size=1M -# Set user agent for HTTP(S) downloads. -user-agent=Transmission/3.00 # Send Accept: deflate, gzip request header http-accept-gzip=true diff --git a/extra/linux/engine/aria2.conf b/extra/linux/engine/aria2.conf index 1c7f8488a..e97e4b7e4 100644 --- a/extra/linux/engine/aria2.conf +++ b/extra/linux/engine/aria2.conf @@ -38,8 +38,6 @@ max-file-not-found=5 max-tries=5 # aria2 does not split less than 2*SIZE byte range. min-split-size=1M -# Set user agent for HTTP(S) downloads. -user-agent=Transmission/3.00 # Send Accept: deflate, gzip request header http-accept-gzip=true diff --git a/extra/win32/ia32/engine/aria2.conf b/extra/win32/ia32/engine/aria2.conf index a2b886f12..cf6fa5f81 100644 --- a/extra/win32/ia32/engine/aria2.conf +++ b/extra/win32/ia32/engine/aria2.conf @@ -38,8 +38,6 @@ max-file-not-found=5 max-tries=5 # aria2 does not split less than 2*SIZE byte range. min-split-size=1M -# Set user agent for HTTP(S) downloads. -user-agent=Transmission/3.00 # Send Accept: deflate, gzip request header http-accept-gzip=true diff --git a/extra/win32/x64/engine/aria2.conf b/extra/win32/x64/engine/aria2.conf index 1f7b8531e..9094423ba 100644 --- a/extra/win32/x64/engine/aria2.conf +++ b/extra/win32/x64/engine/aria2.conf @@ -38,8 +38,6 @@ max-file-not-found=5 max-tries=5 # aria2 does not split less than 2*SIZE byte range. min-split-size=1M -# Set user agent for HTTP(S) downloads. -user-agent=Transmission/3.00 # Send Accept: deflate, gzip request header http-accept-gzip=true diff --git a/package.json b/package.json index 58ce00b95..f219fcf72 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Motrix", - "version": "1.7.2", + "version": "1.8.0", "description": "A full-featured download manager", "homepage": "https://motrix.app", "author": { @@ -58,10 +58,10 @@ "ws": "^8.13.0" }, "devDependencies": { - "@babel/core": "^7.21.3", + "@babel/core": "^7.21.4", "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-transform-runtime": "^7.21.0", - "@babel/preset-env": "^7.20.2", + "@babel/plugin-transform-runtime": "^7.21.4", + "@babel/preset-env": "^7.21.4", "@babel/register": "^7.21.0", "@electron/notarize": "^1.2.3", "@electron/osx-sign": "^1.0.4", @@ -77,7 +77,7 @@ "copy-webpack-plugin": "^11.0.0", "cross-env": "^7.0.3", "css-loader": "^6.7.3", - "css-minimizer-webpack-plugin": "^4.2.2", + "css-minimizer-webpack-plugin": "^5.0.0", "del": "^6.1.1", "electron": "^22.3.3", "electron-builder": "^23.6.0", @@ -102,7 +102,7 @@ "vue-template-compiler": "^2.7.14", "webpack": "^5.77.0", "webpack-cli": "^5.0.1", - "webpack-dev-server": "^4.13.1", + "webpack-dev-server": "^4.13.2", "webpack-hot-middleware": "^2.25.3", "webpack-merge": "^5.8.0", "worker-loader": "^3.0.8" diff --git a/src/main/Application.js b/src/main/Application.js index f9809087b..b73b5aab3 100644 --- a/src/main/Application.js +++ b/src/main/Application.js @@ -3,7 +3,7 @@ import { app, shell, dialog, ipcMain } from 'electron' import is from 'electron-is' import { readFile, unlink } from 'fs' import { extname, basename } from 'path' -import { isEmpty } from 'lodash' +import { isEmpty, isEqual } from 'lodash' import { APP_RUN_MODE, @@ -42,11 +42,9 @@ export default class Application extends EventEmitter { } init () { - this.configManager = this.initConfigManager() + this.initConfigManager() - this.locale = this.configManager.getLocale() - this.localeManager = setupLocaleManager(this.locale) - this.i18n = this.localeManager.getI18n() + this.initLocaleManager() this.setupApplicationMenu() @@ -66,9 +64,9 @@ export default class Application extends EventEmitter { this.initDockManager() - this.autoLaunchManager = new AutoLaunchManager() + this.initAutoLaunchManager() - this.energyManager = new EnergyManager() + this.initEnergyManager() this.initUpdaterManager() @@ -87,7 +85,7 @@ export default class Application extends EventEmitter { initConfigManager () { this.configListeners = {} - return new ConfigManager() + this.configManager = new ConfigManager() } offConfigListeners () { @@ -101,6 +99,12 @@ export default class Application extends EventEmitter { this.configListeners = {} } + initLocaleManager () { + this.locale = this.configManager.getLocale() + this.localeManager = setupLocaleManager(this.locale) + this.i18n = this.localeManager.getI18n() + } + setupApplicationMenu () { this.menuManager = new MenuManager() this.menuManager.setup(this.locale) @@ -162,11 +166,20 @@ export default class Application extends EventEmitter { }) } + initAutoLaunchManager () { + this.autoLaunchManager = new AutoLaunchManager() + } + + initEnergyManager () { + this.energyManager = new EnergyManager() + } + initTrayManager () { this.trayManager = new TrayManager({ theme: this.configManager.getUserConfig('tray-theme'), systemTheme: this.themeManager.getSystemTheme(), - speedometer: this.configManager.getUserConfig('tray-speedometer') + speedometer: this.configManager.getUserConfig('tray-speedometer'), + runMode: this.configManager.getUserConfig('run-mode') }) this.watchTraySpeedometerEnabledChange() @@ -191,8 +204,8 @@ export default class Application extends EventEmitter { watchTraySpeedometerEnabledChange () { const { userConfig } = this.configManager const key = 'tray-speedometer' - this.configListeners[key] = userConfig.onDidChange('tray-speedometer', async (newValue, oldValue) => { - logger.info('[Motrix] detected tray speedometer value change event:', newValue, oldValue) + this.configListeners[key] = userConfig.onDidChange(key, async (newValue, oldValue) => { + logger.info(`[Motrix] detected ${key} value change event:`, newValue, oldValue) this.trayManager.handleSpeedometerEnableChange(newValue) }) } @@ -203,6 +216,55 @@ export default class Application extends EventEmitter { }) } + watchOpenAtLoginChange () { + const { userConfig } = this.configManager + const key = 'open-at-login' + this.configListeners[key] = userConfig.onDidChange(key, async (newValue, oldValue) => { + logger.info(`[Motrix] detected ${key} value change event:`, newValue, oldValue) + if (is.linux()) { + return + } + + if (newValue) { + this.autoLaunchManager.enable() + } else { + this.autoLaunchManager.disable() + } + }) + } + + watchProtocolsChange () { + const { userConfig } = this.configManager + const key = 'protocols' + this.configListeners[key] = userConfig.onDidChange(key, async (newValue, oldValue) => { + logger.info(`[Motrix] detected ${key} value change event:`, newValue, oldValue) + + if (!newValue || isEqual(newValue, oldValue)) { + return + } + + logger.info('[Motrix] setup protocols client:', newValue) + this.protocolManager.setup(newValue) + }) + } + + watchRunModeChange () { + const { userConfig } = this.configManager + const key = 'run-mode' + this.configListeners[key] = userConfig.onDidChange(key, async (newValue, oldValue) => { + logger.info(`[Motrix] detected ${key} value change event:`, newValue, oldValue) + this.trayManager.handleRunModeChange(newValue) + + if (newValue !== APP_RUN_MODE.TRAY) { + this.dockManager.show() + } else { + this.dockManager.hide() + // Hiding the dock icon will trigger the entire app to hide. + this.show() + } + }) + } + initUPnPManager () { this.upnp = new UPnPManager() @@ -365,7 +427,7 @@ export default class Application extends EventEmitter { this.windowManager.on('leave-full-screen', (window) => { const mode = this.configManager.getUserConfig('run-mode') - if (mode !== APP_RUN_MODE.STANDARD) { + if (mode === APP_RUN_MODE.TRAY) { this.dockManager.hide() } }) @@ -393,6 +455,7 @@ export default class Application extends EventEmitter { this.isReady = true this.emit('ready') }) + if (is.macOS()) { this.touchBarManager.setup(page, win) } @@ -621,18 +684,6 @@ export default class Application extends EventEmitter { this.quit() }) - this.on('application:open-at-login', (openAtLogin) => { - if (is.linux()) { - return - } - - if (openAtLogin) { - this.autoLaunchManager.enable() - } else { - this.autoLaunchManager.disable() - } - }) - this.on('application:show', ({ page }) => { this.show(page) }) @@ -769,6 +820,10 @@ export default class Application extends EventEmitter { this.configManager.userConfig.onDidAnyChange(() => this.handleConfigChange('user')) this.configManager.systemConfig.onDidAnyChange(() => this.handleConfigChange('system')) + this.watchOpenAtLoginChange() + this.watchProtocolsChange() + this.watchRunModeChange() + this.on('download-status-change', (downloading) => { this.trayManager.handleDownloadStatusChange(downloading) if (downloading) { diff --git a/src/main/core/ConfigManager.js b/src/main/core/ConfigManager.js index f925795fb..9a5cbae38 100644 --- a/src/main/core/ConfigManager.js +++ b/src/main/core/ConfigManager.js @@ -18,6 +18,7 @@ import { NGOSANG_TRACKERS_BEST_IP_URL_CDN, NGOSANG_TRACKERS_BEST_URL_CDN } from '@shared/constants' +import { CHROME_UA } from '@shared/ua' import { separateConfig } from '@shared/utils' import { reduceTrackerString } from '@shared/utils/tracker' @@ -77,7 +78,7 @@ export default class ConfigManager { 'seed-ratio': 1, 'seed-time': 60, 'split': getMaxConnectionPerServer(), - 'user-agent': 'Transmission/3.00' + 'user-agent': CHROME_UA } /* eslint-enable quote-props */ }) diff --git a/src/main/ui/DockManager.js b/src/main/ui/DockManager.js index 0a74cf949..9579b0b7f 100644 --- a/src/main/ui/DockManager.js +++ b/src/main/ui/DockManager.js @@ -15,7 +15,7 @@ export default class DockManager extends EventEmitter { super() this.options = options const { runMode } = this.options - if (runMode !== APP_RUN_MODE.STANDARD) { + if (runMode === APP_RUN_MODE.TRAY) { this.hide() } } diff --git a/src/main/ui/TrayManager.js b/src/main/ui/TrayManager.js index 63319fb69..c47a40854 100644 --- a/src/main/ui/TrayManager.js +++ b/src/main/ui/TrayManager.js @@ -3,7 +3,7 @@ import { join } from 'path' import { Tray, Menu, nativeImage } from 'electron' import is from 'electron-is' -import { APP_THEME } from '@shared/constants' +import { APP_RUN_MODE, APP_THEME } from '@shared/constants' import { getInverseTheme } from '@shared/utils' import { getI18n } from './Locale' import { @@ -29,6 +29,7 @@ export default class TrayManager extends EventEmitter { this.macOS = platform === 'darwin' this.speedometer = options.speedometer + this.runMode = options.runMode this.i18n = getI18n() this.menu = null @@ -38,20 +39,23 @@ export default class TrayManager extends EventEmitter { this.downloadSpeed = 0 this.status = false this.focused = false + this.initialized = false this.init() } init () { - this.loadTemplate() + if (tray || this.initialized || this.runMode === APP_RUN_MODE.HIDE_TRAY) { + return + } + this.loadTemplate() this.loadImages() - this.initTray() - this.setupMenu() + this.bindEvents() - this.handleEvents() + this.initialized = true } loadTemplate () { @@ -150,7 +154,7 @@ export default class TrayManager extends EventEmitter { } } - handleEvents () { + bindEvents () { // All OS tray.on('click', this.handleTrayClick) @@ -166,6 +170,20 @@ export default class TrayManager extends EventEmitter { tray.on('drop-text', this.handleTrayDropText) } + unbindEvents () { + // All OS + tray.removeListener('click', this.handleTrayClick) + + // macOS, Windows + tray.removeListener('right-click', this.handleTrayRightClick) + tray.removeListener('mouse-down', this.handleTrayMouseDown) + tray.removeListener('mouse-up', this.handleTrayMouseUp) + + // macOS only + tray.removeListener('drop-files', this.handleTrayDropFiles) + tray.removeListener('drop-text', this.handleTrayDropText) + } + handleTrayClick = (event) => { global.application.toggle() } @@ -279,6 +297,15 @@ export default class TrayManager extends EventEmitter { this.setupMenu() } + handleRunModeChange (mode) { + console.log('handleRunModeChange===>', mode) + if (mode === APP_RUN_MODE.HIDE_TRAY) { + this.destroy() + } else { + this.init() + } + } + handleSpeedometerEnableChange (enabled) { this.toggleSpeedometer(enabled) @@ -330,16 +357,11 @@ export default class TrayManager extends EventEmitter { destroy () { if (tray) { - tray.removeListener('click', this.handleTrayClick) - // tray.removeListener('double-click', this.handleTrayDbClick) - tray.removeListener('right-click', this.handleTrayRightClick) - tray.removeListener('mouse-down', this.handleTrayMouseDown) - tray.removeListener('mouse-up', this.handleTrayMouseUp) - - tray.removeListener('drop-files', this.handleTrayDropFiles) - tray.removeListener('drop-text', this.handleTrayDropText) + this.unbindEvents() } tray.destroy() + tray = null + this.initialized = false } } diff --git a/src/renderer/components/Native/DynamicTray.vue b/src/renderer/components/Native/DynamicTray.vue index 5838b0dfc..000043de0 100644 --- a/src/renderer/components/Native/DynamicTray.vue +++ b/src/renderer/components/Native/DynamicTray.vue @@ -1,22 +1,22 @@