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 @@
-
+