Compare commits

...

134 Commits

Author SHA1 Message Date
Dr_rOot 83b55b806d fix: bump version to 1.2.2 2019-03-24 20:44:30 +08:00
Dr_rOot d4dab6de9b fix: linux parse argv 2019-03-24 20:43:23 +08:00
Dr_rOot deae5e8e33 fix: bump version 2019-03-24 10:42:34 +08:00
Dr_rOot b098c8c9bc fix: open file argv path undefined 2019-03-24 10:42:05 +08:00
Dr_rOot b12553cc45 fix: try to fix linux read file eof 2019-03-23 18:15:13 +08:00
Dr_rOot 8891b9a79c refactor: windows tray icon changed to png 2019-03-23 16:12:27 +08:00
Dr_rOot a44f088139 fix: try to downgrade electron-builder 2019-03-22 23:45:47 +08:00
Dr_rOot 7ea0cd3e75 fix: fileAssociations for AppImage 2019-03-22 22:16:29 +08:00
Dr_rOot c93cc9d23b fix: remove node from devDependencies 2019-03-22 22:02:21 +08:00
Dr_rOot 8d2e14486d fix: remove npm audit fix 2019-03-22 21:56:14 +08:00
Dr_rOot 3775da5e36 Merge branch 'hotfix/main_refactor_201903151054' 2019-03-22 21:50:40 +08:00
Dr_rOot 2e21285f99 fix: update dependencies 2019-03-22 21:49:23 +08:00
Dr_rOot 6c2dde8e59 chore: try add npm audit fix to ci shell 2019-03-22 21:47:58 +08:00
Dr_rOot e014580512 feat: update tray icon based on changes in the download status 2019-03-22 21:45:11 +08:00
Dr_rOot e970a51b71 refactor: remove unuse menu config json 2019-03-21 18:23:07 +08:00
Antoine Leblanc 019f8be306 fix: i18n fr in preferences (#152) 2019-03-21 11:10:39 +08:00
Dr_rOot 20f79dacb7 refactor: menu i18n 2019-03-20 23:22:48 +08:00
Dr_rOot 1bdd17a80a feat: add tray 2019-03-20 23:18:30 +08:00
Dr_rOot b01e006073 refactor: window close event 2019-03-20 22:57:31 +08:00
Dr_rOot 82728a2b23 refactor: windows manager show hide 2019-03-20 22:55:37 +08:00
Dr_rOot 217d2df5be fix: open-file dialog cancel 2019-03-20 21:10:02 +08:00
Dr_rOot 960f0674ef fix: open url send command to all 2019-03-19 23:17:53 +08:00
Dr_rOot 54e9f326d9 refactor: return change language promise 2019-03-19 23:16:41 +08:00
Dr_rOot 4e7267028f fix: sendCommandToAll fn typo 2019-03-19 23:14:58 +08:00
Dr_rOot efd7f97a36 fix: add open-file to task i18n file 2019-03-19 23:13:04 +08:00
Dr_rOot 5bb790822d fix: mac dock download speed text add /s 2019-03-19 18:30:19 +08:00
Dr_rOot 71f3fb601b fix: send command no effect when no focused window 2019-03-19 18:29:35 +08:00
Dr_rOot af710aa265 refactor: rename handleFileAssociation 2019-03-19 18:05:20 +08:00
Dr_rOot 52b6fb0849 fix: add pt menu missing translations 2019-03-17 12:09:06 +08:00
Dr_rOot b8d63374b7 fix: add fr menu missing translations 2019-03-17 11:50:19 +08:00
Dr_rOot ff38d4ea5c refactor: main index to launcher 2019-03-17 11:36:18 +08:00
Dr_rOot a24a7acfaf feat: add support for windows x86 2019-03-17 11:34:44 +08:00
Dr_rOot 16e9c8d848 feat: add torrent to file associations 2019-03-17 11:33:44 +08:00
Dr_rOot f36cdccf9f feat: open torrent from file dialog 2019-03-17 11:31:54 +08:00
Dr_rOot c826a7dd77 fix: on download pause message 2019-03-17 11:20:22 +08:00
Dr_rOot b96518a42c fix: remove task confirm message typo 2019-03-17 10:54:41 +08:00
Dr_rOot 02f0b66500 fix: select torrent counld not replace 2019-03-17 10:54:12 +08:00
Dr_rOot 377bc47d87 refactor: engine fetchTaskItem 2019-03-17 00:29:18 +08:00
Dr_rOot f8a4ef267d fix: i18n startEngine error message 2019-03-17 00:27:52 +08:00
Dr_rOot baea3f0345 refactor: task removeTask action 2019-03-16 21:26:52 +08:00
Dr_rOot 1fcf0bb0d0 fix: main i18n #120
close #120
2019-03-16 16:11:10 +08:00
Dr_rOot 85e1acfe5b chore: config manager add doc link comment 2019-03-16 16:07:05 +08:00
Dr_rOot 41ac6ad335 fix: add missing translations 2019-03-16 16:05:15 +08:00
Dr_rOot b151c45e70 fix: remove useless page configuration 2019-03-16 16:04:06 +08:00
Dr_rOot b3686fff04 fix: torrent dragger on drop 2019-03-15 23:32:58 +08:00
Dr_rOot af81107b3d fix: temp set max-overall-upload-limit=128K #136
Preferences will be added to the speed limit setting.
close #136
2019-03-14 21:24:08 +08:00
Dr_rOot 88224998b7 fix: readme link 2019-03-14 21:03:18 +08:00
Dr_rOot 8508ca9b3c fix: i18n pt-BR 2019-03-14 21:01:38 +08:00
Dr_rOot 6fad6a876c chore: update readme i18n progress 2019-03-14 20:59:14 +08:00
Dr_rOot 6c8a844cd9 fix: copyright left & right width 2019-03-14 20:47:52 +08:00
Schlömi 4657a503f9 feat: added german (#140)
* added german

* Improved german

* more details for preferences.continue

* shorted some translations, added missing seperator
2019-03-14 20:46:14 +08:00
Dr_rOot 324347e591 fix: menu task.clear-recent-tasks no effect #135
close #135
2019-03-10 15:28:53 +08:00
Kay 16c376c108 refactor: drag and drop file (#124)
* add drag file

* refactor: drag and drop file

* add template
2019-03-10 10:47:57 +08:00
monomagentaeggroll 79cad28cc1 fix: README.md editing (#123)
* Update README.md

Revision sweep of the README.md file.
Some style changes, fixes a few typos, and corrects some grammar.

* Update README.md
2019-03-04 20:52:22 +08:00
Dr_rOot ac16bd91c2 fix: i18n pt explanation 2019-03-03 19:43:21 +08:00
Dr_rOot fafeaca47d chore: update bug_report_cn issue template 2019-03-03 19:36:07 +08:00
Dr_rOot 3152252fb8 refactor: i18n sort locale key 2019-03-03 19:25:53 +08:00
FramboisePi a5240bfeb0 fix: French spelling improvement (#117)
* Accents correction

* French: accent improvement in edit.js

* French: accent improvement in help.js

* French: accent improvement in menu.js

* French spelling improvement in preferences.js

* French spelling improvement in task.js
2019-03-03 19:24:25 +08:00
Andre Noberto 64cda63587 feat: Adding the Brazilian portuguese translation to the app [Done] (#111)
* Added locales for pt-BR

* Added menu support for pt-BR

* Configuring pt-BR in locales

* Fixing typo

* Make use of abbreviation

* Fixed typo & adjustments on variable naming case
2019-03-03 18:34:38 +08:00
Dr_rOot fe071a3783 fix: temp limit the task list num 2019-03-01 22:25:14 +08:00
Dr_rOot 5d812e9c4e fix: readme typo 2019-03-01 22:07:25 +08:00
Dr_rOot f36ba605e2 fix: update readme 2019-03-01 21:32:26 +08:00
Dr_rOot e7ed58e394 fix: i18n for some reason 2019-03-01 21:27:44 +08:00
Dr_rOot be789e7ea8 Merge pull request #108 from Yukaii/locale-zh-tw
feat: Add zh-TW language support
2019-03-01 20:44:08 +08:00
Yukai Huang 780a01e404 feat: Adding zh-TW language support 2019-03-01 14:51:04 +08:00
Dr_rOot b45518a5b6 fix: increase engine retry max to 10 2019-02-28 13:17:12 +08:00
Dr_rOot 2401d68a24 fix: add missing brew cask cmd 2019-02-28 13:16:36 +08:00
Dr_rOot 6cb2986f39 style: readme adjust the paragraph 2019-02-28 13:03:53 +08:00
Dr_rOot cb8e0dbd2e refactor: advanced preference change lng 2019-02-28 13:01:03 +08:00
Dr_rOot b4faed0621 docs: update readme 2019-02-28 12:59:55 +08:00
Dr_rOot 249aa616fe Merge pull request #101 from gpatarin/master
feat: Adding the french translation to the app [Done]
2019-02-28 12:57:52 +08:00
Gael Patarin 482ccb3293 Update utils.js to match latest changes 2019-02-27 23:33:21 +01:00
Gael Patarin f1be6bc1a4 Translated the app to french 2019-02-27 19:52:56 +01:00
Dr_rOot 326e8c700b fix: update i18n progress 2019-02-27 21:13:57 +08:00
Dr_rOot 2a538fd7c3 fix: getTaskFullPath bittorrent 2019-02-27 21:07:00 +08:00
Dr_rOot c424b981b3 Merge pull request #97 from agalwood/revert-93-master
fix: Revert "feat: Adding the french translation to the app [WIP]"
2019-02-27 21:05:26 +08:00
Dr_rOot a284aba2cc Revert "feat: Adding the french translation to the app [WIP]" 2019-02-27 20:54:07 +08:00
Dr_rOot c8bfdbf087 Merge pull request #93 from gpatarin/master
feat: Adding the french translation to the app [WIP]
2019-02-27 20:47:49 +08:00
Gael Patarin eb80f3698f More translation in french (WIP) 2019-02-26 19:18:55 +01:00
Gael Patarin 23f3d85ad4 Added french translation 2019-02-26 19:13:28 +01:00
Dr_rOot 24019123ba fix: add i18n guide link to readme 2019-02-25 23:48:56 +08:00
Dr_rOot 06a471982a fix: add CONTRIBUTING Guide 2019-02-25 23:46:24 +08:00
Dr_rOot 43627aba50 fix: linux AppImage dock icon missing #83
Close #83
2019-02-25 19:33:23 +08:00
Dr_rOot 8116234b3e fix: update npm dependencies 2019-02-24 15:21:45 +08:00
Dr_rOot e488de5c3f fix: magnet link task moveTaskFilesToTrash bug 2019-02-24 15:05:19 +08:00
Dr_rOot 084f834a41 fix: update readme 2019-02-24 13:33:18 +08:00
Dr_rOot 97d30ee85e fix: update bug report issue template 2019-02-24 13:05:32 +08:00
Dr_rOot 387ccc9cf7 fix: i18n download-session-path error 2019-02-23 18:32:50 +08:00
Dr_rOot fed5744607 docs: update github issue template 2019-02-21 12:56:30 +08:00
Dr_rOot 3e2b448e09 fix: openDownloadDock & updateDockBadge mac only 2019-02-20 18:05:43 +08:00
Dr_rOot c12c13066d fix: magnet task file path did not start with dir 2019-02-20 12:54:51 +08:00
Dr_rOot 5c36454ca0 fix: copy link fail when bttorrent info is empty 2019-02-20 12:54:17 +08:00
Dr_rOot 7b6ba13d94 fix: eslint 2019-02-19 20:52:03 +08:00
Dr_rOot 5d93d4d7bb fix: bt task copy link bug #39
Close #39
2019-02-19 20:50:36 +08:00
Dr_rOot 4d024eb6a6 feat: fetch engineOptions (getGlobalOption) 2019-02-19 20:48:39 +08:00
Dr_rOot 182acec265 fix: remove task with file name is empty bug #75 2019-02-18 22:54:05 +08:00
Dr_rOot e293b16343 fix: one msg notify twice error 2019-02-18 22:29:39 +08:00
Dr_rOot 70cf36d7b2 Merge pull request #73 from Raistlin916/master
refactor: message refactor
2019-02-18 21:33:57 +08:00
Kay f3d8cac9ba fix: update .editorconfig 2019-02-18 21:24:03 +08:00
Dr_rOot 620b243794 Merge pull request #72 from mesquka/master
fix: Consistant hms capitalisation
2019-02-18 11:46:08 +08:00
gaokai 37fe7d4dbd feat: msg add max length with queue 2019-02-18 01:05:25 +08:00
gaokai 11b6d651b8 refactor: message default options 2019-02-18 00:36:21 +08:00
Kieran Mesquita 8a5bc11d88 Merge remote-tracking branch 'upstream/master' 2019-02-17 23:07:24 +08:00
Kieran Mesquita bf69146035 Decapitalise 'h' for hms consistancy 2019-02-17 23:06:43 +08:00
Dr_rOot 14ff0c4bbe fix: add preferences missing translations 2019-02-17 11:02:29 +08:00
Dr_rOot d9706a2c3e Merge pull request #70 from abdullah/improve-tr-localization-key
refactor: rename Turkish i18n key from 'Tr-tr' to 'tr'
2019-02-17 10:57:58 +08:00
Abdullah mara c36f7b73f1 refactor: rename Turkish i18n key from 'Tr-tr' to 'tr'
This commit also includes menu localization keys.
2019-02-16 21:06:20 +03:00
Dr_rOot 7e6d0542cc fix: update readme 2019-02-16 23:11:12 +08:00
Dr_rOot 72bf4ec909 style: update i18n 2019-02-16 23:09:40 +08:00
Dr_rOot fa87b8ff9b fix: i18n hash link 2019-02-16 23:07:38 +08:00
Dr_rOot 31203e72fc fix: update README i18n 2019-02-16 23:06:07 +08:00
Dr_rOot 5bd9875f61 Merge pull request #67 from abdullah/add-turkish
feat: Add Turkish.
2019-02-16 21:56:54 +08:00
Abdullah mara 646ad28fbc Add Turkish. 2019-02-16 16:30:51 +03:00
Dr_rOot a66d482d3a fix: aside draggable area not response click event 2019-02-16 19:45:59 +08:00
Dr_rOot 5dfc8cce37 Merge pull request #63 from mesquka/master
feat: Make notifications dismissible and truncate long messages
2019-02-16 10:28:16 +08:00
Kieran Mesquita 4c88431147 Make all message notifications dismissable 2019-02-16 02:49:04 +08:00
Dr_rOot bb06b3970d refactor: util getTaskName 2019-02-15 23:48:26 +08:00
Dr_rOot c86767bc3f fix: el message text style 2019-02-15 23:44:17 +08:00
Dr_rOot 3c6d14ec7e Merge pull request #59 from mesquka/master
fix: Form Labels in add Task
2019-02-15 14:13:11 +08:00
Kieran Mesquita 88a9a69c27 Adjust width of add task labels to fit 'user-agent' 2019-02-15 13:52:02 +08:00
Kieran Mesquita da7241cd6a Fix Form Labels 2019-02-15 13:44:10 +08:00
Dr_rOot 397055826e Merge pull request #57 from Raistlin916/master
feat: drag & drop torrent file to add task
2019-02-15 11:54:31 +08:00
raistlin916 2e6b8bb5fa add drag file 2019-02-15 10:57:04 +08:00
Dr_rOot ed4f3afcbd fix: update app screenshot 2019-02-14 21:35:47 +08:00
Dr_rOot 53ab75fbf9 fix: update hide app menu default 2019-02-14 21:20:33 +08:00
Dr_rOot c19cf17b07 fix: update read me 2019-02-14 17:23:54 +08:00
Dr_rOot a994f45e8f fix: add manual link to readme 2019-02-14 13:28:24 +08:00
Dr_rOot 1bdaeeb3a6 fix: Windows title bar drag 2019-02-13 12:08:18 +08:00
Dr_rOot 32f0a3d084 fix: windows &linux hide app menu fail 2019-02-12 23:25:24 +08:00
Dr_rOot ba4ef326f7 feat: add lock bot config 2019-02-11 21:57:42 +08:00
Dr_rOot 10a8f0bd16 fix: remove pacman && update version to 1.1.3 2019-02-10 23:14:47 +08:00
Dr_rOot d3c40a8fc3 fix: remove rpm && update version to 1.1.2 2019-02-10 23:04:30 +08:00
Dr_rOot 34a9247270 fix: update version to 1.1.1 2019-02-10 22:52:48 +08:00
Dr_rOot 0b0f9b41e9 feat: add more linux targets 2019-02-10 22:51:47 +08:00
139 changed files with 5991 additions and 1891 deletions
+8
View File
@@ -0,0 +1,8 @@
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
-14
View File
@@ -143,20 +143,6 @@ let webConfig = {
? path.resolve(__dirname, '../node_modules')
: false
}),
new HtmlWebpackPlugin({
title: '关于',
filename: 'about.html',
chunks: ['about'],
template: path.resolve(__dirname, '../src/about.ejs'),
// minify: {
// collapseWhitespace: true,
// removeAttributeQuotes: true,
// removeComments: true
// },
nodeModules: devMode
? path.resolve(__dirname, '../node_modules')
: false
}),
new webpack.DefinePlugin({
'process.env.IS_WEB': 'true'
}),
+11 -7
View File
@@ -2,11 +2,16 @@
name: Bug report
about: Create a report to help us improve
title: ''
labels: "bug \U0001F41E"
labels: ''
assignees: ''
---
**Before feedback**
Before you feedback, please search for the issues to see if there are similar problems that can solve your problem.
**Please delete the above and the contents of this line, then fill in the feedback form in the following format, Thanks.**
**Describe the bug**
A clear and concise description of what the bug is.
@@ -23,12 +28,11 @@ A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. macOS, Windows, Linux]
- Version [e.g. 10.14.2, Win 10]
**App (please complete the following information):**
- Version [e.g. 1.1.0]
**Environment (please complete the following information):**
- OS & Version: [e.g. macOS, Windows, Linux]
- Version: [e.g. macOS 10.14.2, Windows 10, Ubuntu 18.04]
- Motrix Version: [e.g. v1.1.3, v1.1.0]
- Installation package type: [e.g. dmg, AppImage]
**Additional context**
Add any other context about the problem here.
+40
View File
@@ -0,0 +1,40 @@
---
name: 错误反馈
about: 创建一个错误报告帮助改进「请按照模板提交,提供详细的信息,方便我们复现之后处理」
title: ''
labels: ''
assignees: ''
---
**反馈之前**
反馈之前请搜索一下已有 issues 和 帮助文档,看是否有类似问题可以解决你的问题
https://github.com/agalwood/Motrix/issues
http://motrix.app/support
**请删除上面和本行的内容,然后按以下格式填写反馈信息,谢谢**
**错误描述**
清楚简洁地描述错误,方便我们复现之后处理。
**如何重现**
重现步骤,如:
1. 点击新建任务按钮
2. 黏贴链接(如链接不涉及到隐私和版权问题,请顺便提供)
3. 点击提交
4. 发现报错
**预期的行为**
清楚简洁地描述您期望发生的事情。
**截图**
请添加屏幕截图以帮助解释您的问题:
打开应用菜单中的「帮助」——「开发者工具」—— 切换到 console,然后**完整**截图。
**运行环境**
- 操作系统类型: [如 macOS, Windows, Linux]
- 具体版本: [如 macOS 10.14.2, Windows 10, Ubuntu 18.04]
- Motrix 版本: [如 v1.1.3, v1.1.0]
- 安装包类型:[如 dmg, AppImage]
**更多信息**
添加有关此问题的任何其他上下文信息。
+38
View File
@@ -0,0 +1,38 @@
# Configuration for Lock Threads - https://github.com/dessant/lock-threads
# Number of days of inactivity before a closed issue or pull request is locked
daysUntilLock: 30
# Skip issues and pull requests created before a given timestamp. Timestamp must
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
skipCreatedBefore: false
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
exemptLabels: []
# Label to add before locking, such as `outdated`. Set to `false` to disable
lockLabel: false
# Comment to post before locking. Set to `false` to disable
lockComment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.
# Assign `resolved` as the reason for locking. Set to `false` to disable
setLockReason: true
# Limit to only `issues` or `pulls`
# only: issues
# Optionally, specify configuration settings just for `issues` or `pulls`
# issues:
# exemptLabels:
# - help-wanted
# lockLabel: outdated
# pulls:
# daysUntilLock: 30
# Repository to extend settings from
# _extends: repo
+37
View File
@@ -0,0 +1,37 @@
# Motrix 贡献指南
## 🌍 翻译指南
首先你要确定一个语言的英文简写作为 **locale**,如 en-US,这个 locale 值请严格参考 [Electron 的 Locales 文档](https://electronjs.org/docs/api/locales)
Motrix 的国际化分三部分:
- Element UI
- 应用菜单
- 主界面
### Element UI
Element UI 的国际化由 [Element 社区](http://element.eleme.io/#/en-US/component/i18n)提供,找到 **locale** 对应的语言包文件「两者 locale 命名可能不一致」,在 `src/shared/locales/all.js` 中引入,如
```
import eleLocaleEn from 'element-ui/lib/locale/lang/en'
import eleLocaleZhCN from 'element-ui/lib/locale/lang/zh-CN'
```
### 应用菜单
应用菜单的国际化文件按照语言进行目录划分,每个目录里有三大操作系统对应的 JSON 文件:
- darwin.json
- linux.json
- win32.json
### 主界面
主界面和 Element UI 都是用 i18next 作为翻译支持库,所以你可能需要简单了解一下它的[使用方法](https://www.i18next.com/overview/getting-started)。
主界面的配置同样按照语言划分目录:`src/shared/locales`,如:`src/shared/locales/en-US``src/shared/locales/zh-CN`
目录里面有按业务模块划分的语言文件:
- about.js
- app.js
- edit.js
- help.js
- index.js
- menu.js
- preferences.js
- subnav.js
- task.js
- window.js
+37
View File
@@ -0,0 +1,37 @@
# Motrix Contributing Guide
## 🌍 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://electronjs.org/docs/api/locales).
The internationalization of Motrix is divided into three parts:
- Element UI
- Application Menu
- Main Interface
### Element UI
The internationalization of Element UI is provided by the [Element community](http://element.eleme.io/#/en-US/component/i18n), then find the language pack file corresponding to **locale** (both locale naming may be inconsistent), which is import in `src/shared/locales/all.js`, such as
```
import eleLocaleEn from 'element-ui/lib/locale/lang/en'
import eleLocaleZhCN from 'element-ui/lib/locale/lang/zh-CN'
```
### Application Menu
The internationalization files of the application menu are divided into directories according to the **locale**. Each directory has three JSON files corresponding to the OS:
- darwin.json
- linux.json
- win32.json
### Main Interface
Both the main interface and the Element UI use [i18next](https://www.i18next.com/overview/getting-started) as the translation support library, so you may need to take a brief look at how to use it.
The configuration of the main interface is also divided into directories according to the **locale**: `src/shared/locales`, such as: `src/shared/locales/en-US` and `src/shared/locales/zh-CN`.
There are language files in the directory divided by business modules:
- about.js
- app.js
- edit.js
- help.js
- index.js
- menu.js
- preferences.js
- subnav.js
- task.js
- window.js
+24 -7
View File
@@ -13,28 +13,32 @@
Motirx 是一款全能的下载工具,支持下载 HTTP、FTP、BT、磁力链、百度网盘等资源。它的界面简洁易用,希望大家喜欢 👻。
✈️ 去 [官网](https://motrix.app) 逛逛
✈️ 去 [官网](https://motrix.app/zh-CN) 逛逛 | 📖 查看 [帮助手册](http://motrix.app/support/issues)
## 💽 安装稳定版
[GitHub](https://github.com/agalwood/Motrix/releases) 和 [官网](https://motrix.app) 提供了已经编译好的稳定版安装包,当然你也可以自己克隆代码编译打包。
[GitHub](https://github.com/agalwood/Motrix/releases) 和 [官网](https://motrix.app/zh-CN) 提供了已经编译好的稳定版安装包,当然你也可以自己克隆代码编译打包。
> 七牛CDN流量🔥烧不起,高峰时一天烧了110G的流量💸💸💸
更新:macOS 用户支持 `brew cask` 安装,感谢 [Mitscherlich](https://github.com/Mitscherlich) 的 [PR](https://github.com/Homebrew/homebrew-cask/pull/59494)。
```bash
brew update && brew cask install motrix
```
## ✨ 特性
- 🕹 简洁明了的图形操作界面
- 🧲 支持BT和磁力链任务
- 🤫 支持下载百度云盘资源
- 🦄 支持BT和磁力链任务
- 💾 支持下载百度云盘资源
- 🎛 最高支持 10 个任务同时下载
- 🚀 单任务最高支持 64 线程下载
- 🕶 模拟用户代理UA
- 🔔 下载完成后通知
- 💻 支持触控栏快捷健 (Mac 专享)
- 🗑 移除任务时可同时删除相关文件
- 🌍 国际化(可选择简体中文或英文界面)
- 🌍 国际化[查看已可选的语言](#-国际化)
- 🎏 ...
## 🖥 应用界面
![motrix-screenshot-task-cn.png](https://cdn.nlark.com/yuque/0/2019/png/129147/1548251088177-21762a41-3975-4417-bf54-6f64aeb0f20d.png)
![motrix-screenshot-task-cn.png](https://cdn.nlark.com/yuque/0/2019/png/129147/1550151234585-e513bd4f-e127-402f-accb-1ebbba9b3c41.png)
## ⌨️ 本地开发
@@ -78,5 +82,18 @@ npm run build
## 🤝 参与共建 [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
如果你有兴趣参与共同开发,欢迎 FORK 和 PR。
## 🌍 国际化
欢迎大家将 Motrix 翻译成更多的语言版本 🧐,开工之前请先阅读一下 [翻译指南](./CONTRIBUTING-CN.md#-翻译指南)。
| Key | Name | Status |
|-------|:--------------------|:-------------|
| de | German | 下版本发布 [@Schloemicher](https://github.com/Schloemicher) |
| en-US | English | ✔️ |
| fr | Français | 下版本发布 [@gpatarin](https://github.com/gpatarin) |
| pt-BR | Portuguese (Brazil) | 下版本发布 [@andrenoberto](https://github.com/andrenoberto) |
| tr | Türkçe | 下版本发布 [@abdullah](https://github.com/abdullah) |
| zh-CN | 简体中文 | ✔️ |
| zh-TW | 繁體中文 | 下版本发布 [@Yukaii](https://github.com/Yukaii) |
## 📜 开源许可
基于 [MIT license](https://opensource.org/licenses/MIT) 许可进行开源。
+30 -11
View File
@@ -9,30 +9,36 @@
English | [简体中文](./README-CN.md)
Motrix is a full-featured download manager that support downloading HTTP, FTP, BitTorrent, Magnet, Baidu Net Disk etc.
Motrix is a full-featured download manager that supports downloading HTTP, FTP, BitTorrent, Magnet, Baidu Net Disk, etc.
It has a clean and simple interface and is easy to use. I hope you will like it 👻.
Motrix has a clean and easy to use interface. I hope you will like it 👻.
✈️ [Official Website](https://motrix.app)
✈️ [Official Website](https://motrix.app) | 📖 [Manual](http://motrix.app/support/issues) (zh-CN)
## 💽 Installation
Download from [GitHub Releases](https://github.com/agalwood/Motrix/releases) and install it.
Update: macOS user support `brew cask` installation, thanks to [PR](https://github.com/Homebrew/homebrew-cask/pull/59494) of [Mitscherlich](https://github.com/Mitscherlich).
```bash
brew update && brew cask install motrix
```
## ✨ Features
- 🕹 Simple and clear user interface
- 🧲 Support BitTorrent & Magnet
- 🤫 Support downloading Baidu Net Disk
- 🎛 Up to 10 tasks concurrently download
- 🚀 Single task maximum support 64 thread download
- 🦄 Supports BitTorrent & Magnet
- 💾 Supports downloading Baidu Net Disk
- 🎛 Up to 10 concurrent download tasks
- 🚀 Supports 64 threads in a single task
- 🕶 Mock User-Agent
- 🔔 Download completed Notification
- 💻 Ready for Touch Bar (Mac only)
- 🗑 Delete related files when removing tasks (optional)
- 🌍 I18n, currently available Simplified Chinese & English.
- 🌍 I18n, [View supported languages](#-internationalization).
- 🎏 ...
## 🖥 User Interface
![motrix-screenshot-task-en.png](https://cdn.nlark.com/yuque/0/2019/png/129147/1548251350313-73aa0d60-ee31-4405-bdb9-1793e3fd46ef.png)
![motrix-screenshot-task-en.png](https://cdn.nlark.com/yuque/0/2019/png/129147/1550151166169-94b4bfb0-746e-42b8-aad7-0b6890f89abb.png)
## ⌨️ Development
@@ -57,7 +63,7 @@ npm run dev
```bash
npm run build
```
After build finish, you can see the compiled packaged application file in the `release` directory of the project.
After building, the application will be found in the project's `release` directory.
## 🛠 Technology Stack
- [Electron](https://electronjs.org/)
@@ -68,7 +74,20 @@ After build finish, you can see the compiled packaged application file in the `r
Development Roadmap see: [Trello](https://trello.com/b/qNUzA0bv/motrix)
## 🤝 Contribute [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
If you are interested in participating in joint development, Fork and PR are welcome.
If you are interested in participating in joint development, PR and Forks are welcome!
## 🌍 Internationalization
Translations into versions for other languages are welcome 🧐! Please read the [translation guide](./CONTRIBUTING.md#-translation-guide) before starting translations.
| Key | Name | Status |
|-------|:--------------------|:-------------|
| de | German | Next Release [@Schloemicher](https://github.com/Schloemicher) |
| en-US | English | ✔️ |
| fr | Français | Next Release [@gpatarin](https://github.com/gpatarin) |
| pt-BR | Portuguese (Brazil) | Next Release [@andrenoberto](https://github.com/andrenoberto) |
| tr | Türkçe | Next Release [@abdullah](https://github.com/abdullah) |
| zh-CN | 简体中文 | ✔️ |
| zh-TW | 繁體中文 | Next Release [@Yukaii](https://github.com/Yukaii) |
## 📜 License
[MIT](https://opensource.org/licenses/MIT) Copyright (c) 2018-present Dr_rOot
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

+1 -1
View File
@@ -33,7 +33,7 @@
# 单个任务下载速度限制, 默认:0
#@max-download-limit=0
# 整体上传速度限制, 运行时可修改, 默认:0
#@max-overall-upload-limit=0
max-overall-upload-limit=128K
# 单个任务上传速度限制, 默认:0
#@max-upload-limit=0
# 禁用IPv6, 默认:false
+1 -1
View File
@@ -33,7 +33,7 @@ file-allocation=trunc
# 单个任务下载速度限制, 默认:0
#@max-download-limit=0
# 整体上传速度限制, 运行时可修改, 默认:0
#@max-overall-upload-limit=0
max-overall-upload-limit=128K
# 单个任务上传速度限制, 默认:0
#@max-upload-limit=0
# 禁用IPv6, 默认:false
+1 -1
View File
@@ -33,7 +33,7 @@ file-allocation=falloc
# 单个任务下载速度限制, 默认:0
#@max-download-limit=0
# 整体上传速度限制, 运行时可修改, 默认:0
#@max-overall-upload-limit=0
max-overall-upload-limit=128K
# 单个任务上传速度限制, 默认:0
#@max-upload-limit=0
# 禁用IPv6, 默认:false
+3250 -976
View File
File diff suppressed because it is too large Load Diff
+56 -27
View File
@@ -1,6 +1,6 @@
{
"name": "Motrix",
"version": "1.1.0",
"version": "1.2.2",
"description": "A full-featured download manager",
"homepage": "https://motrix.app",
"author": {
@@ -32,6 +32,14 @@
"build": {
"productName": "Motrix",
"appId": "net.agalwood.Motrix",
"fileAssociations": [
{
"ext": "torrent",
"mimeType": "application/x-bittorrent",
"name": "Torrent",
"role": "Viewer"
}
],
"asar": true,
"directories": {
"output": "release"
@@ -88,9 +96,27 @@
},
"win": {
"target": [
"nsis",
"zip",
"portable"
{
"target": "nsis",
"arch": [
"x64",
"ia32"
]
},
{
"target": "zip",
"arch": [
"x64",
"ia32"
]
},
{
"target": "portable",
"arch": [
"x64",
"ia32"
]
}
],
"extraResources": {
"from": "./extra/win32/",
@@ -105,8 +131,10 @@
"allowToChangeInstallationDirectory": true
},
"linux": {
"category": "Network",
"target": [
"deb",
"snap",
"AppImage"
],
"extraResources": {
@@ -131,30 +159,31 @@
"@panter/vue-i18next": "^0.15.0",
"aria2": "^4.0.3",
"axios": "^0.18.0",
"blob-util": "^2.0.2",
"clipboard-polyfill": "^2.7.0",
"electron-debug": "^2.1.0",
"electron-is": "^3.0.0",
"electron-log": "^2.2.17",
"electron-updater": "^4.0.7",
"element-ui": "^2.5.4",
"electron-updater": "^4.0.8",
"element-ui": "^2.6.2",
"forever-monitor": "^1.7.1",
"i18next": "^15.0.0",
"i18next": "^15.0.6",
"lodash": "^4.17.11",
"normalize.css": "^8.0.1",
"parse-torrent": "^6.1.2",
"svg-innerhtml": "^1.1.0",
"vue": "^2.6.4",
"vue": "^2.6.10",
"vue-electron": "^1.0.6",
"vue-router": "^3.0.2",
"vuex": "^3.1.0",
"vuex-router-sync": "^5.0.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.4.0",
"@vue/cli-plugin-eslint": "^3.4.0",
"@vue/cli-service": "^3.4.0",
"@vue/cli-plugin-babel": "^3.5.1",
"@vue/cli-plugin-eslint": "^3.5.1",
"@vue/cli-service": "^3.5.1",
"@vue/eslint-config-standard": "^4.0.0",
"ajv": "^6.9.1",
"ajv": "^6.10.0",
"babel-core": "^6.26.3",
"babel-eslint": "^10.0.1",
"babel-loader": "^7.1.4",
@@ -165,28 +194,29 @@
"babel-register": "^6.26.0",
"babili-webpack-plugin": "^0.1.2",
"cfonts": "^2.4.2",
"chalk": "^2.4.1",
"copy-webpack-plugin": "^4.6.0",
"chalk": "^2.4.2",
"copy-webpack-plugin": "^5.0.1",
"cross-env": "^5.1.6",
"css-loader": "^1.0.1",
"del": "^3.0.0",
"css-loader": "^2.1.1",
"del": "^4.0.0",
"devtron": "^1.4.0",
"electron": "^4.0.4",
"electron": "^4.1.1",
"electron-builder": "^20.38.5",
"electron-devtools-installer": "^2.2.4",
"electron-notarize": "^0.0.5",
"electron-osx-sign": "^0.4.11",
"electron-store": "^2.0.0",
"eslint": "^5.13.0",
"eslint": "^5.15.3",
"eslint-config-standard": "^12.0.0",
"eslint-friendly-formatter": "^4.0.1",
"eslint-loader": "^2.1.2",
"eslint-plugin-html": "^4.0.6",
"eslint-plugin-import": "^2.16.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-node": "^8.0.1",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^5.1.0",
"file-loader": "^2.0.0",
"eslint-plugin-vue": "^5.2.2",
"file-loader": "^3.0.1",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "0.5.0",
"multispinner": "^0.2.1",
@@ -196,15 +226,14 @@
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"url-loader": "^1.1.2",
"eslint-plugin-html": "^4.0.6",
"vue-html-loader": "^1.2.4",
"vue-loader": "^15.6.2",
"vue-loader": "^15.7.0",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.4",
"webpack": "^4.29.3",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.29.6",
"webpack-cli": "^3.2.3",
"webpack-dev-server": "^3.1.14",
"webpack-dev-server": "^3.2.1",
"webpack-hot-middleware": "^2.24.3",
"webpack-merge": "^4.1.4"
"webpack-merge": "^4.2.1"
}
}
+99 -12
View File
@@ -1,9 +1,12 @@
import { EventEmitter } from 'events'
import { app, shell, dialog, ipcMain } from 'electron'
import is from 'electron-is'
import { readFile } from 'fs'
import { extname, basename } from 'path'
import logger from './core/Logger'
import ExceptionHandler from './core/ExceptionHandler'
import ConfigManager from './core/ConfigManager'
import { setupLocaleManager } from '@/ui/Locale'
import Engine from './core/Engine'
import UpdateManager from './core/UpdateManager'
import EnergyManager from './core/EnergyManager'
@@ -11,19 +14,21 @@ import ProtocolManager from './core/ProtocolManager'
import WindowManager from './ui/WindowManager'
import MenuManager from './ui/MenuManager'
import TouchBarManager from './ui/TouchBarManager'
import TrayManager from './ui/TrayManager'
export default class Application extends EventEmitter {
constructor () {
super()
this.exceptionHandler = new ExceptionHandler()
this.isReady = false
this.init()
}
init () {
this.configManager = new ConfigManager()
this.locale = this.configManager.getLocale()
this.localeManager = setupLocaleManager(this.locale)
this.i18n = this.localeManager.getI18n()
this.windowManager = new WindowManager({
userConfig: this.configManager.getUserConfig()
@@ -40,6 +45,8 @@ export default class Application extends EventEmitter {
this.touchBarManager = new TouchBarManager()
this.trayManager = new TrayManager()
this.energyManager = new EnergyManager()
this.initUpdaterManager()
@@ -54,12 +61,11 @@ export default class Application extends EventEmitter {
try {
this.engine.start()
} catch (err) {
const { message } = err
dialog.showMessageBox({
type: 'error',
title: '系统错误',
message: `应用启动失败:${err.message}`,
buttons: ['知道了'],
cancelId: 1
title: this.i18n.t('app.system-error-title'),
message: this.i18n.t('app.system-error-message', { message })
}, () => {
setTimeout(() => {
app.quit()
@@ -74,9 +80,29 @@ export default class Application extends EventEmitter {
showPage (page) {
const win = this.windowManager.openWindow(page)
win.once('ready-to-show', () => {
this.isReady = true
this.emit('ready')
})
this.touchBarManager.setup(page, win)
}
show (page = 'index') {
this.windowManager.showWindow(page)
}
hide (page) {
if (page) {
this.windowManager.hideWindow(page)
} else {
this.windowManager.hideAllWindow()
}
}
toggle (page = 'index') {
this.windowManager.toggleWindow(page)
}
closePage (page) {
this.windowManager.destroyWindow(page)
}
@@ -120,8 +146,33 @@ export default class Application extends EventEmitter {
if (is.dev() || is.mas()) {
return
}
this.show()
this.protocolManager.handle(url)
this.showPage('index')
}
handleFile (filePath) {
if (!filePath) {
return
}
if (extname(filePath).toLowerCase() !== '.torrent') {
return
}
this.show()
const fileName = basename(filePath)
readFile(filePath, (err, data) => {
if (err) {
logger.warn(`[Motrix] read file error: ${filePath}`, err.message)
return
}
const file = Buffer.from(data).toString('base64')
const args = [fileName, file]
this.sendCommandToAll('application:new-bt-task-with-file', ...args)
})
}
initUpdaterManager () {
@@ -184,8 +235,12 @@ export default class Application extends EventEmitter {
app.exit()
})
this.on('application:show', (page = 'index') => {
this.showPage(page)
this.on('application:show', (page) => {
this.show(page)
})
this.on('application:hide', (page) => {
this.hide(page)
})
this.on('application:reset', () => {
@@ -198,7 +253,35 @@ export default class Application extends EventEmitter {
})
this.on('application:change-locale', (locale) => {
this.menuManager.setup(locale)
logger.info('[Motrix] application:change-locale===>', locale)
this.localeManager.changeLanguageByLocale(locale)
.then(() => {
this.menuManager.setup(locale)
this.trayManager.setup(locale)
})
})
this.on('application:open-file', (event) => {
dialog.showOpenDialog({
properties: ['openFile'],
filters: [
{
name: 'Torrent',
extensions: ['torrent']
}
]
}, (filePaths) => {
if (!filePaths || filePaths.length === 0) {
return
}
const [filePath] = filePaths
this.handleFile(filePath)
})
})
this.on('application:clear-recent-tasks', () => {
app.clearRecentDocuments()
})
this.on('help:official-website', () => {
@@ -231,5 +314,9 @@ export default class Application extends EventEmitter {
ipcMain.on('update-menu-states', (event, visibleStates, enabledStates, checkedStates) => {
this.menuManager.updateStates(visibleStates, enabledStates, checkedStates)
})
ipcMain.on('download-status-change', (event, status) => {
this.trayManager.updateStatus(status)
})
}
}
+140
View File
@@ -0,0 +1,140 @@
import { EventEmitter } from 'events'
import { app } from 'electron'
import is from 'electron-is'
import ExceptionHandler from './core/ExceptionHandler'
import logger from './core/Logger'
import Application from './Application'
import { parseArgv } from './utils'
const EMPTY_STRING = ''
export default class Launcher extends EventEmitter {
constructor () {
super()
this.url = EMPTY_STRING
this.file = EMPTY_STRING
this.makeSingleInstance(() => {
this.init()
})
}
makeSingleInstance (callback) {
// Mac App Store Sandboxed App not support requestSingleInstanceLock
if (is.mas()) {
callback()
return
}
const gotSingleLock = app.requestSingleInstanceLock()
if (!gotSingleLock) {
app.quit()
} else {
app.on('second-instance', (event, argv, workingDirectory) => {
global.application.showPage('index')
if (!is.macOS() && argv.length > 1) { // Windows, Linux
this.file = parseArgv(argv)
this.sendFileToApplication()
}
})
callback()
}
}
init () {
this.exceptionHandler = new ExceptionHandler()
this.handleAppEvents()
}
handleAppEvents () {
this.handleOpenUrl()
this.handleOpenFile()
this.handelAppReady()
this.handleAppWillQuit()
}
/**
* handleOpenUrl
* "name": "Motrix Protocol",
* "schemes": ["mo", "motrix"]
*/
handleOpenUrl () {
if (is.mas()) {
return
}
app.on('open-url', (event, url) => {
logger.info(`[Motrix] open-url path: ${url}`)
event.preventDefault()
this.url = url
if (this.url && global.application && global.application.isReady) {
global.application.handleProtocol(this.url)
this.url = EMPTY_STRING
}
})
}
/**
* handleOpenFile [WIP]
* handle open torrent file
*/
handleOpenFile () {
// macOS
if (is.macOS()) {
app.on('open-file', (event, path) => {
logger.info(`[Motrix] open-file path: ${path}`)
event.preventDefault()
this.file = path
this.sendFileToApplication()
})
} else if (process.argv.length > 1) { // Windows, Linux
this.file = parseArgv(process.argv)
this.sendFileToApplication()
}
}
sendFileToApplication () {
if (this.file && global.application && global.application.isReady) {
global.application.handleFile(this.file)
this.file = EMPTY_STRING
}
}
handelAppReady () {
app.on('ready', () => {
global.application = new Application()
global.application.start('index')
global.application.on('ready', () => {
if (this.url) {
global.application.handleProtocol(this.url)
}
if (this.file) {
global.application.handleFile(this.file)
}
})
})
app.on('activate', () => {
if (global.application) {
logger.info('[Motrix] activate')
global.application.showPage('index')
}
})
}
handleAppWillQuit () {
app.on('will-quit', () => {
logger.info('[Motrix] will-quit')
if (global.application) {
global.application.stop()
}
})
}
}
-12
View File
@@ -13,17 +13,5 @@ export default {
},
bindCloseToHide: true,
url: is.dev() ? `http://localhost:9080` : `file://${__dirname}/index.html`
},
about: {
attrs: {
title: '关于',
width: 580,
height: 320,
backgroundColor: '#FFFFFF',
resizable: false,
minimizable: false,
maximizable: false
},
url: is.dev() ? `http://localhost:9080/about` : `file://${__dirname}/about.html`
}
}
+5 -1
View File
@@ -20,6 +20,10 @@ export default class ConfigManager {
this.initUserConfig()
}
/**
* some aria2 conf
* https://aria2.github.io/manual/en/html/aria2c.html
*/
initSystemConfig () {
this.systemConfig = new Store({
name: 'system',
@@ -52,7 +56,7 @@ export default class ConfigManager {
defaults: {
'resume-all-when-app-launched': false,
'task-notification': true,
'hide-app-menu': false,
'hide-app-menu': is.windows() || is.linux(),
'new-task-show-downloading': true,
'auto-check-for-updates': false,
'update-channel': 'latest',
+27 -8
View File
@@ -6,6 +6,7 @@ import { existsSync } from 'fs'
import { resolve, join } from 'path'
import forever from 'forever-monitor'
import logger from './Logger'
import { getI18n } from '@/ui/Locale'
import {
getEngineBin,
getSessionPath,
@@ -16,6 +17,9 @@ export default class Engine {
static instance = null
constructor (options = {}) {
this.options = options
this.i18n = getI18n()
this.systemConfig = options.systemConfig
this.userConfig = options.userConfig
}
@@ -30,14 +34,14 @@ export default class Engine {
const binName = getEngineBin(platform)
if (!binName) {
throw new Error('引擎已损坏,请重新安装: (')
throw new Error(this.i18n.t('app.engine-damaged-message'))
}
let binPath = join(basePath, `/engine/${binName}`)
const binIsExist = existsSync(binPath)
if (!binIsExist) {
logger.error('[Motrix] engine bin is not exist===>', binPath)
throw new Error('引擎文件缺失,请重新安装: (')
throw new Error(this.i18n.t('app.engine-missing-message'))
}
let confPath = join(basePath, '/engine/aria2.conf')
@@ -60,7 +64,7 @@ export default class Engine {
const sh = this.getStartSh()
logger.info('[Motrix] Engine start sh===>', sh)
this.instance = forever.start(sh, {
max: 3,
max: 10,
parser: function (command, args) {
return {
command: command,
@@ -73,13 +77,29 @@ export default class Engine {
const { child } = this.instance
logger.info('[Motrix] Engine pid===>', child.pid)
this.instance.on('exit:code', function (code) {
logger.info(`[Motrix] Engine has exited after 3 restarts===> ${code}`)
this.instance.on('error', (err) => {
logger.info(`[Motrix] Engine error===> ${err}`)
})
this.instance.on('error', (err) => {
logger.info(`[Motrix] Engine has exited after 3 restarts===> ${err}`)
this.instance.on('start', function (process, data) {
logger.info(`[Motrix] Engine started===>`)
})
this.instance.on('stop', function (process) {
logger.info(`[Motrix] Engine stopped===>`)
})
this.instance.on('restart', function (forever) {
logger.info(`[Motrix] Engine exit===>`)
})
this.instance.on('exit:code', function (code) {
logger.info(`[Motrix] Engine exit===> ${code}`)
})
// this.instance.on('stderr', (data) => {
// logger.info(`[Motrix] Engine stderr===> ${data}`)
// })
}
stop () {
@@ -87,7 +107,6 @@ export default class Engine {
try {
logger.info('[Motrix] Engine stopping===>')
this.instance.stop()
logger.info('[Motrix] Engine stopped===>', pid)
} catch (err) {
logger.error('[Motrix] Engine stop fail===>', err.message)
this.forceStop(pid)
+1
View File
@@ -3,5 +3,6 @@ import logger from 'electron-log'
logger.transports.file.level = is.production() ? 'warn' : 'info'
logger.info('Logger init')
logger.warn('[Motrix] Logger init')
export default logger
+1 -1
View File
@@ -37,6 +37,6 @@ export default class ProtocolManager extends EventEmitter {
// 如果按顺序传递,那 url 的 query string 就要求有序的了
// const query = queryString.parse(parsed.query)
const args = []
global.application.sendCommand(command, ...args)
global.application.sendCommandToAll(command, ...args)
}
}
+12 -10
View File
@@ -4,6 +4,7 @@ import is from 'electron-is'
import { autoUpdater } from 'electron-updater'
import { resolve } from 'path'
import logger from './Logger'
import { getI18n } from '@/ui/Locale'
if (is.dev()) {
autoUpdater.updateConfigPath = resolve(__dirname, '../../../app-update.yml')
@@ -13,6 +14,7 @@ export default class UpdateManager extends EventEmitter {
constructor (options = {}) {
super()
this.options = options
this.i18n = getI18n()
this.updater = autoUpdater
this.updater.autoDownload = false
@@ -48,9 +50,9 @@ export default class UpdateManager extends EventEmitter {
this.emit('update-available', info)
dialog.showMessageBox({
type: 'info',
title: '发现新版本',
message: '发现新版本,是否现在更新?',
buttons: ['是', '否'],
title: this.i18n.t('app.check-for-updates-title'),
message: this.i18n.t('app.update-available-message'),
buttons: [this.i18n.t('app.yes'), this.i18n.t('app.no')],
cancelId: 1
}, (buttonIndex) => {
if (buttonIndex === 0) {
@@ -62,8 +64,8 @@ export default class UpdateManager extends EventEmitter {
updateNotAvailable (event, info) {
this.emit('update-not-available', info)
dialog.showMessageBox({
title: '没有更新的版本',
message: '您目前使用的已是最新版本'
title: this.i18n.t('app.check-for-updates-title'),
message: this.i18n.t('app.update-not-available-message')
})
}
@@ -84,8 +86,8 @@ export default class UpdateManager extends EventEmitter {
this.emit('update-downloaded', info)
this.updater.logger.log(`Update Downloaded: ${info}`)
dialog.showMessageBox({
title: '安装更新',
message: '更新下载完成,应用程序将退出并开始更新...'
title: this.i18n.t('app.check-for-updates-title'),
message: this.i18n.t('app.update-downloaded-message')
}, () => {
this.emit('will-updated')
setImmediate(() => {
@@ -96,8 +98,8 @@ export default class UpdateManager extends EventEmitter {
updateError (event, error) {
this.emit('update-error', error)
const msg = error == null ? '未知错误' : (error.stack || error).toString()
this.updater.logger.warn(`Update Error: ${msg}`)
dialog.showErrorBox('错误: ', msg)
const msg = error == null ? this.i18n.t('update-error-message') : (error.stack || error).toString()
this.updater.logger.warn(`[Motrix] update-error: ${msg}`)
dialog.showErrorBox(msg)
}
}
+3 -63
View File
@@ -1,8 +1,7 @@
import { app } from 'electron'
import is from 'electron-is'
import logger from './core/Logger'
import Application from './Application'
import Launcher from './Launcher'
if (process.env.NODE_ENV !== 'development') {
global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
@@ -12,67 +11,8 @@ if (process.env.NODE_ENV !== 'development') {
* Fix Windows notification func
* appId defined in .electron-vue/webpack.main.config.js
*/
if (process.platform === 'win32') {
if (is.windows()) {
app.setAppUserModelId(appId)
}
function _init () {
let openURL = null
if (!is.mas()) {
app.on('open-url', (event, url) => {
logger.info(`You arrived from: ${url}`)
event.preventDefault()
openURL = url
if (global.application) {
global.application.handleProtocol(openURL)
}
})
}
app.on('ready', () => {
global.application = new Application()
global.application.start('index')
if (openURL) {
global.application.handleProtocol(openURL)
}
})
app.on('will-quit', () => {
logger.warn('will-quit')
global.application && global.application.stop()
})
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it's common NOT to close app even if all windows are closed
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
global.application.showPage('index')
})
}
function init () {
// Mac App Store Sandboxed App Not support requestSingleInstanceLock
if (is.mas()) {
_init()
} else {
const gotSingleLock = app.requestSingleInstanceLock()
if (!gotSingleLock) {
app.quit()
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
global.application.showPage('index')
})
_init()
}
}
}
init()
global.launcher = new Launcher()
+76
View File
@@ -0,0 +1,76 @@
{
"menu": [
{
"id": "menu.app",
"submenu": [
{ "id": "app.about", "command": "application:about", "command-before": "application:show,index" },
{ "type": "separator" },
{ "id": "app.preferences", "command": "application:preferences" },
{ "id": "app.check-for-updates", "command": "application:check-for-updates" },
{ "id": "app.hide", "role": "hide" },
{ "id": "app.hide-others", "role": "hideothers" },
{ "id": "app.unhide", "role": "unhide" },
{ "type": "separator" },
{ "id": "app.quit", "role": "quit" }
]
},
{
"id": "menu.task",
"submenu": [
{ "id": "task.new-task", "command": "application:new-task", "command-after": "application:show,index" },
{ "id": "task.new-bt-task", "command": "application:new-bt-task", "command-arg": "torrent", "command-after": "application:show,index" },
{ "id": "task.open-file", "command": "application:open-file", "command-before": "application:show,index" },
{ "type": "separator" },
{ "id": "task.pause-task", "command": "application:pause-task" },
{ "id": "task.resume-task", "command": "application:resume-task" },
{ "id": "task.delete-task", "command": "application:delete-task" },
{ "id": "task.move-task-up", "command": "application:move-task-up" },
{ "id": "task.move-task-down", "command": "application:move-task-down" },
{ "type": "separator" },
{ "id": "task.pause-all-task", "command": "application:pause-all-task" },
{ "id": "task.resume-all-task", "command": "application:resume-all-task" },
{ "type": "separator" },
{ "id": "task.clear-recent-tasks", "command": "application:clear-recent-tasks" }
]
},
{
"id": "menu.edit",
"submenu": [
{ "id": "edit.undo", "role": "undo" },
{ "id": "edit.redo", "role": "redo" },
{ "type": "separator" },
{ "id": "edit.cut", "role": "cut" },
{ "id": "edit.copy", "role": "copy" },
{ "id": "edit.paste", "role": "paste" },
{ "id": "edit.delete", "role": "delete" },
{ "id": "edit.select-all", "role": "selectall" }
]
},
{
"role": "window",
"id": "menu.window",
"submenu": [
{ "id": "window.reload", "role": "reload" },
{ "id": "window.close", "role": "close" },
{ "id": "window.minimize", "role": "minimize" },
{ "id": "window.zoom", "role": "zoom" },
{ "id": "window.toggle-fullscreen", "role": "togglefullscreen" },
{ "type": "separator" },
{ "id": "window.front", "role": "front" }
]
},
{
"role": "help",
"id": "menu.help",
"submenu": [
{ "id": "help.official-website", "command": "help:official-website" },
{ "id": "help.manual", "command": "help:manual" },
{ "id": "help.release-notes", "command": "help:release-notes" },
{ "type": "separator" },
{ "id": "help.report-problem", "command": "help:report-problem" },
{ "type": "separator" },
{ "id": "help.toggle-dev-tools", "role": "toggledevtools" }
]
}
]
}
-80
View File
@@ -1,80 +0,0 @@
{
"menu": [
{
"label": "Motrix",
"id": "menu.app",
"submenu": [
{ "label": "About Motrix", "id": "app.about", "command": "application:about", "command-before": "application:show,index"},
{ "type": "separator" },
{ "label": "Preferences...", "id": "app.preferences", "command": "application:preferences", "command-before": "application:show,index"},
{ "label": "Check for Updates...", "id": "app.check-for-updates", "command": "application:check-for-updates" },
{ "label": "Hide Motrix", "id": "app.hide", "role": "hide" },
{ "label": "Hide Others", "id": "app.hide-others", "role": "hideothers" },
{ "label": "Show All", "id": "app.unhide", "role": "unhide" },
{ "type": "separator" },
{ "label": "Quit Motrix", "id": "app.quit", "role": "quit" }
]
},
{
"label": "Task",
"id": "menu.task",
"submenu": [
{ "label": "New Task", "id": "task.new-task", "command": "application:new-task", "command-arg": "uri", "command-after": "application:show,index"},
{ "label": "New BT Task", "id": "task.new-bt-task", "command": "application:new-bt-task", "command-arg": "torrent", "command-after": "application:show,index"},
{ "type": "separator" },
{ "label": "Pause Task", "id": "task.pause-task", "command": "application:pause-task" },
{ "label": "Resume Task", "id": "task.resume-task", "command": "application:resume-task" },
{ "label": "Delete Task", "id": "task.delete-task", "command": "application:delete-task" },
{ "label": "Move Task Up", "id": "task.move-task-up", "command": "application:move-task-up" },
{ "label": "Move Task Down", "id": "task.move-task-down", "command": "application:move-task-down" },
{ "type": "separator" },
{ "label": "Pause All Task", "id": "task.pause-all-task", "command": "application:pause-all-task" },
{ "label": "Resume All Task", "id": "task.resume-all-task", "command": "application:resume-all-task" },
{ "type": "separator" },
{ "label": "Clear Recent Tasks", "id": "task.clear-recent-tasks", "command": "application:clear-recent-tasks" }
]
},
{
"label": "Edit",
"id": "menu.edit",
"submenu": [
{ "label": "Undo", "id": "edit.undo", "role": "undo" },
{ "label": "Redo", "id": "edit.redo", "role": "redo" },
{ "type": "separator" },
{ "label": "Cut", "id": "edit.cut", "role": "cut" },
{ "label": "Copy", "id": "edit.copy", "role": "copy" },
{ "label": "Paste", "id": "edit.paste", "role": "paste" },
{ "label": "Delete", "id": "edit.delete", "role": "delete" },
{ "label": "Select All", "id": "edit.select-all", "role": "selectall" }
]
},
{
"label": "Window",
"role": "window",
"id": "menu.window",
"submenu": [
{ "label": "Reload", "id": "window.reload", "role": "reload" },
{ "label": "Close", "id": "window.close", "role": "close" },
{ "label": "Minimize", "id": "window.minimize", "role": "minimize" },
{ "label": "Zoom", "id": "window.zoom", "role": "zoom" },
{ "label": "Enter Full Screen", "id": "window.toggle-fullscreen", "role": "togglefullscreen" },
{ "type": "separator" },
{ "label": "Bring All to Front", "id": "window.front", "role": "front" }
]
},
{
"label": "Help",
"role": "help",
"id": "menu.help",
"submenu": [
{ "label": "Motrix Website", "id": "help.official-website", "command": "help:official-website" },
{ "label": "Manual", "id": "help.manual", "command": "help:manual" },
{ "label": "Release Notes...", "id": "help.release-notes", "command": "help:release-notes" },
{ "type": "separator" },
{ "label": "Report Problem", "id": "help.report-problem", "command": "help:report-problem" },
{ "type": "separator" },
{ "label": "Toggle Developer Tools", "id": "help.toggle-dev-tools", "role": "toggledevtools" }
]
}
]
}
-80
View File
@@ -1,80 +0,0 @@
{
"menu": [
{
"label": "File",
"id": "menu.file",
"submenu": [
{ "label": "About Motrix", "id": "app.about", "command": "application:about", "command-before": "application:show,index"},
{ "type": "separator" },
{ "label": "Preferences...", "id": "app.preferences", "command": "application:preferences", "command-before": "application:show,index"},
{ "label": "Check for Updates...", "id": "app.check-for-updates", "command": "application:check-for-updates" },
{ "label": "Hide Motrix", "id": "app.hide", "role": "hide" },
{ "label": "Hide Others", "id": "app.hide-others", "role": "hideothers" },
{ "label": "Show All", "id": "app.unhide", "role": "unhide" },
{ "type": "separator" },
{ "label": "Quit Motrix", "id": "app.quit", "role": "quit" }
]
},
{
"label": "Task",
"id": "menu.task",
"submenu": [
{ "label": "New Task", "id": "task.new-task", "command": "application:new-task", "command-arg": "uri", "command-after": "application:show,index"},
{ "label": "New BT Task", "id": "task.new-bt-task", "command": "application:new-bt-task", "command-arg": "torrent", "command-after": "application:show,index"},
{ "type": "separator" },
{ "label": "Pause Task", "id": "task.pause-task", "command": "application:pause-task" },
{ "label": "Resume Task", "id": "task.resume-task", "command": "application:resume-task" },
{ "label": "Delete Task", "id": "task.delete-task", "command": "application:delete-task" },
{ "label": "Move Task Up", "id": "task.move-task-up", "command": "application:move-task-up" },
{ "label": "Move Task Down", "id": "task.move-task-down", "command": "application:move-task-down" },
{ "type": "separator" },
{ "label": "Pause All Task", "id": "task.pause-all-task", "command": "application:pause-all-task" },
{ "label": "Resume All Task", "id": "task.resume-all-task", "command": "application:resume-all-task" },
{ "type": "separator" },
{ "label": "Clear Recent Tasks", "id": "task.clear-recent-tasks", "command": "application:clear-recent-tasks" }
]
},
{
"label": "Edit",
"id": "menu.edit",
"submenu": [
{ "label": "Undo", "id": "edit.undo", "role": "undo" },
{ "label": "Redo", "id": "edit.redo", "role": "redo" },
{ "type": "separator" },
{ "label": "Cut", "id": "edit.cut", "role": "cut" },
{ "label": "Copy", "id": "edit.copy", "role": "copy" },
{ "label": "Paste", "id": "edit.paste", "role": "paste" },
{ "label": "Delete", "id": "edit.delete", "role": "delete" },
{ "label": "Select All", "id": "edit.select-all", "role": "selectall" }
]
},
{
"label": "Window",
"role": "window",
"id": "menu.window",
"submenu": [
{ "label": "Reload", "id": "window.reload", "role": "reload" },
{ "label": "Close", "id": "window.close", "role": "close" },
{ "label": "Minimize", "id": "window.minimize", "role": "minimize" },
{ "label": "Zoom", "id": "window.zoom", "role": "zoom" },
{ "label": "Enter Full Screen", "id": "window.toggle-fullscreen", "role": "togglefullscreen" },
{ "type": "separator" },
{ "label": "Bring All to Front", "id": "window.front", "role": "front" }
]
},
{
"label": "Help",
"role": "help",
"id": "menu.help",
"submenu": [
{ "label": "Motrix Website", "id": "help.official-website", "command": "help:official-website" },
{ "label": "Manual", "id": "help.manual", "command": "help:manual" },
{ "label": "Release Notes...", "id": "help.release-notes", "command": "help:release-notes" },
{ "type": "separator" },
{ "label": "Report Problem", "id": "help.report-problem", "command": "help:report-problem" },
{ "type": "separator" },
{ "label": "Toggle Developer Tools", "id": "help.toggle-dev-tools", "role": "toggledevtools" }
]
}
]
}
-80
View File
@@ -1,80 +0,0 @@
{
"menu": [
{
"label": "File",
"id": "menu.file",
"submenu": [
{ "label": "About Motrix", "id": "app.about", "command": "application:about", "command-before": "application:show,index"},
{ "type": "separator" },
{ "label": "Preferences...", "id": "app.preferences", "command": "application:preferences", "command-before": "application:show,index"},
{ "label": "Check for Updates...", "id": "app.check-for-updates", "command": "application:check-for-updates" },
{ "label": "Hide Motrix", "id": "app.hide", "role": "hide" },
{ "label": "Hide Others", "id": "app.hide-others", "role": "hideothers" },
{ "label": "Show All", "id": "app.unhide", "role": "unhide" },
{ "type": "separator" },
{ "label": "Quit Motrix", "id": "app.quit", "role": "quit" }
]
},
{
"label": "Task",
"id": "menu.task",
"submenu": [
{ "label": "New Task", "id": "task.new-task", "command": "application:new-task", "command-arg": "uri", "command-after": "application:show,index"},
{ "label": "New BT Task", "id": "task.new-bt-task", "command": "application:new-bt-task", "command-arg": "torrent", "command-after": "application:show,index"},
{ "type": "separator" },
{ "label": "Pause Task", "id": "task.pause-task", "command": "application:pause-task" },
{ "label": "Resume Task", "id": "task.resume-task", "command": "application:resume-task" },
{ "label": "Delete Task", "id": "task.delete-task", "command": "application:delete-task" },
{ "label": "Move Task Up", "id": "task.move-task-up", "command": "application:move-task-up" },
{ "label": "Move Task Down", "id": "task.move-task-down", "command": "application:move-task-down" },
{ "type": "separator" },
{ "label": "Pause All Task", "id": "task.pause-all-task", "command": "application:pause-all-task" },
{ "label": "Resume All Task", "id": "task.resume-all-task", "command": "application:resume-all-task" },
{ "type": "separator" },
{ "label": "Clear Recent Tasks", "id": "task.clear-recent-tasks", "command": "application:clear-recent-tasks" }
]
},
{
"label": "Edit",
"id": "menu.edit",
"submenu": [
{ "label": "Undo", "id": "edit.undo", "role": "undo" },
{ "label": "Redo", "id": "edit.redo", "role": "redo" },
{ "type": "separator" },
{ "label": "Cut", "id": "edit.cut", "role": "cut" },
{ "label": "Copy", "id": "edit.copy", "role": "copy" },
{ "label": "Paste", "id": "edit.paste", "role": "paste" },
{ "label": "Delete", "id": "edit.delete", "role": "delete" },
{ "label": "Select All", "id": "edit.select-all", "role": "selectall" }
]
},
{
"label": "Window",
"role": "window",
"id": "menu.window",
"submenu": [
{ "label": "Reload", "id": "window.reload", "role": "reload" },
{ "label": "Close", "id": "window.close", "role": "close" },
{ "label": "Minimize", "id": "window.minimize", "role": "minimize" },
{ "label": "Zoom", "id": "window.zoom", "role": "zoom" },
{ "label": "Enter Full Screen", "id": "window.toggle-fullscreen", "role": "togglefullscreen" },
{ "type": "separator" },
{ "label": "Bring All to Front", "id": "window.front", "role": "front" }
]
},
{
"label": "Help",
"role": "help",
"id": "menu.help",
"submenu": [
{ "label": "Motrix Website", "id": "help.official-website", "command": "help:official-website" },
{ "label": "Manual", "id": "help.manual", "command": "help:manual" },
{ "label": "Release Notes...", "id": "help.release-notes", "command": "help:release-notes" },
{ "type": "separator" },
{ "label": "Report Problem", "id": "help.report-problem", "command": "help:report-problem" },
{ "type": "separator" },
{ "label": "Toggle Developer Tools", "id": "help.toggle-dev-tools", "role": "toggledevtools" }
]
}
]
}
+72
View File
@@ -0,0 +1,72 @@
{
"menu": [
{
"id": "menu.file",
"submenu": [
{ "id": "app.about", "command": "application:about", "command-before": "application:show,index" },
{ "type": "separator" },
{ "id": "app.preferences", "command": "application:preferences" },
{ "id": "app.check-for-updates", "command": "application:check-for-updates" },
{ "id": "app.show", "command": "application:show", "command-arg": "index" },
{ "type": "separator" },
{ "id": "app.quit", "role": "quit" }
]
},
{
"id": "menu.task",
"submenu": [
{ "id": "task.new-task", "command": "application:new-task", "command-after": "application:show,index" },
{ "id": "task.new-bt-task", "command": "application:new-bt-task", "command-arg": "torrent", "command-after": "application:show,index" },
{ "id": "task.open-file", "command": "application:open-file", "command-before": "application:show,index" },
{ "type": "separator" },
{ "id": "task.pause-task", "command": "application:pause-task" },
{ "id": "task.resume-task", "command": "application:resume-task" },
{ "id": "task.delete-task", "command": "application:delete-task" },
{ "id": "task.move-task-up", "command": "application:move-task-up" },
{ "id": "task.move-task-down", "command": "application:move-task-down" },
{ "type": "separator" },
{ "id": "task.pause-all-task", "command": "application:pause-all-task" },
{ "id": "task.resume-all-task", "command": "application:resume-all-task" }
]
},
{
"id": "menu.edit",
"submenu": [
{ "id": "edit.undo", "role": "undo" },
{ "id": "edit.redo", "role": "redo" },
{ "type": "separator" },
{ "id": "edit.cut", "role": "cut" },
{ "id": "edit.copy", "role": "copy" },
{ "id": "edit.paste", "role": "paste" },
{ "id": "edit.delete", "role": "delete" },
{ "id": "edit.select-all", "role": "selectall" }
]
},
{
"role": "window",
"id": "menu.window",
"submenu": [
{ "id": "window.reload", "role": "reload" },
{ "id": "window.close", "role": "close" },
{ "id": "window.minimize", "role": "minimize" },
{ "id": "window.zoom", "role": "zoom" },
{ "id": "window.toggle-fullscreen", "role": "togglefullscreen" },
{ "type": "separator" },
{ "id": "window.front", "role": "front" }
]
},
{
"role": "help",
"id": "menu.help",
"submenu": [
{ "id": "help.official-website", "command": "help:official-website" },
{ "id": "help.manual", "command": "help:manual" },
{ "id": "help.release-notes", "command": "help:release-notes" },
{ "type": "separator" },
{ "id": "help.report-problem", "command": "help:report-problem" },
{ "type": "separator" },
{ "id": "help.toggle-dev-tools", "role": "toggledevtools" }
]
}
]
}
+11
View File
@@ -0,0 +1,11 @@
[
{ "id": "task.new-task", "command": "application:new-task", "command-after": "application:show,index" },
{ "id": "task.new-bt-task", "command": "application:new-bt-task", "command-arg": "torrent", "command-after": "application:show,index" },
{ "id": "task.open-file", "command": "application:open-file", "command-before": "application:show,index" },
{ "type": "separator" },
{ "id": "app.show", "command": "application:show", "command-arg": "index" },
{ "id": "help.manual", "command": "help:manual" },
{ "type": "separator" },
{ "id": "app.preferences", "command": "application:preferences", "command-before": "application:show,index" },
{ "id": "app.quit", "role": "quit" }
]
+74
View File
@@ -0,0 +1,74 @@
{
"menu": [
{
"id": "menu.file",
"submenu": [
{ "id": "app.about", "command": "application:about", "command-before": "application:show,index" },
{ "type": "separator" },
{ "id": "app.preferences", "command": "application:preferences" },
{ "id": "app.check-for-updates", "command": "application:check-for-updates" },
{ "id": "app.show", "command": "application:show", "command-arg": "index" },
{ "type": "separator" },
{ "id": "app.quit", "role": "quit" }
]
},
{
"id": "menu.task",
"submenu": [
{ "id": "task.new-task", "command": "application:new-task", "command-after": "application:show,index" },
{ "id": "task.new-bt-task", "command": "application:new-bt-task", "command-arg": "torrent", "command-after": "application:show,index" },
{ "id": "task.open-file", "command": "application:open-file", "command-before": "application:show,index" },
{ "type": "separator" },
{ "id": "task.pause-task", "command": "application:pause-task" },
{ "id": "task.resume-task", "command": "application:resume-task" },
{ "id": "task.delete-task", "command": "application:delete-task" },
{ "id": "task.move-task-up", "command": "application:move-task-up" },
{ "id": "task.move-task-down", "command": "application:move-task-down" },
{ "type": "separator" },
{ "id": "task.pause-all-task", "command": "application:pause-all-task" },
{ "id": "task.resume-all-task", "command": "application:resume-all-task" },
{ "type": "separator" },
{ "id": "task.clear-recent-tasks", "command": "application:clear-recent-tasks" }
]
},
{
"id": "menu.edit",
"submenu": [
{ "id": "edit.undo", "role": "undo" },
{ "id": "edit.redo", "role": "redo" },
{ "type": "separator" },
{ "id": "edit.cut", "role": "cut" },
{ "id": "edit.copy", "role": "copy" },
{ "id": "edit.paste", "role": "paste" },
{ "id": "edit.delete", "role": "delete" },
{ "id": "edit.select-all", "role": "selectall" }
]
},
{
"role": "window",
"id": "menu.window",
"submenu": [
{ "id": "window.reload", "role": "reload" },
{ "id": "window.close", "role": "close" },
{ "id": "window.minimize", "role": "minimize" },
{ "id": "window.zoom", "role": "zoom" },
{ "id": "window.toggle-fullscreen", "role": "togglefullscreen" },
{ "type": "separator" },
{ "id": "window.front", "role": "front" }
]
},
{
"role": "help",
"id": "menu.help",
"submenu": [
{ "id": "help.official-website", "command": "help:official-website" },
{ "id": "help.manual", "command": "help:manual" },
{ "id": "help.release-notes", "command": "help:release-notes" },
{ "type": "separator" },
{ "id": "help.report-problem", "command": "help:report-problem" },
{ "type": "separator" },
{ "id": "help.toggle-dev-tools", "role": "toggledevtools" }
]
}
]
}
-80
View File
@@ -1,80 +0,0 @@
{
"menu": [
{
"label": "Motrix",
"id": "menu.app",
"submenu": [
{ "label": "关于 Motrix", "id": "app.about", "command": "application:about", "command-before": "application:show,index"},
{ "type": "separator" },
{ "label": "偏好设置...", "id": "app.preferences", "command": "application:preferences" },
{ "label": "检查更新...", "id": "app.check-for-updates", "command": "application:check-for-updates" },
{ "label": "隐藏 Motrix", "id": "app.hide", "role": "hide" },
{ "label": "隐藏其他", "id": "app.hide-others", "role": "hideothers" },
{ "label": "显示全部", "id": "app.unhide", "role": "unhide" },
{ "type": "separator" },
{ "label": "退出 Motrix", "id": "app.quit", "role": "quit" }
]
},
{
"label": "任务",
"id": "menu.task",
"submenu": [
{ "label": "新建任务", "id": "task.new-task", "command": "application:new-task", "command-after": "application:show,index"},
{ "label": "新建 BT 任务", "id": "task.new-bt-task", "command": "application:new-bt-task", "command-arg": "torrent", "command-after": "application:show,index"},
{ "type": "separator" },
{ "label": "暂停任务", "id": "task.pause-task", "command": "application:pause-task" },
{ "label": "恢复任务", "id": "task.resume-task", "command": "application:resume-task" },
{ "label": "删除任务", "id": "task.delete-task", "command": "application:delete-task" },
{ "label": "上移任务", "id": "task.move-task-up", "command": "application:move-task-up" },
{ "label": "下移任务", "id": "task.move-task-down", "command": "application:move-task-down" },
{ "type": "separator" },
{ "label": "暂停所有任务", "id": "task.pause-all-task", "command": "application:pause-all-task" },
{ "label": "恢复所有任务", "id": "task.resume-all-task", "command": "application:resume-all-task" },
{ "type": "separator" },
{ "label": "清除最近的下载记录", "id": "task.clear-recent-tasks", "command": "application:clear-recent-tasks" }
]
},
{
"label": "编辑",
"id": "menu.edit",
"submenu": [
{ "label": "撤销", "id": "edit.undo", "role": "undo" },
{ "label": "重做", "id": "edit.redo", "role": "redo" },
{ "type": "separator" },
{ "label": "剪切", "id": "edit.cut", "role": "cut" },
{ "label": "复制", "id": "edit.copy", "role": "copy" },
{ "label": "黏贴", "id": "edit.paste", "role": "paste" },
{ "label": "删除", "id": "edit.delete", "role": "delete" },
{ "label": "全选", "id": "edit.select-all", "role": "selectall" }
]
},
{
"label": "窗口",
"role": "window",
"id": "menu.window",
"submenu": [
{ "label": "重新加载", "id": "window.reload", "role": "reload" },
{ "label": "关闭", "id": "window.close", "role": "close" },
{ "label": "最小化", "id": "window.minimize", "role": "minimize" },
{ "label": "放大", "id": "window.zoom", "role": "zoom" },
{ "label": "进入全屏幕", "id": "window.toggle-fullscreen", "role": "togglefullscreen" },
{ "type": "separator" },
{ "label": "前置全部窗口", "id": "window.front", "role": "front" }
]
},
{
"label": "帮助",
"role": "help",
"id": "menu.help",
"submenu": [
{ "label": "Motrix 官网", "id": "help.official-website", "command": "help:official-website" },
{ "label": "使用手册", "id": "help.manual", "command": "help:manual" },
{ "label": "发行说明...", "id": "help.release-notes", "command": "help:release-notes" },
{ "type": "separator" },
{ "label": "报告问题", "id": "help.report-problem", "command": "help:report-problem" },
{ "type": "separator" },
{ "label": "开发者工具", "id": "help.toggle-dev-tools", "role": "toggledevtools" }
]
}
]
}
-80
View File
@@ -1,80 +0,0 @@
{
"menu": [
{
"label": "文件",
"id": "menu.file",
"submenu": [
{ "label": "关于 Motrix", "id": "app.about", "command": "application:about", "command-before": "application:show,index"},
{ "type": "separator" },
{ "label": "偏好设置...", "id": "app.preferences", "command": "application:preferences" },
{ "label": "检查更新...", "id": "app.check-for-updates", "command": "application:check-for-updates" },
{ "label": "隐藏 Motrix", "id": "app.hide", "role": "hide" },
{ "label": "隐藏其他", "id": "app.hide-others", "role": "hideothers" },
{ "label": "显示全部", "id": "app.unhide", "role": "unhide" },
{ "type": "separator" },
{ "label": "退出 Motrix", "id": "app.quit", "role": "quit" }
]
},
{
"label": "任务",
"id": "menu.task",
"submenu": [
{ "label": "新建任务", "id": "task.new-task", "command": "application:new-task", "command-after": "application:show,index"},
{ "label": "新建 BT 任务", "id": "task.new-bt-task", "command": "application:new-bt-task", "command-arg": "torrent", "command-after": "application:show,index"},
{ "type": "separator" },
{ "label": "暂停任务", "id": "task.pause-task", "command": "application:pause-task" },
{ "label": "恢复任务", "id": "task.resume-task", "command": "application:resume-task" },
{ "label": "删除任务", "id": "task.delete-task", "command": "application:delete-task" },
{ "label": "上移任务", "id": "task.move-task-up", "command": "application:move-task-up" },
{ "label": "下移任务", "id": "task.move-task-down", "command": "application:move-task-down" },
{ "type": "separator" },
{ "label": "暂停所有任务", "id": "task.pause-all-task", "command": "application:pause-all-task" },
{ "label": "恢复所有任务", "id": "task.resume-all-task", "command": "application:resume-all-task" },
{ "type": "separator" },
{ "label": "清除最近的下载记录", "id": "task.clear-recent-tasks", "command": "application:clear-recent-tasks" }
]
},
{
"label": "编辑",
"id": "menu.edit",
"submenu": [
{ "label": "撤销", "id": "edit.undo", "role": "undo" },
{ "label": "重做", "id": "edit.redo", "role": "redo" },
{ "type": "separator" },
{ "label": "剪切", "id": "edit.cut", "role": "cut" },
{ "label": "复制", "id": "edit.copy", "role": "copy" },
{ "label": "黏贴", "id": "edit.paste", "role": "paste" },
{ "label": "删除", "id": "edit.delete", "role": "delete" },
{ "label": "全选", "id": "edit.select-all", "role": "selectall" }
]
},
{
"label": "窗口",
"role": "window",
"id": "menu.window",
"submenu": [
{ "label": "重新加载", "id": "window.reload", "role": "reload" },
{ "label": "关闭", "id": "window.close", "role": "close" },
{ "label": "最小化", "id": "window.minimize", "role": "minimize" },
{ "label": "放大", "id": "window.zoom", "role": "zoom" },
{ "label": "进入全屏幕", "id": "window.toggle-fullscreen", "role": "togglefullscreen" },
{ "type": "separator" },
{ "label": "前置全部窗口", "id": "window.front", "role": "front" }
]
},
{
"label": "帮助",
"role": "help",
"id": "menu.help",
"submenu": [
{ "label": "Motrix 官网", "id": "help.official-website", "command": "help:official-website" },
{ "label": "使用手册", "id": "help.manual", "command": "help:manual" },
{ "label": "发行说明...", "id": "help.release-notes", "command": "help:release-notes" },
{ "type": "separator" },
{ "label": "报告问题", "id": "help.report-problem", "command": "help:report-problem" },
{ "type": "separator" },
{ "label": "开发者工具", "id": "help.toggle-dev-tools", "role": "toggledevtools" }
]
}
]
}
-80
View File
@@ -1,80 +0,0 @@
{
"menu": [
{
"label": "文件",
"id": "menu.file",
"submenu": [
{ "label": "关于 Motrix", "id": "app.about", "command": "application:about", "command-before": "application:show,index"},
{ "type": "separator" },
{ "label": "偏好设置...", "id": "app.preferences", "command": "application:preferences" },
{ "label": "检查更新...", "id": "app.check-for-updates", "command": "application:check-for-updates" },
{ "label": "隐藏 Motrix", "id": "app.hide", "role": "hide" },
{ "label": "隐藏其他", "id": "app.hide-others", "role": "hideothers" },
{ "label": "显示全部", "id": "app.unhide", "role": "unhide" },
{ "type": "separator" },
{ "label": "退出 Motrix", "id": "app.quit", "role": "quit" }
]
},
{
"label": "任务",
"id": "menu.task",
"submenu": [
{ "label": "新建任务", "id": "task.new-task", "command": "application:new-task", "command-after": "application:show,index"},
{ "label": "新建 BT 任务", "id": "task.new-bt-task", "command": "application:new-bt-task", "command-arg": "torrent", "command-after": "application:show,index"},
{ "type": "separator" },
{ "label": "暂停任务", "id": "task.pause-task", "command": "application:pause-task" },
{ "label": "恢复任务", "id": "task.resume-task", "command": "application:resume-task" },
{ "label": "删除任务", "id": "task.delete-task", "command": "application:delete-task" },
{ "label": "上移任务", "id": "task.move-task-up", "command": "application:move-task-up" },
{ "label": "下移任务", "id": "task.move-task-down", "command": "application:move-task-down" },
{ "type": "separator" },
{ "label": "暂停所有任务", "id": "task.pause-all-task", "command": "application:pause-all-task" },
{ "label": "恢复所有任务", "id": "task.resume-all-task", "command": "application:resume-all-task" },
{ "type": "separator" },
{ "label": "清除最近的下载记录", "id": "task.clear-recent-tasks", "command": "application:clear-recent-tasks" }
]
},
{
"label": "编辑",
"id": "menu.edit",
"submenu": [
{ "label": "撤销", "id": "edit.undo", "role": "undo" },
{ "label": "重做", "id": "edit.redo", "role": "redo" },
{ "type": "separator" },
{ "label": "剪切", "id": "edit.cut", "role": "cut" },
{ "label": "复制", "id": "edit.copy", "role": "copy" },
{ "label": "黏贴", "id": "edit.paste", "role": "paste" },
{ "label": "删除", "id": "edit.delete", "role": "delete" },
{ "label": "全选", "id": "edit.select-all", "role": "selectall" }
]
},
{
"label": "窗口",
"role": "window",
"id": "menu.window",
"submenu": [
{ "label": "重新加载", "id": "window.reload", "role": "reload" },
{ "label": "关闭", "id": "window.close", "role": "close" },
{ "label": "最小化", "id": "window.minimize", "role": "minimize" },
{ "label": "放大", "id": "window.zoom", "role": "zoom" },
{ "label": "进入全屏幕", "id": "window.toggle-fullscreen", "role": "togglefullscreen" },
{ "type": "separator" },
{ "label": "前置全部窗口", "id": "window.front", "role": "front" }
]
},
{
"label": "帮助",
"role": "help",
"id": "menu.help",
"submenu": [
{ "label": "Motrix 官网", "id": "help.official-website", "command": "help:official-website" },
{ "label": "使用手册", "id": "help.manual", "command": "help:manual" },
{ "label": "发行说明...", "id": "help.release-notes", "command": "help:release-notes" },
{ "type": "separator" },
{ "label": "报告问题", "id": "help.report-problem", "command": "help:report-problem" },
{ "type": "separator" },
{ "label": "开发者工具", "id": "help.toggle-dev-tools", "role": "toggledevtools" }
]
}
]
}
+24
View File
@@ -0,0 +1,24 @@
import resources from '@shared/locales/app'
import LocaleManager from '@shared/locales/LocaleManager'
const localeManager = new LocaleManager({
resources
})
export function getLocaleManager () {
return localeManager
}
export function setupLocaleManager (locale) {
localeManager.changeLanguageByLocale(locale)
return localeManager
}
export function getI18n () {
return localeManager.getI18n()
}
export function getI18nTranslator () {
return localeManager.getI18n().t
}
+21 -20
View File
@@ -6,29 +6,24 @@ import {
updateStates
} from '../utils/menu'
import keymap from '@shared/keymap'
import { getI18n } from '@/ui/Locale'
export default class MenuManager extends EventEmitter {
constructor (options) {
super()
this.options = options
this.i18n = getI18n()
this.keymap = keymap
this.template = []
this.menu = null
this.items = {}
this.load()
this.setup()
}
load (locale = 'en-US') {
let template = null
try {
template = require(`../menus/${locale}/${process.platform}.json`)
if (!template) {
template = require(`../menus/en-US/${process.platform}.json`)
}
} catch (err) {
template = require(`../menus/en-US/${process.platform}.json`)
}
load () {
let template = require(`../menus/${process.platform}.json`)
this.template = template['menu']
}
@@ -38,15 +33,21 @@ export default class MenuManager extends EventEmitter {
keystrokesByCommand[this.keymap[item]] = item
}
const tpl = translateTemplate(this.template, keystrokesByCommand)
this.menu = Menu.buildFromTemplate(tpl)
// Deepclone the menu template to refresh menu
const template = JSON.parse(JSON.stringify(this.template))
const tpl = translateTemplate(template, keystrokesByCommand, this.i18n)
const menu = Menu.buildFromTemplate(tpl)
return menu
}
setup (locale) {
this.load(locale)
this.build()
Menu.setApplicationMenu(this.menu)
this.items = flattenMenuItems(this.menu)
setup () {
const menu = this.build()
Menu.setApplicationMenu(menu)
this.items = flattenMenuItems(menu)
}
rebuild () {
this.setup()
}
updateStates (visibleStates, enabledStates, checkedStates) {
+95 -1
View File
@@ -1,3 +1,97 @@
export default class TrayManager {
import { EventEmitter } from 'events'
import { join } from 'path'
import { Tray, Menu } from 'electron'
import is from 'electron-is'
import { translateTemplate } from '../utils/menu'
import { getI18n } from '@/ui/Locale'
let tray = null
export default class TrayManager extends EventEmitter {
constructor (options = {}) {
super()
this.i18n = getI18n()
this.menu = null
this.load()
this.init()
this.setup()
this.handleEvents()
}
load () {
this.template = require(`../menus/tray.json`)
if (is.macOS()) {
this.normalIcon = join(__static, './mo-tray-normal.png')
this.activeIcon = join(__static, './mo-tray-active.png')
} else {
this.normalIcon = join(__static, './mo-tray-colorful-normal.png')
this.activeIcon = join(__static, './mo-tray-colorful-active.png')
}
}
build () {
const keystrokesByCommand = {}
for (let item in this.keymap) {
keystrokesByCommand[this.keymap[item]] = item
}
// Deepclone the menu template to refresh menu
const template = JSON.parse(JSON.stringify(this.template))
const tpl = translateTemplate(template, keystrokesByCommand, this.i18n)
this.menu = Menu.buildFromTemplate(tpl)
}
setup () {
this.build()
/**
* Linux requires setContextMenu to be called
* in order for the context menu to populate correctly
*/
if (process.platform === 'linux') {
tray.setContextMenu(this.menu)
}
}
init () {
tray = new Tray(this.normalIcon)
tray.setToolTip('Motrix')
}
handleEvents () {
tray.on('click', this.handleTrayClick)
tray.on('double-click', this.handleTrayDbClick)
tray.on('right-click', this.handleTrayRightClick)
tray.on('drop-files', this.handleTrayDropFile)
}
handleTrayClick = (event) => {
event.preventDefault()
global.application.toggle()
}
handleTrayDbClick = (event) => {
event.preventDefault()
global.application.show()
}
handleTrayRightClick = (event) => {
event.preventDefault()
tray.popUpContextMenu(this.menu)
}
handleTrayDropFile = (event, files) => {
global.application.show()
global.application.handleFile(files[0])
}
updateStatus (status) {
const icon = status ? this.activeIcon : this.normalIcon
tray.setImage(icon)
}
}
+62 -6
View File
@@ -1,6 +1,9 @@
import { join } from 'path'
import { EventEmitter } from 'events'
import { app, shell, BrowserWindow } from 'electron'
import is from 'electron-is'
import pageConfig from '../configs/page'
import logger from '../core/Logger'
const defaultBrowserOptions = {
titleBarStyle: 'hiddenInset',
@@ -19,9 +22,9 @@ export default class WindowManager extends EventEmitter {
this.willQuit = false
app.on('before-quit', () => {
this.setWillQuit(true)
})
this.handleBeforeQuit()
this.handleAllWindowClosed()
}
setWillQuit (flag) {
@@ -32,8 +35,15 @@ export default class WindowManager extends EventEmitter {
const result = pageConfig[page] || {}
const hideAppMenu = this.userConfig['hide-app-menu']
if (hideAppMenu) {
result.frame = false
result.attrs.frame = false
}
// fix AppImage Dock Icon Missing
// https://github.com/AppImage/AppImageKit/wiki/Bundling-Electron-apps
if (is.linux()) {
result.attrs.icon = join(__static, './512x512.png')
}
return result
}
@@ -65,7 +75,7 @@ export default class WindowManager extends EventEmitter {
window.show()
})
if (options.bindCloseToHide && process.platform === 'darwin') {
if (options.bindCloseToHide) {
this.bindCloseToHide(page, window)
}
@@ -116,15 +126,61 @@ export default class WindowManager extends EventEmitter {
})
}
showWindow (page) {
const window = this.getWindow(page)
if (!window) {
return
}
window.show()
}
hideWindow (page) {
const window = this.getWindow(page)
if (!window) {
return
}
window.hide()
}
hideAllWindow () {
this.getWindowList().forEach((window) => {
window.hide()
})
}
toggleWindow (page) {
const window = this.getWindow(page)
if (!window) {
return
}
if (window.isVisible()) {
window.hide()
} else {
window.show()
}
}
getFocusedWindow () {
return BrowserWindow.getFocusedWindow()
}
handleBeforeQuit () {
app.on('before-quit', () => {
this.setWillQuit(true)
})
}
handleAllWindowClosed () {
app.on('window-all-closed', (event) => {
event.preventDefault()
})
}
sendCommandTo (window, command, ...args) {
if (!window) {
return
}
console.log('sendCommandTo====>', window, command, ...args)
logger.info('[Motrix] sendCommandTo===>', window, command, ...args)
window.webContents.send('command', command, ...args)
}
+19 -2
View File
@@ -1,6 +1,7 @@
import { app } from 'electron'
import is from 'electron-is'
import { resolve } from 'path'
import { existsSync, lstatSync } from 'fs'
import logger from '../core/Logger'
import engineBinMap from '../configs/engine'
@@ -44,17 +45,33 @@ export function isRunningInDmg () {
return result
}
export function moveAppToApplicationsFolder () {
export function moveAppToApplicationsFolder (errorMsg = '') {
return new Promise((resolve, reject) => {
try {
const result = app.moveToApplicationsFolder()
if (result) {
resolve(result)
} else {
reject(new Error('应用程序移动失败'))
reject(new Error(errorMsg))
}
} catch (err) {
reject(err)
}
})
}
export function isDirectory (path) {
return existsSync(path) && lstatSync(path).isDirectory()
}
export function parseArgv (argv) {
let arg = argv[1]
if (!arg || isDirectory(arg)) {
return
}
if (is.linux()) {
arg = arg.replace('file://', '')
}
return arg
}
+16 -6
View File
@@ -71,19 +71,29 @@ function findById (template, id) {
return null
}
export function translateTemplate (template, keystrokesByCommand) {
export function translateTemplate (template, keystrokesByCommand, i18n) {
for (let i in template) {
let item = template[i]
if (item.command) {
item.accelerator = acceleratorForCommand(item.command, keystrokesByCommand)
}
// If label is specified, label is used as the key of i18n.t(key),
// which mainly solves the inaccurate translation of item.id.
if (i18n) {
if (item.label) {
item.label = i18n.t(item.label)
} else if (item.id) {
item.label = i18n.t(item.id)
}
}
item.click = () => {
console.log('click sendCommand', item)
handleCommand(item)
}
if (item.submenu) {
translateTemplate(item.submenu, keystrokesByCommand)
translateTemplate(item.submenu, keystrokesByCommand, i18n)
}
}
return template
@@ -96,7 +106,7 @@ export function handleCommand (item) {
? [item.command, item['command-arg']]
: [item.command]
global.application.sendCommand(...args)
global.application.sendCommandToAll(...args)
handleCommandAfter(item)
}
@@ -108,7 +118,7 @@ function handleCommandBefore (item) {
}
const [ command, ...args ] = item['command-before'].split(',')
console.log('handleCommandBefore==2=>', command, ...args)
global.application.sendCommand(command, ...args)
global.application.sendCommandToAll(command, ...args)
}
function handleCommandAfter (item) {
@@ -118,7 +128,7 @@ function handleCommandAfter (item) {
}
const [ command, ...args ] = item['command-after'].split(',')
console.log('handleCommandAfter==2=>', command, ...args)
global.application.sendCommand(command, ...args)
global.application.sendCommandToAll(command, ...args)
}
function acceleratorForCommand (command, keystrokesByCommand) {
+12 -3
View File
@@ -111,6 +111,15 @@ export default class Api {
return this.client.call('getVersion')
}
getGlobalOption () {
return new Promise((resolve) => {
this.client.call('getGlobalOption')
.then((data) => {
resolve(changeKeysToCamelCase(data))
})
})
}
getGlobalStat () {
return this.client.call('getGlobalStat')
}
@@ -146,7 +155,7 @@ export default class Api {
}
fetchDownloadingTaskList (params = {}) {
const { offset = 0, num = 200, keys } = params
const { offset = 0, num = 20, keys } = params
const activeArgs = compactUndefined([keys])
const waitingArgs = compactUndefined([offset, num, keys])
return new Promise((resolve, reject) => {
@@ -165,13 +174,13 @@ export default class Api {
}
fetchWaitingTaskList (params = {}) {
const { offset = 0, num = 200, keys } = params
const { offset = 0, num = 20, keys } = params
const args = compactUndefined([offset, num, keys])
return this.client.call('tellWaiting', ...args)
}
fetchStoppedTaskList (params = {}) {
const { offset = 0, num = 200, keys } = params
const { offset = 0, num = 20, keys } = params
const args = compactUndefined([offset, num, keys])
return this.client.call('tellStopped', ...args)
}
+2 -2
View File
@@ -1,11 +1,11 @@
<template>
<el-row class="copyright">
<el-col :span="8" class="copyright-left">
<el-col :span="6" class="copyright-left">
<a target="_blank" href="https://motrix.app/" rel="noopener noreferrer">
&copy;2018 Motrix
</a>
</el-col>
<el-col :span="16" class="copyright-right">
<el-col :span="18" class="copyright-right">
<a target="_blank" href="https://motrix.app/about" rel="noopener noreferrer">
{{ $t('about.about') }}
</a>
+6 -5
View File
@@ -1,5 +1,5 @@
<template>
<el-aside width="78px" class="aside" :class="{ draggable: !isWindows() }">
<el-aside width="78px" :class="['aside', { 'draggable': asideDraggable }]">
<div class="aside-inner">
<mo-logo-mini />
<ul class="menu top-menu">
@@ -39,11 +39,12 @@
computed: {
...mapState('app', {
currentPage: state => state.currentPage
})
}),
asideDraggable: function () {
return is.macOS()
}
},
methods: {
isRenderer: is.renderer,
isWindows: is.windows,
open (link) {
this.$electron.shell.openExternal(link)
},
@@ -51,7 +52,7 @@
this.$store.dispatch('app/showAddTaskDialog', taskType)
},
showAboutPanel () {
// if (this.isRenderer()) {
// if (is.renderer()) {
// this.$electron.ipcRenderer.send('command', 'application:about')
// } else {
this.$store.dispatch('app/showAboutPanel')
+13
View File
@@ -3,6 +3,8 @@ import store from '@/store'
import CommandManager from './CommandManager'
import { Message } from 'element-ui'
import { getLocaleManager } from '@/components/Locale'
import { base64StringToBlob } from 'blob-util'
import { buildFileList } from '@shared/utils'
const commands = new CommandManager()
const i18n = getLocaleManager().getI18n()
@@ -15,6 +17,16 @@ function showAddTask (taskType = 'uri') {
store.dispatch('app/showAddTaskDialog', taskType)
}
function showAddBtTaskWithFile (fileName, base64Data = '') {
const blob = base64StringToBlob(base64Data, 'application/x-bittorrent')
const file = new File([blob], fileName, { type: 'application/x-bittorrent' })
const fileList = buildFileList(file)
store.dispatch('app/showAddTaskDialog', 'torrent')
setTimeout(() => {
store.dispatch('app/addTaskAddTorrents', { fileList })
}, 200)
}
function navigateTaskList (status = 'active') {
router.push({ path: `/task/${status}` })
}
@@ -58,6 +70,7 @@ function resumeAllTask () {
commands.register('application:about', showAboutPanel)
commands.register('application:new-task', showAddTask)
commands.register('application:new-bt-task', showAddTask)
commands.register('application:new-bt-task-with-file', showAddBtTaskWithFile)
commands.register('application:task-list', navigateTaskList)
commands.register('application:preferences', navigatePreferences)
+48
View File
@@ -0,0 +1,48 @@
<template>
<div v-if="false"></div>
</template>
<script>
export default {
name: 'mo-dragger',
mounted () {
this.preventDefault = ev => ev.preventDefault()
let count = 0
this.onDragEnter = (ev) => {
if (count === 0) {
this.$store.dispatch('app/showAddTaskDialog', 'torrent')
}
count++
}
this.onDragLeave = (ev) => {
count--
if (count === 0) {
this.$store.dispatch('app/hideAddTaskDialog')
}
}
this.onDrop = (ev) => {
count = 0
const fileList = [...ev.dataTransfer.files]
.map(item => ({ raw: item, name: item.name }))
.filter(item => /\.torrent$/.test(item.name))
if (!fileList.length) {
this.$msg.error(this.$t('task.select-torrent'))
}
}
document.addEventListener('dragover', this.preventDefault)
document.body.addEventListener('dragenter', this.onDragEnter)
document.body.addEventListener('dragleave', this.onDragLeave)
document.body.addEventListener('drop', this.onDrop)
},
destroyed () {
document.removeEventListener('dragover', this.preventDefault)
document.body.removeEventListener('dragenter', this.onDragEnter)
document.body.removeEventListener('dragleave', this.onDragLeave)
document.body.removeEventListener('drop', this.onDrop)
}
}
</script>
+4 -26
View File
@@ -1,32 +1,10 @@
import i18next from 'i18next'
import { getLanguage } from '@shared/locales'
import resources from '@shared/locales/all'
import LocaleManager from '@shared/locales/LocaleManager'
export class LocaleManager {
constructor (options = {}) {
this.options = options
const localeManager = new LocaleManager({
resources
})
i18next.init({
fallbackLng: 'en-US',
resources
})
}
changeLanguage (lng) {
i18next.changeLanguage(lng)
}
changeLanguageByLocale (locale) {
const lng = getLanguage(locale)
this.changeLanguage(lng)
}
getI18n () {
return i18next
}
}
const localeManager = new LocaleManager()
export function getLocaleManager () {
return localeManager
}
+4 -1
View File
@@ -6,6 +6,7 @@
<mo-add-task :visible="addTaskVisible" :type="addTaskType" />
<mo-about-panel :visible="aboutPanelVisible" />
<mo-task-item-info :visible="taskItemInfoVisible" :task="currentTaskItem" />
<mo-dragger />
</el-container>
</template>
@@ -17,6 +18,7 @@
import Speedometer from '@/components/Speedometer/Speedometer'
import AddTask from '@/components/Task/AddTask'
import TaskItemInfo from '@/components/Task/TaskItemInfo'
import Dragger from '@/components/Dragger/Index'
export default {
name: 'mo-main',
@@ -26,7 +28,8 @@
[Subnav.name]: Subnav,
[Speedometer.name]: Speedometer,
[AddTask.name]: AddTask,
[TaskItemInfo.name]: TaskItemInfo
[TaskItemInfo.name]: TaskItemInfo,
[Dragger.name]: Dragger
},
computed: {
...mapState('app', {
+42
View File
@@ -0,0 +1,42 @@
const queue = []
const maxLength = 5
export default {
install: function (Vue, Message, defaultOption = {}) {
Vue.prototype.$msg = new Proxy(Message, {
get (obj, prop) {
return (arg) => {
if (!(arg instanceof Object)) {
arg = { message: arg }
}
const task = {
run () {
obj[prop]({
...defaultOption,
...arg,
onClose (...data) {
const currentTask = queue.pop()
if (currentTask) {
currentTask.run()
}
if (arg.onClose) {
arg.onClose(...data)
}
}
})
}
}
if (queue.length >= maxLength) {
queue.pop()
}
queue.unshift(task)
if (queue.length === 1) {
queue.pop().run()
}
}
}
})
}
}
+38 -15
View File
@@ -3,6 +3,7 @@
</template>
<script>
import is from 'electron-is'
import { mapState } from 'vuex'
import api from '@/api'
import {
@@ -18,10 +19,17 @@
export default {
name: 'mo-engine-client',
data: function () {
return {
downloading: false
}
},
computed: {
isRenderer: () => is.renderer(),
...mapState('app', {
downloadSpeed: state => state.stat.downloadSpeed,
interval: state => state.interval
interval: state => state.interval,
numActive: state => state.stat.numActive
}),
...mapState('task', {
taskItemInfoVisible: state => state.taskItemInfoVisible,
@@ -34,56 +42,70 @@
watch: {
downloadSpeed: function (val, oldVal) {
showDownloadSpeedInDock(val)
},
numActive: function (val, oldVal) {
this.downloading = val > 0
},
downloading: function (val, oldVal) {
if (val !== oldVal && this.isRenderer) {
this.$electron.ipcRenderer.send('download-status-change', val)
}
}
},
methods: {
fetchTaskItem ({ gid }) {
return api.fetchTaskItem({ gid })
.catch((e) => {
console.warn(`fetchTaskItem fail: ${e.message}`)
})
},
onDownloadStart: function (event) {
this.$store.dispatch('task/fetchList')
this.$store.dispatch('app/resetInterval')
console.log('aria2 onDownloadStart', event)
const [{ gid }] = event
api.fetchTaskItem({ gid })
this.fetchTaskItem({ gid })
.then((task) => {
const taskName = getTaskName(task)
const message = this.$t('task.download-start-message', { taskName })
this.$message.info(message)
this.$msg.info(message)
})
},
onDownloadPause: function (event) {
console.log('aria2 onDownloadPause')
const [{ gid }] = event
api.fetchTaskItem({ gid })
this.fetchTaskItem({ gid })
.then((task) => {
const taskName = getTaskName(task)
const message = this.$t('task.download-pause-message', { taskName })
this.$message.info(message)
this.$msg.info(message)
})
},
onDownloadStop: function (event) {
console.log('aria2 onDownloadStop')
const [{ gid }] = event
api.fetchTaskItem({ gid })
this.fetchTaskItem({ gid })
.then((task) => {
const taskName = getTaskName(task)
const message = this.$t('task.download-stop-message', { taskName })
this.$message.info(message)
this.$msg.info(message)
})
},
onDownloadError: function (event) {
console.log('aria2 onDownloadError', event)
const [{ gid }] = event
api.fetchTaskItem({ gid })
this.fetchTaskItem({ gid })
.then((task) => {
const taskName = getTaskName(task)
const message = this.$t('task.download-error-message', { taskName })
this.$message.error(message)
this.$msg.error(message)
})
},
onDownloadComplete: function (event) {
console.log('aria2 onDownloadComplete')
this.$store.dispatch('task/fetchList')
const [{ gid }] = event
api.fetchTaskItem({ gid })
this.fetchTaskItem({ gid })
.then((task) => {
this.showTaskCompleteNotify(task)
})
@@ -92,7 +114,7 @@
console.log('aria2 onBtDownloadComplete')
this.$store.dispatch('task/fetchList')
const [{ gid }] = event
api.fetchTaskItem({ gid })
this.fetchTaskItem({ gid })
.then((task) => {
this.showTaskCompleteNotify(task)
})
@@ -109,7 +131,7 @@
openDownloadDock(path)
const message = this.$t('task.download-complete-message', { taskName })
this.$message.success(message)
this.$msg.success(message)
/* eslint-disable no-new */
const notify = new Notification(this.$t('task.download-complete-notify'), {
@@ -129,7 +151,7 @@
const taskName = getTaskName(task)
const message = this.$t('task.download-fail-message', { taskName })
this.$message.success(message)
this.$msg.success(message)
/* eslint-disable no-new */
new Notification(this.$t('task.download-fail-notify'), {
@@ -138,7 +160,7 @@
},
bindEngineEvents: function () {
api.client.on('onDownloadStart', this.onDownloadStart)
api.client.on('onDownloadPause', this.onDownloadPause)
// api.client.on('onDownloadPause', this.onDownloadPause)
api.client.on('onDownloadStop', this.onDownloadStop)
api.client.on('onDownloadComplete', this.onDownloadComplete)
api.client.on('onDownloadError', this.onDownloadError)
@@ -146,7 +168,7 @@
},
unbindEngineEvents: function () {
api.client.removeListener('onDownloadStart', this.onDownloadStart)
api.client.removeListener('onDownloadPause', this.onDownloadPause)
// api.client.removeListener('onDownloadPause', this.onDownloadPause)
api.client.removeListener('onDownloadStop', this.onDownloadStop)
api.client.removeListener('onDownloadComplete', this.onDownloadComplete)
api.client.removeListener('onDownloadError', this.onDownloadError)
@@ -172,6 +194,7 @@
},
created: function () {
this.$store.dispatch('app/fetchEngineInfo')
this.$store.dispatch('app/fetchEngineOptions')
this.startPolling()
+27 -4
View File
@@ -1,5 +1,6 @@
<template>
<div class="title-bar">
<div class="title-bar-dragger"></div>
<ul v-if="showActions" class="window-actions">
<li @click="handleMinimize">
<mo-icon name="win-minimize" width="12" height="12" />
@@ -50,19 +51,41 @@
</script>
<style lang="scss">
.title-bar {
position: fixed;
top: 0;
left: 0;
display: flex;
flex-direction: row;
width: 100%;
height: 36px;
z-index: 5000;
.title-bar-dragger {
flex: 1;
user-select: none;
-webkit-app-region: drag;
-webkit-user-select: none;
}
.window-actions {
position: fixed;
top: 0;
right: 24px;
opacity: 0.4;
transition: $--fade-transition;
list-style: none;
padding: 0;
margin: 0;
z-index: 5100;
> li {
float: left;
display: inline-block;
padding: 5px 10px;
margin: 0 5px;
&:hover {
background-color: $--titlebar-actions-active-background;
}
}
}
&:hover {
.window-actions {
opacity: 1;
}
}
}
</style>
+34 -5
View File
@@ -2,6 +2,7 @@ import is from 'electron-is'
import { existsSync } from 'fs'
import { Message } from 'element-ui'
import {
isMagnetTask,
getTaskFullPath,
bytesToSize
} from '@shared/utils'
@@ -40,10 +41,23 @@ export function openItem (fullPath, { errorMsg }) {
return result
}
export function moveTaskFilesToTrash (task, { pathErrorMsg, delFailMsg, delConfigFailMsg }) {
export function moveTaskFilesToTrash (task, messages = {}) {
/**
* 磁力链接任务 bittorrent但没有 bittorrent.info
* 在没下完变成BT任务之前 path 不是一个完整路径
* 未避免误删所在目录所以删除时直接返回 true
*/
if (isMagnetTask(task)) {
return true
}
const { pathErrorMsg, delFailMsg, delConfigFailMsg } = messages
const { dir } = task
const path = getTaskFullPath(task)
if (!path && pathErrorMsg) {
Message.error(pathErrorMsg)
if (!path || dir === path) {
if (pathErrorMsg) {
Message.error(pathErrorMsg)
}
return false
}
@@ -66,30 +80,45 @@ export function moveTaskFilesToTrash (task, { pathErrorMsg, delFailMsg, delConfi
}
export function openDownloadDock (path) {
if (!is.macOS()) {
return
}
remote.app.dock.downloadFinished(path)
}
export function updateDockBadge (text) {
if (!is.macOS()) {
return
}
remote.app.dock.setBadge(text)
}
export function showDownloadSpeedInDock (downloadSpeed) {
if (is.windows()) {
if (!is.macOS()) {
return
}
const text = downloadSpeed > 0 ? bytesToSize(downloadSpeed) : ''
const text = downloadSpeed > 0 ? `${bytesToSize(downloadSpeed)}/s` : ''
updateDockBadge(text)
}
export function addToRecentTask (task) {
if (is.linux()) {
return
}
const path = getTaskFullPath(task)
remote.app.addRecentDocument(path)
}
export function addToRecentTaskByPath (path) {
if (is.linux()) {
return
}
remote.app.addRecentDocument(path)
}
export function clearRecentTasks () {
if (is.linux()) {
return
}
remote.app.clearRecentDocuments()
}
+10 -17
View File
@@ -85,7 +85,9 @@
</el-input>
</el-col>
<el-col class="form-item-sub" :span="24">
<el-button plain type="danger" @click="() => onFactoryResetClick()">{{ $t('preferences.factory-reset') }}</el-button>
<el-button plain type="danger" @click="() => onFactoryResetClick()">
{{ $t('preferences.factory-reset') }}
</el-button>
</el-col>
</el-form-item>
</el-form>
@@ -102,7 +104,7 @@
import { mapState } from 'vuex'
import ShowInFolder from '@/components/Native/ShowInFolder'
import userAgentMap from '@shared/ua'
import { getLanguage } from '@shared/locales'
import { availableLanguages, getLanguage } from '@shared/locales'
import { getLocaleManager } from '@/components/Locale'
const initialForm = (config) => {
@@ -136,16 +138,7 @@
form: initialForm(this.$store.state.preference.config),
rules: {},
color: '#c00',
locales: [
{
value: 'zh-CN',
label: '🇨🇳 简体中文'
},
{
value: 'en-US',
label: '🇺🇸 English (US)'
}
]
locales: availableLanguages
}
},
computed: {
@@ -186,8 +179,8 @@
onFactoryResetClick () {
this.$electron.remote.dialog.showMessageBox({
type: 'warning',
title: '恢复初始设置',
message: '你确定要恢复为初始设置吗?',
title: this.$t('preferences.factory-reset'),
message: this.$t('preferences.factory-reset-confirm'),
buttons: [this.$t('app.yes'), this.$t('app.no')],
cancelId: 1
}, (buttonIndex) => {
@@ -218,7 +211,7 @@
</script>
<style lang="scss">
.ua-group {
margin-top: 8px;
}
.ua-group {
margin-top: 8px;
}
</style>
@@ -4,7 +4,7 @@
<ul>
<li
@click="() => nav('basic')"
v-bind:class="[ current === 'basic' ? 'active' : '' ]"
:class="[ current === 'basic' ? 'active' : '' ]"
>
<i class="subnav-icon">
<mo-icon name='preference-basic' width="20" height="20" />
@@ -13,7 +13,7 @@
</li>
<li
@click="() => nav('advanced')"
v-bind:class="[ current === 'advanced' ? 'active' : '' ]"
:class="[ current === 'advanced' ? 'active' : '' ]"
>
<i class="subnav-icon">
<mo-icon name='preference-advanced' width="20" height="20" />
@@ -22,7 +22,7 @@
</li>
<li
@click="() => nav('lab')"
v-bind:class="[ current === 'lab' ? 'active' : '' ]"
:class="[ current === 'lab' ? 'active' : '' ]"
>
<i class="subnav-icon">
<mo-icon name='preference-lab' width="20" height="20" />
@@ -34,7 +34,6 @@
</template>
<script>
import is from 'electron-is'
import '@/components/Icons/preference-basic'
import '@/components/Icons/preference-advanced'
import '@/components/Icons/preference-lab'
@@ -53,7 +52,6 @@
}
},
methods: {
isMas: is.mas,
nav: function (category = 'basic') {
this.$router.push({
path: `/preference/${category}`
@@ -4,7 +4,7 @@
<ul>
<li
@click="() => nav('active')"
v-bind:class="[ current === 'active' ? 'active' : '' ]"
:class="[ current === 'active' ? 'active' : '' ]"
>
<i class="subnav-icon">
<mo-icon name="task-start" width="20" height="20" />
@@ -13,7 +13,7 @@
</li>
<li
@click="() => nav('waiting')"
v-bind:class="[ current === 'waiting' ? 'active' : '' ]"
:class="[ current === 'waiting' ? 'active' : '' ]"
>
<i class="subnav-icon">
<mo-icon name="task-pause" width="20" height="20" />
@@ -22,7 +22,7 @@
</li>
<li
@click="() => nav('stopped')"
v-bind:class="[ current === 'stopped' ? 'active' : '' ]"
:class="[ current === 'stopped' ? 'active' : '' ]"
>
<i class="subnav-icon">
<mo-icon name="task-stop" width="20" height="20" />
+6 -6
View File
@@ -68,7 +68,7 @@
</el-input>
</el-form-item>
<div v-if="showAdvanced">
<el-form-item :label="`${$t('task.task-dir')}: `" :label-width="formLabelWidth">
<el-form-item :label="`${$t('task.task-user-agent')}: `" :label-width="formLabelWidth">
<el-input
type="textarea"
:autosize="{ minRows: 2, maxRows: 3 }"
@@ -156,7 +156,7 @@
},
data () {
return {
formLabelWidth: '75px',
formLabelWidth: '100px',
showAdvanced: false,
torrentName: '',
form: {},
@@ -227,7 +227,7 @@
// https://github.com/ElemeFE/element/blob/master/packages/input/src/input.vue
const { uris } = this.form
if (uris.includes('thunder://')) {
this.$message({
this.$msg({
type: 'warning',
message: this.$t('task.thunder-link-tip'),
duration: 6000
@@ -318,13 +318,13 @@
payload = this.buildUriPayload(form)
this.$store.dispatch('task/addUri', payload)
.catch((err) => {
this.$message.error(err.message)
this.$msg.error(err.message)
})
} else if (type === 'torrent') {
payload = this.buildTorrentPayload(form)
this.$store.dispatch('task/addTorrent', payload)
.catch((err) => {
this.$message.error(err.message)
this.$msg.error(err.message)
})
} else if (type === 'metalink') {
// @TODO addMetalink
@@ -382,7 +382,7 @@
}
})
.catch((err) => {
this.$message.error(err.message)
this.$msg.error(err.message)
})
})
}
+23 -4
View File
@@ -3,8 +3,11 @@
class="upload-torrent"
drag
action="/"
:limit="1"
:multiple="false"
accept=".torrent"
:on-change="handleChange"
:on-exceed="handleExceed"
:auto-upload="false"
:show-file-list="false">
<i class="upload-inbox-icon"><mo-icon name="inbox" width="24" height="24" /></i>
@@ -19,7 +22,7 @@
import { mapState } from 'vuex'
import parseTorrent from 'parse-torrent'
import '@/components/Icons/inbox'
import { getAsBase64 } from '@shared/utils'
import { getAsBase64, buildFileList } from '@shared/utils'
export default {
name: 'mo-select-torrent',
@@ -35,11 +38,18 @@
computed: {
...mapState('preference', {
config: state => state.config
}),
...mapState('app', {
torrents: state => state.addTaskTorrents
})
},
methods: {
handleChange (file, fileList) {
console.log('file===>', file)
watch: {
torrents (fileList) {
const file = fileList[0]
if (fileList.length === 0) {
this.name = ''
return
}
if (!file.raw) {
return
}
@@ -54,6 +64,15 @@
this.$emit('change', torrent, file, fileList)
})
}
},
methods: {
handleChange (file, fileList) {
this.$store.dispatch('app/addTaskAddTorrents', { fileList })
},
handleExceed (files) {
const fileList = buildFileList(files[0])
this.$store.dispatch('app/addTaskAddTorrents', { fileList })
}
}
}
</script>
+6 -8
View File
@@ -44,7 +44,6 @@
import '@/components/Icons/purge'
import '@/components/Icons/more'
import {
getTaskName,
bytesToSize,
timeFormat
} from '@shared/utils'
@@ -70,7 +69,6 @@
timeFormat
},
methods: {
getTaskName,
refreshSpin: function () {
this.t && clearTimeout(this.t)
@@ -86,33 +84,33 @@
onResumeAllClick: function () {
this.$store.dispatch('task/resumeAllTask')
.then(() => {
this.$message.success(this.$t('task.resume-all-task-success'))
this.$msg.success(this.$t('task.resume-all-task-success'))
})
.catch(({ code }) => {
if (code === 1) {
this.$message.error(this.$t('task.resume-all-task-fail'))
this.$msg.error(this.$t('task.resume-all-task-fail'))
}
})
},
onPauseAllClick: function () {
this.$store.dispatch('task/pauseAllTask')
.then(() => {
this.$message.success(this.$t('task.pause-all-task-success'))
this.$msg.success(this.$t('task.pause-all-task-success'))
})
.catch(({ code }) => {
if (code === 1) {
this.$message.error(this.$t('task.pause-all-task-fail'))
this.$msg.error(this.$t('task.pause-all-task-fail'))
}
})
},
onPurgeRecordClick: function () {
this.$store.dispatch('task/purgeTaskRecord')
.then(() => {
this.$message.success(this.$t('task.purge-record-success'))
this.$msg.success(this.$t('task.purge-record-success'))
})
.catch(({ code }) => {
if (code === 1) {
this.$message.error(this.$t('task.purge-record-fail'))
this.$msg.error(this.$t('task.purge-record-fail'))
}
})
}
+13 -5
View File
@@ -1,7 +1,7 @@
<template>
<li :key="task.gid" class="task-item" v-on:dblclick="onDbClick">
<div class="task-name" :title="taskName">
<span>{{ taskName }}</span>
<div class="task-name" :title="taskFullName">
<span>{{ taskFullName }}</span>
</div>
<mo-task-item-actions mode="LIST" :task="task" />
<div class="task-progress">
@@ -68,8 +68,16 @@
}
},
computed: {
taskFullName: function () {
return getTaskName(this.task, {
defaultName: this.$t('task.get-task-name'),
maxLen: -1
})
},
taskName: function () {
return getTaskName(this.task, this.$t('task.get-task-name'))
return getTaskName(this.task, {
defaultName: this.$t('task.get-task-name')
})
},
remaining: function () {
const { totalLength, completedLength, downloadSpeed } = this.task
@@ -81,7 +89,6 @@
timeFormat
},
methods: {
getTaskName,
onDbClick () {
const { status } = this.task
if (status === 'complete') {
@@ -92,7 +99,7 @@
},
openTask () {
const { taskName } = this
this.$message.info(this.$t('task.opening-task-message', { taskName }))
this.$msg.info(this.$t('task.opening-task-message', { taskName }))
const fullPath = getTaskFullPath(this.task)
openItem(fullPath, {
errorMsg: this.$t('task.file-not-exist')
@@ -126,6 +133,7 @@
color: #505753;
margin-bottom: 32px;
margin-right: 240px;
word-break: break-all;
&> span {
font-size: 14px;
line-height: 26px;
@@ -35,7 +35,7 @@
<script>
import is from 'electron-is'
import clipboard from 'clipboard-polyfill'
import * as clipboard from 'clipboard-polyfill'
import '@/components/Icons/task-start-line'
import '@/components/Icons/task-pause-line'
import '@/components/Icons/delete'
@@ -89,13 +89,13 @@
if (isRemoveWithFiles) {
this.deleteTaskFiles(task)
}
this.$message.success(this.$t('task.delete-task-success', {
this.$msg.success(this.$t('task.delete-task-success', {
taskName: this.taskName
}))
})
.catch(({ code }) => {
if (code === 1) {
this.$message.error(this.$t('task.delete-task-fail', {
this.$msg.error(this.$t('task.delete-task-fail', {
taskName: this.taskName
}))
}
@@ -107,13 +107,13 @@
if (isRemoveWithFiles) {
this.deleteTaskFiles(task)
}
this.$message.success(this.$t('task.remove-record-success', {
this.$msg.success(this.$t('task.remove-record-success', {
taskName: this.taskName
}))
})
.catch(({ code }) => {
if (code === 1) {
this.$message.error(this.$t('task.remove-record-fail', {
this.$msg.error(this.$t('task.remove-record-fail', {
taskName: this.taskName
}))
}
@@ -123,19 +123,19 @@
this.$store.dispatch('task/resumeTask', this.task)
.catch(({ code }) => {
if (code === 1) {
this.$message.error(this.$t('task.resume-task-fail', {
this.$msg.error(this.$t('task.resume-task-fail', {
taskName: this.taskName
}))
}
})
},
onPauseClick: function () {
const { taskName } = this
this.$msg.info(this.$t('task.download-pause-message', { taskName }))
this.$store.dispatch('task/pauseTask', this.task)
.catch(({ code }) => {
if (code === 1) {
this.$message.error(this.$t('task.pause-task-fail', {
taskName: this.taskName
}))
this.$msg.error(this.$t('task.pause-task-fail', { taskName }))
}
})
},
@@ -177,10 +177,14 @@
})
},
onLinkClick: function () {
const uri = getTaskUri(this.task)
clipboard.writeText(uri)
.then(() => {
this.$message.success(this.$t('task.copy-link-success'))
this.$store.dispatch('app/fetchEngineOptions')
.then((data) => {
const { btTracker } = data
const uri = getTaskUri(this.task, btTracker)
clipboard.writeText(uri)
.then(() => {
this.$msg.success(this.$t('task.copy-link-success'))
})
})
},
onInfoClick: function () {
+13 -7
View File
@@ -9,8 +9,8 @@
:before-close="handleClose"
@closed="handleClosed"
>
<div class="task-name" :title="taskName">
<span>{{ taskName }}</span>
<div class="task-name" :title="taskFullName">
<span>{{ taskFullName }}</span>
</div>
<mo-task-item-actions mode="ITEM" :task="task" />
<div class="task-progress">
@@ -78,13 +78,20 @@
}
},
computed: {
taskFullName: function () {
return getTaskName(this.task, {
defaultName: this.$t('task.get-task-name'),
maxLen: -1
})
},
taskName: function () {
return getTaskName(this.task, this.$t('task.get-task-name'))
return getTaskName(this.task, {
defaultName: this.$t('task.get-task-name'),
maxLen: 32
})
},
dialogTitle: function () {
const len = this.taskName.length
let title = len > 40 ? this.taskName.substr(0, 40) + '...' : this.taskName
return this.$t('task.task-info-dialog-title', { title })
return this.$t('task.task-info-dialog-title', { title: this.taskName })
},
remaining: function () {
const { totalLength, completedLength, downloadSpeed } = this.task
@@ -96,7 +103,6 @@
timeFormat
},
methods: {
getTaskName,
handleClose (done) {
this.$store.dispatch('task/hideTaskItemInfoDialog')
},
-10
View File
@@ -12,12 +12,6 @@
<script>
import { mapState } from 'vuex'
import TaskItem from './TaskItem'
import {
getTaskName,
bytesToSize,
timeRemaining,
timeFormat
} from '@shared/utils'
export default {
name: 'mo-task-list',
@@ -30,10 +24,6 @@
})
},
methods: {
getTaskName,
bytesToSize,
timeRemaining,
timeFormat
}
}
</script>
+6 -20
View File
@@ -21,26 +21,6 @@ img {
@include clearfix();
}
.title-bar {
position: fixed;
top: 0;
width: 100%;
height: 40px;
user-select: none;
-webkit-app-region: drag;
-webkit-user-select: none;
z-index: 5000;
&> .window-actions {
opacity: 0.4;
transition: $--fade-transition;
}
&:hover {
.window-actions {
opacity: 1;
}
}
}
#app,
#container {
height: 100%;
@@ -89,6 +69,11 @@ img {
outline: none;
}
.el-message__content {
line-height: 18px;
word-break: break-all;
}
.tab-title-dialog {
.el-dialog__header {
padding: 0 20px;
@@ -104,6 +89,7 @@ img {
.el-form-item--mini .el-form-item__info {
padding-top: 1px;
}
.el-form-item__info {
font-size: 12px;
line-height: 1;
+6 -1
View File
@@ -2,7 +2,7 @@ import is from 'electron-is'
import Vue from 'vue'
import VueI18Next from '@panter/vue-i18next'
import { sync } from 'vuex-router-sync'
import Element, { Loading } from 'element-ui'
import Element, { Loading, Message } from 'element-ui'
import axios from 'axios'
import 'svg-innerhtml'
@@ -11,6 +11,8 @@ import router from '@/router'
import store from '@/store'
import { getLocaleManager } from '@/components/Locale'
import Icon from '@/components/Icons/Icon'
import Msg from '@/components/Msg'
import '@/components/Theme/Index.scss'
function init (config) {
@@ -31,6 +33,9 @@ function init (config) {
size: 'mini',
i18n: (key, value) => i18n.t(key, value)
})
Vue.use(Msg, Message, {
showClose: true
})
const loading = Loading.service({
fullscreen: true,
+22 -1
View File
@@ -12,6 +12,7 @@ const state = {
version: '',
enabledFeatures: []
},
engineOptions: {},
interval: BASE_INTERVAL,
stat: {
downloadSpeed: 0,
@@ -21,7 +22,8 @@ const state = {
numWaiting: 0
},
addTaskVisible: false,
addTaskType: 'uri'
addTaskType: 'uri',
addTaskTorrents: []
}
const getters = {
@@ -34,6 +36,9 @@ const mutations = {
UPDATE_ENGINE_INFO (state, engineInfo) {
state.engineInfo = { ...state.engineInfo, ...engineInfo }
},
UPDATE_ENGINE_OPTIONS (state, engineOptions) {
state.engineOptions = { ...state.engineOptions, ...engineOptions }
},
UPDATE_GLOBAL_STAT (state, stat) {
state.stat = stat
},
@@ -43,6 +48,9 @@ const mutations = {
CHANGE_ADD_TASK_TYPE (state, taskType) {
state.addTaskType = taskType
},
CHANGE_ADD_TASK_TORRENTS (state, fileList) {
state.addTaskTorrents = [...fileList]
},
UPDATE_INTERVAL (state, millisecond) {
let interval = millisecond
if (millisecond > MAX_INTERVAL) {
@@ -81,6 +89,15 @@ const actions = {
commit('UPDATE_ENGINE_INFO', data)
})
},
fetchEngineOptions ({ commit }) {
return new Promise((resolve) => {
api.getGlobalOption()
.then((data) => {
commit('UPDATE_ENGINE_OPTIONS', data)
resolve(data)
})
})
},
fetchGlobalStat ({ commit, dispatch }) {
api.getGlobalStat()
.then((data) => {
@@ -121,10 +138,14 @@ const actions = {
},
hideAddTaskDialog ({ commit }) {
commit('CHANGE_ADD_TASK_VISIBLE', false)
commit('CHANGE_ADD_TASK_TORRENTS', [])
},
changeAddTaskType ({ commit }, taskType) {
commit('CHANGE_ADD_TASK_TYPE', taskType)
},
addTaskAddTorrents ({ commit }, { fileList }) {
commit('CHANGE_ADD_TASK_TORRENTS', fileList)
},
updateInterval ({ commit }, millisecond) {
commit('UPDATE_INTERVAL', millisecond)
},
+10 -7
View File
@@ -31,13 +31,13 @@ const actions = {
dispatch('fetchList')
},
fetchList ({ state, commit }) {
api.fetchTaskList({ type: state.currentList })
return api.fetchTaskList({ type: state.currentList })
.then((data) => {
commit('UPDATE_TASK_LIST', data)
})
},
fetchItem ({ dispatch }, gid) {
api.fetchTaskItem({ gid })
return api.fetchTaskItem({ gid })
.then((data) => {
dispatch('updateCurrentTaskItem', data)
})
@@ -75,13 +75,16 @@ const actions = {
},
removeTask ({ dispatch }, task) {
const { gid } = task
return api.removeTask({ gid })
.catch(() => {
return api.forceRemoveTask({ gid })
return api.forcePauseTask({ gid })
.catch((e) => {
console.log(`[Motrix] removeTask.forcePauseTask#[${gid}] fail`, e.message)
})
.finally(() => {
dispatch('fetchList')
dispatch('saveSession')
return api.removeTask({ gid })
.finally(() => {
dispatch('fetchList')
dispatch('saveSession')
})
})
},
pauseTask ({ dispatch }, task) {
+1
View File
@@ -1,6 +1,7 @@
{
"cmd-n": "application:new-task",
"cmd-shift-n": "application:new-bt-task",
"cmd-o": "application:open-file",
"cmd-,": "application:preferences",
"cmd-shift-p": "application:pause-all-task",
"cmd-shift-r": "application:resume-all-task"
+26
View File
@@ -0,0 +1,26 @@
import i18next from 'i18next'
import { getLanguage } from '@shared/locales'
export default class LocaleManager {
constructor (options = {}) {
this.options = options
i18next.init({
fallbackLng: 'en-US',
resources: options.resources
})
}
changeLanguage (lng) {
return i18next.changeLanguage(lng)
}
changeLanguageByLocale (locale) {
const lng = getLanguage(locale)
return this.changeLanguage(lng)
}
getI18n () {
return i18next
}
}
+41
View File
@@ -1,20 +1,61 @@
import eleLocaleDe from 'element-ui/lib/locale/lang/de'
import eleLocaleEn from 'element-ui/lib/locale/lang/en'
import eleLocaleFr from 'element-ui/lib/locale/lang/fr'
import eleLocalePtBR from 'element-ui/lib/locale/lang/pt-br'
import eleLocaleTr from 'element-ui/lib/locale/lang/tr-TR'
import eleLocaleZhCN from 'element-ui/lib/locale/lang/zh-CN'
import eleLocaleZhTW from 'element-ui/lib/locale/lang/zh-TW'
import appLocaleDe from '@shared/locales/de'
import appLocaleEnUS from '@shared/locales/en-US'
import appLocaleFr from '@shared/locales/fr'
import appLocalePtBR from '@shared/locales/pt-BR'
import appLocaleTr from '@shared/locales/tr'
import appLocaleZhCN from '@shared/locales/zh-CN'
import appLocaleZhTW from '@shared/locales/zh-TW'
// Please keep the locale key in alphabetical order.
const resources = {
'de': {
translation: {
...eleLocaleDe,
...appLocaleDe
}
},
'en-US': {
translation: {
...eleLocaleEn,
...appLocaleEnUS
}
},
'fr': {
translation: {
...eleLocaleFr,
...appLocaleFr
}
},
'pt-BR': {
translation: {
...eleLocalePtBR,
...appLocalePtBR
}
},
'tr': {
translation: {
...eleLocaleTr,
...appLocaleTr
}
},
'zh-CN': {
translation: {
...eleLocaleZhCN,
...appLocaleZhCN
}
},
'zh-TW': {
translation: {
...eleLocaleZhTW,
...appLocaleZhTW
}
}
}
+31
View File
@@ -1,16 +1,47 @@
import appLocaleDeDE from '@shared/locales/de'
import appLocaleEnUS from '@shared/locales/en-US'
import appLocaleFrFR from '@shared/locales/fr'
import appLocalePtBr from '@shared/locales/pt-BR'
import appLocaleTrTR from '@shared/locales/tr'
import appLocaleZhCN from '@shared/locales/zh-CN'
import appLocaleZhTW from '@shared/locales/zh-TW'
// Please keep the locale key in alphabetical order.
const resources = {
'de': {
translation: {
...appLocaleDeDE
}
},
'en-US': {
translation: {
...appLocaleEnUS
}
},
'fr': {
translation: {
...appLocaleFrFR
}
},
'pt-BR': {
translation: {
...appLocalePtBr
}
},
'tr': {
translation: {
...appLocaleTrTR
}
},
'zh-CN': {
translation: {
...appLocaleZhCN
}
},
'zh-TW': {
translation: {
...appLocaleZhTW
}
}
}
+6
View File
@@ -0,0 +1,6 @@
export default {
'engine-version': 'Engine Version',
'about': 'Über',
'release': 'Versionen',
'support': 'Unterstützung anfordern'
}
+30
View File
@@ -0,0 +1,30 @@
export default {
'task-list': 'Aufgabenliste',
'add-task': 'Aufgabe hinzufügen',
'about': 'Über Motrix',
'preferences': 'Präferenzen...',
'check-for-updates': 'Nach Updates suchen...',
'check-for-updates-title': 'Nach Updates suchen',
'update-available-message': 'Eine neue Version von Motrix ist verfügbar, jetzt aktualisieren?',
'update-not-available-message': 'Sie sind auf dem neuesten Stand!',
'update-downloaded-message': 'Bereit zur Installation...',
'update-error-message': 'Aktualisierungsfehler',
'engine-damaged-message': 'Der Motor ist beschädigt, bitte neu installieren : (',
'engine-missing-message': 'Der Motor fehlt, bitte neu installieren : (',
'system-error-title': 'Systemfehler',
'system-error-message': 'Die Anwendung konnte nicht gestartet werden: {{message}}',
'hide': 'Motrix verbergen',
'hide-others': 'Andere verbergen',
'unhide': 'Alles anzeigen',
'show': 'Motrix anzeigen',
'quit': 'Motrix beenden',
'under-development-message': 'Entschuldigung, diese Funktion befindet sich in der Entwicklung...',
'yes': 'Ja',
'no': 'Nein',
'cancel': 'Abbrechen',
'submit': 'Übernehmen',
'gt1d': '> 1 Tag',
'hour': 'h',
'minute': 'm',
'second': 's'
}
+9
View File
@@ -0,0 +1,9 @@
export default {
'undo': 'Rückgängig',
'redo': 'Wiederholen',
'cut': 'Ausschneiden',
'copy': 'Kopieren',
'paste': 'Einfügen',
'delete': 'Löschen',
'select-all': 'Alles auswählen'
}
+7
View File
@@ -0,0 +1,7 @@
export default {
'official-website': 'Motrix Website',
'manual': 'Handbuch',
'release-notes': 'Versionshinweise...',
'report-problem': 'Problem melden',
'toggle-dev-tools': 'Entwicklerwerkzeuge umschalten'
}
+21
View File
@@ -0,0 +1,21 @@
import about from './about'
import app from './app'
import edit from './edit'
import help from './help'
import menu from './menu'
import preferences from './preferences'
import subnav from './subnav'
import task from './task'
import window from './window'
export default {
about,
app,
edit,
help,
menu,
preferences,
subnav,
task,
window
}
+8
View File
@@ -0,0 +1,8 @@
export default {
'app': 'Motrix',
'file': 'Datei',
'task': 'Aufgabe',
'edit': 'Bearbeiten',
'window': 'Fenster',
'help': 'Hilfe'
}
+37
View File
@@ -0,0 +1,37 @@
export default {
'basic': 'Standard',
'advanced': 'Erweitert',
'lab': 'Experimentell',
'save': 'Speichern & übernehmen',
'discard': 'Verwerfen',
'startup': 'Startup',
'auto-resume-all': 'Alle nicht abgeschlossenen Aufgaben automatisch fortsetzen',
'default-dir': 'Standard Speicherort',
'mas-default-dir-tip': 'Aufgrund der Einschränkungen durch Sandbox-Berechtigungen im App Store wird der Download Ordner als Standard empfohlen',
'task-manage': 'Aufgaben verwalten',
'max-concurrent-downloads': 'Maximal aktive Aufgaben',
'max-connection-per-server': 'Maximale Verbindungen pro Server',
'new-task-show-downloading': 'Nach hinzufügen einer Aufgabe zu aktiven Downloads wechseln',
'continue': 'HTTPS/FTP Downloads fortsetzen wenn bereits angefangen',
'task-completed-notify': 'Benachrichtigung nach abgeschlossenen Download anzeigen',
'auto-purge-record': 'Download Protokoll beim Schließen der App löschen',
'ui': 'UI',
'language': 'Sprache',
'change-language': 'Sprache ändern',
'hide-app-menu': 'App Menü ausblenden (nur auf Windows & Linux)',
'proxy': 'Proxy',
'use-proxy': 'Proxy aktivieren',
'developer': 'Entwickler',
'mock-user-agent': 'User-Agent simulieren',
'app-log-path': 'Appprotokollpfad',
'download-session-path': 'Downloadsitzungspfad',
'factory-reset': 'Werkseinstellungen',
'factory-reset-confirm': 'Sollen die Einstellungen auf die Werkseinstellungen unwiderruflich zurückgesetzt werden?',
'lab-warning': '⚠️ Die Aktivierung von experimentellen Funktionen kann zu App-Abstürzen oder Datenverlust führen!',
'download-protocol': 'Protokoll',
'support-more-download-protocols': 'Erweiterte Protokollunterstützung aktivieren',
'browser-extensions': 'Erweiterungen',
'baidu-exporter': 'Baidu Exporter',
'browser-extensions-tip': 'Von der Community bereitgestellt, ',
'baidu-exporter-help': 'mehr über die Verwendung zu erfahren'
}
+4
View File
@@ -0,0 +1,4 @@
export default {
'task-list': 'Aufgaben',
'preferences': 'Präferenzen'
}
+79
View File
@@ -0,0 +1,79 @@
export default {
'active': 'Aktiv',
'waiting': 'Warteschlange',
'stopped': 'Gestoppt',
'new-task': 'Neue Aufgabe',
'new-bt-task': 'Neue BT Aufgabe',
'open-file': 'Torrent-Datei öffnen...',
'uri-task': 'URL',
'torrent-task': 'Torrent',
'uri-task-tip': 'Eine Download URL pro Zeile (magnet wird unterstützt)',
'thunder-link-tip': 'Tipp: Thunder Links werden möglicherweise nach dem dekodieren nicht heruntergeladen',
'task-name': 'Aufgaben Name',
'task-out': 'Umbenennen',
'task-out-tip': 'Optional, unterstützt nur Einzelaufgaben',
'task-split': 'Splits',
'task-dir': 'Ordner',
'pause-task': 'Aufgabe pausieren',
'task-ua': 'UA',
'task-user-agent': 'User-Agent',
'task-referer': 'Referer',
'task-cookie': 'Cookie',
'navigate-to-downloading': 'Navigiere zu aktive Downloads',
'show-advanced-options': 'Erweiterte Optionen',
'copyright-warning': 'Copyright Warnung',
'copyright-warning-message': 'Die Datei, die Sie herunterladen möchten, könnte unter Copyright stehen. Bitte überprüfen Sie ob Sie in Besitz der notwendigen Lizenz sind.',
'copyright-yes': 'Ja, Ich habe',
'copyright-no': 'Nein',
'copyright-error-message': 'Aufgabe konnte Aufgrund von Copyright Problemen nicht hinzugefügt werden',
'pause-task-success': 'Aufgabe "{{taskName}}" erfolgreich pausiert',
'pause-task-fail': 'Aufgabe "{{taskName}}" pausieren fehlgeschlagen',
'resume-task': 'Aufgabe fortsetzen',
'resume-task-success': 'Aufgabe "{{taskName}}" erfolgreich fortgesetzt',
'resume-task-fail': 'Aufgabe "{{taskName}}" fortsetzen ist fehlgschlagen',
'delete-task': 'Aufgabe löschen',
'delete-selected-tasks': 'Ausgewählte Aufgaben löschen',
'delete-task-confirm': 'Den Download von "{{taskName}}" unwiederruflich löschen?',
'delete-task-label': 'Datei auch löschen',
'delete-task-success': 'Aufgabe "{{taskName}}" erfolgreich gelöscht',
'delete-task-fail': 'Aufgabe "{{taskName}}" löschen fehlgeschlagen',
'remove-task-file-fail': 'Aufgaben Datei löschen fehlgeschlagen, bitte manuell löschen',
'remove-task-config-file-fail': 'Aufgaben Konfigurationsdatei löschen fehlgeschlagen, bitte manuell löschen',
'move-task-up': 'Aufgabe nach oben verschieben',
'move-task-down': 'Aufgabe nach unten verschieben',
'pause-all-task': 'Alle Aufgaben pausieren',
'pause-all-task-success': 'Alle Aufgaben erfolgreich pausiert',
'pause-all-task-fail': 'Die Aufgaben konnten nicht pausiert werden',
'resume-all-task': 'Alle Aufgaben fortsetzen',
'resume-all-task-success': 'Alle Aufgaben erfolgreich fortgesetzt',
'resume-all-task-fail': 'Fortsetzen aller Aufgaben fehlgeschlagen',
'clear-recent-tasks': 'Letzte Aufgaben entfernen',
'purge-record': 'Aufgaben Protokoll löschen',
'purge-record-success': 'Aufgabenprotokoll erfolgreich gelöscht',
'purge-record-fail': 'Aufgabenprotokoll konnte nicht gelöscht werden',
'refresh-list': 'Aufgabenliste aktualisieren',
'no-task': 'Keine Downloads aktiv',
'copy-link': 'Link kopieren',
'copy-link-success': 'Link erfolgreich kopiert',
'remove-record': 'Aufgaben Aufzeichnung löschen',
'remove-record-confirm': 'Soll die Aufzeichnung von "{{taskName}}" gelöscht werden?',
'remove-record-label': 'Datei auch löschen',
'remove-record-success': 'Aufzeichnung von "{{taskName}}" erfolgreich gelöscht',
'remove-record-fail': 'Aufzeichnung von "{{taskName}}" konnte nicht gelöscht werden',
'show-in-folder': 'Aufgabe in Ordner anzeigen',
'file-not-exist': 'Datei existiert nicht oder wurde gelöscht',
'file-path-error': 'Dateipfadfehler',
'opening-task-message': 'Öffne "{{taskName}}" ...',
'get-task-name': 'Aufgabenbezeichnung bekommen...',
'remaining-prefix': 'Verbleibend',
'select-torrent': 'Torrent mit Drag & Drop hinzufügen, oder klicken um auszuwählen',
'task-info-dialog-title': '{{title}} Details',
'download-start-message': 'Starte Download von {{taskName}}',
'download-pause-message': 'Pausiere Download von {{taskName}}',
'download-stop-message': 'Download von {{taskName}} gestoppt',
'download-error-message': 'Fehler beim Download von {{taskName}} aufgetreten',
'download-complete-message': 'Download von {{taskName}} abgeschlossen',
'download-complete-notify': 'Download abgeschlossen',
'download-fail-message': 'Download von {{taskName}} fehlgeschlagen',
'download-fail-notify': 'Download fehlgeschlagen'
}
+8
View File
@@ -0,0 +1,8 @@
export default {
'reload': 'Neu laden',
'close': 'Schließen',
'minimize': 'Minimieren',
'zoom': 'Zoomen',
'toggle-fullscreen': 'Vollbildmodus aktivieren',
'front': 'Alles in den Vordergrund bringen'
}
+11 -1
View File
@@ -4,9 +4,19 @@ export default {
'about': 'About Motrix',
'preferences': 'Preferences...',
'check-for-updates': 'Check for Updates...',
'check-for-updates-title': 'Check for Updates',
'update-available-message': 'A new version of Motrix is available, update now?',
'update-not-available-message': 'You are up-to-date!',
'update-downloaded-message': 'Ready to install...',
'update-error-message': 'Update Error',
'engine-damaged-message': 'The engine is damaged, please reinstall : (',
'engine-missing-message': 'The engine is missing, please reinstall : (',
'system-error-title': 'System Error',
'system-error-message': 'Application startup failed: {{message}}',
'hide': 'Hide Motrix',
'hide-others': 'Hide Others',
'unhide': 'Show All',
'show': 'Show Motrix',
'quit': 'Quit Motrix',
'under-development-message': 'Sorry, this feature is under development...',
'yes': 'Yes',
@@ -14,7 +24,7 @@ export default {
'cancel': 'Cancel',
'submit': 'Submit',
'gt1d': '> 1 day',
'hour': 'H',
'hour': 'h',
'minute': 'm',
'second': 's'
}
+9 -9
View File
@@ -1,21 +1,21 @@
import about from './about'
import app from './app'
// import edit from './edit'
// import help from './help'
// import menu from './menu'
import edit from './edit'
import help from './help'
import menu from './menu'
import preferences from './preferences'
import subnav from './subnav'
import task from './task'
// import window from './window'
import window from './window'
export default {
about,
app,
// edit,
// help,
// menu,
edit,
help,
menu,
preferences,
subnav,
task
// window
task,
window
}
+1
View File
@@ -26,6 +26,7 @@ export default {
'app-log-path': 'App log path',
'download-session-path': 'Download session path',
'factory-reset': 'Factory Reset',
'factory-reset-confirm': 'Are you sure you want to revert to factory settings?',
'lab-warning': '⚠️ Enabling lab features may cause app crashes or data loss, decide for yourself!',
'download-protocol': 'Protocol',
'support-more-download-protocols': 'Enable more download protocols support',
+1
View File
@@ -4,6 +4,7 @@ export default {
'stopped': 'Stopped',
'new-task': 'New Task',
'new-bt-task': 'New BT Task',
'open-file': 'Open Torrent File...',
'uri-task': 'URL',
'torrent-task': 'Torrent',
'uri-task-tip': 'One task url per line (support magnet)',
+6
View File
@@ -0,0 +1,6 @@
export default {
'engine-version': 'Version du moteur',
'about': 'À Propos',
'release': 'Release',
'support': 'Support'
}
+30
View File
@@ -0,0 +1,30 @@
export default {
'task-list': 'Liste des tâches',
'add-task': 'Ajouter une tâche',
'about': 'À Propos de Motrix',
'preferences': 'Préférences...',
'check-for-updates': 'Vérifier les mises à jour...',
'check-for-updates-title': 'Vérifier les mises à jour',
'update-available-message': 'Une nouvelle version de Motrix est disponible, mise à jour maintenant?',
'update-not-available-message': 'Vous êtes à jour!',
'update-downloaded-message': 'Prêt à installer...',
'update-error-message': 'Erreur de mise à jour',
'engine-damaged-message': 'Le moteur est endommagé, veuillez réinstaller : (',
'engine-missing-message': 'Le moteur est manquant, veuillez réinstaller : (',
'system-error-title': 'Erreur système',
'system-error-message': 'L\'application n\'a pas pu démarrer: {{message}}',
'hide': 'Cacher Motrix',
'hide-others': 'Cacher les autres',
'unhide': 'Tout montrer',
'show': 'Montrer Motrix',
'quit': 'Quitter Motrix',
'under-development-message': 'Désolé, cette fonctionnalité est en cours de développement...',
'yes': 'Oui',
'no': 'Non',
'cancel': 'Annuler',
'submit': 'Envoyer',
'gt1d': '> 1 jour',
'hour': 'h',
'minute': 'm',
'second': 's'
}
+9
View File
@@ -0,0 +1,9 @@
export default {
'undo': 'Annuler la dernière action',
'redo': 'Rétablir la dernière action',
'cut': 'Couper',
'copy': 'Copier',
'paste': 'Coller',
'delete': 'Supprimer',
'select-all': 'Tout sélectionner'
}
+7
View File
@@ -0,0 +1,7 @@
export default {
'official-website': 'Site web de Motrix ',
'manual': 'Manuel',
'release-notes': 'Notes de version...',
'report-problem': 'Signaler un problème',
'toggle-dev-tools': 'Activer les outils pour développeurs'
}
+21
View File
@@ -0,0 +1,21 @@
import about from './about'
import app from './app'
import edit from './edit'
import help from './help'
import menu from './menu'
import preferences from './preferences'
import subnav from './subnav'
import task from './task'
import window from './window'
export default {
about,
app,
edit,
help,
menu,
preferences,
subnav,
task,
window
}
+8
View File
@@ -0,0 +1,8 @@
export default {
'app': 'Motrix',
'file': 'Fichier',
'task': 'Tâche',
'edit': 'Editer',
'window': 'Fenêtre',
'help': 'Aide'
}
+37
View File
@@ -0,0 +1,37 @@
export default {
'basic': 'Basique',
'advanced': 'Avancé',
'lab': 'Labo',
'save': 'Sauver et appliquer',
'discard': 'Annuler les changement',
'startup': 'Démarrage',
'auto-resume-all': 'Reprendre les tâches non terminées',
'default-dir': 'Répertoire par défaut',
'mas-default-dir-tip': 'En raison des restrictions d\'autorisations du bac à sable de l\'App Store, il est recommandé de définir le répertoire de téléchargement par défaut sur le répertoire Téléchargements.',
'task-manage': 'Tâches',
'max-concurrent-downloads': 'Nombre de tâches active au maximum',
'max-connection-per-server': 'Nombre maximum de connexions par serveurs',
'new-task-show-downloading': 'Montrer automatiquement les téléchargements après l\'ajout d\'une tâche',
'continue': 'Continuer',
'task-completed-notify': 'Notifier à la fin d\'un téléchargement',
'auto-purge-record': 'Purger l\'historique de téléchargement lorsque vous quittez l\'application',
'ui': 'UI',
'language': 'Langues',
'change-language': 'Changer la langue',
'hide-app-menu': 'Cacher le menu de l\'application (Windows & Linux uniquement)',
'proxy': 'Proxy',
'use-proxy': 'Activer le Proxy',
'developer': 'Développeur',
'mock-user-agent': 'Mock User-Agent',
'app-log-path': 'Chemin des logs',
'download-session-path': 'Chemin de la session de téléchargement',
'factory-reset': 'Réinitialisation',
'factory-reset-confirm': 'Êtes vous sûr de vouloir réinitialiser les paramètres',
'lab-warning': '⚠️ Activer les fonctionalités labo peut causer des crash ou la perte de données !',
'download-protocol': 'Protocole',
'support-more-download-protocols': 'Activer les protocoles de téléchargement suplémentaires',
'browser-extensions': 'Extensions',
'baidu-exporter': 'BaiduExporter',
'browser-extensions-tip': 'Fourni par la communauté, ',
'baidu-exporter-help': 'Cliquez ici pour voir l\'utilisation'
}
+4
View File
@@ -0,0 +1,4 @@
export default {
'task-list': 'Tâches',
'preferences': 'Préférences'
}
+79
View File
@@ -0,0 +1,79 @@
export default {
'active': 'Actives',
'waiting': 'En attente',
'stopped': 'Stopées',
'new-task': 'Nouvelle Tâche',
'new-bt-task': 'Nouvelle Tâche BT',
'open-file': 'Ouvrir un fichier torrent...',
'uri-task': 'Lien',
'torrent-task': 'Torrent',
'uri-task-tip': 'Un lien par ligne (supporte les magnets)',
'thunder-link-tip': 'Astuce: Les liens Thunder ne doivent pas être téléchargés après décodage',
'task-name': 'Nom de la tâche',
'task-out': 'Renommer',
'task-out-tip': 'Optionel, supporte une seule tâche',
'task-split': 'Découpages',
'task-dir': 'Répertoire',
'pause-task': 'Mettre en Pause',
'task-ua': 'UA',
'task-user-agent': 'User-Agent',
'task-referer': 'Référent',
'task-cookie': 'Cookie',
'navigate-to-downloading': 'Aller au Téléchargement',
'show-advanced-options': 'Options Avancées',
'copyright-warning': 'Avertissement Copyright',
'copyright-warning-message': 'Le fichier que vous voulez télécharger peut être une vidéo ou de l\'audio soumie aux copyright, verifiez que vous possédez bien sa license.',
'copyright-yes': 'Oui, je l\'ai',
'copyright-no': 'Non',
'copyright-error-message': 'Ajout de la tâche annulé, pas de copyright',
'pause-task-success': 'Mise en pause de "{{taskName}}" avec succés',
'pause-task-fail': 'Mise en pause de "{{taskName}}" échouée',
'resume-task': 'Reprendre',
'resume-task-success': 'Reprise de "{{taskName}}" avec succés',
'resume-task-fail': 'Reprise de "{{taskName}}" échouée',
'delete-task': 'Supprimer',
'delete-selected-tasks': 'Supprimer la séléction',
'delete-task-confirm': 'Étes vous sûr de vouloir supprimer "{{taskName}}" ?',
'delete-task-label': 'Supprimer avec les fichiers',
'delete-task-success': 'Suppression de "{{taskName}}" avec succés',
'delete-task-fail': 'Suppression de "{{taskName}}" échouée',
'remove-task-file-fail': 'Impossible de supprimer la tâche, s\'il vous plait supprimez la manuellement',
'remove-task-config-file-fail': 'Impossible de supprimer le fichier de configuration de la tâche, s\'il vous plait supprimez le manuellement',
'move-task-up': 'Déplacer vers le haut',
'move-task-down': 'Déplacer vers le bas',
'pause-all-task': 'Tout mettre en pause',
'pause-all-task-success': 'Mise en pause réussie',
'pause-all-task-fail': 'Mise en pause échouée',
'resume-all-task': 'Tout reprendre',
'resume-all-task-success': 'Reprise réussie',
'resume-all-task-fail': 'Reprise échouée',
'clear-recent-tasks': 'Effacer les tâches récentes',
'purge-record': 'Purger les tâches récentes',
'purge-record-success': 'Purge des tâches récentes réussie',
'purge-record-fail': 'Purge des tâches récentes échouée',
'refresh-list': 'Rafraichir la liste des tâches',
'no-task': 'Aucun téléchargement en cours',
'copy-link': 'Copier le lien',
'copy-link-success': 'Lien copié',
'remove-record': 'Effacer l\'enregistrement des tâches',
'remove-record-confirm': 'Étes vous sûr de vouloir effacer "{{taskName}}" ?',
'remove-record-label': 'Supprimer avec les fichiers',
'remove-record-success': '"{{taskName}}" éffacée',
'remove-record-fail': '"{{taskName}}" n\'a pas été éffacée',
'show-in-folder': 'Montrer la tâche dans le dossier',
'file-not-exist': 'Le fichier n\'existe pas ou a été supprimé',
'file-path-error': 'Erreur de lien sur le fichier',
'opening-task-message': 'Ouverture de "{{taskName}}" ...',
'get-task-name': 'Récupération du nom de la tâche...',
'remaining-prefix': 'Restant',
'select-torrent': 'Glissez-déposez un torrent ici, ou cliquez pour en choisir un',
'task-info-dialog-title': '{{title}} Details',
'download-start-message': 'Téléchargment de {{taskName}}',
'download-pause-message': 'Mise en pause de {{taskName}}',
'download-stop-message': '{{taskName}} téléchargment arrété',
'download-error-message': '{{taskName}} une erreur c\'est produite',
'download-complete-message': '{{taskName}} téléchargement terminé',
'download-complete-notify': 'Téléchargement Terminé',
'download-fail-message': '{{taskName}} téléchargement échoué',
'download-fail-notify': 'Téléchargement Échoué'
}
+8
View File
@@ -0,0 +1,8 @@
export default {
'reload': 'Recharger',
'close': 'Fermer',
'minimize': 'Réduire',
'zoom': 'Zoom',
'toggle-fullscreen': 'Passer en mode Plein écran',
'front': 'Tout mettre au premier plan'
}
+53 -7
View File
@@ -1,28 +1,74 @@
/**
* If you want to contribute translation, please add a 'locale' here.
* For the value of locale, please refer to the link below.
* https://electronjs.org/docs/api/locales
* Welcome to translate to more versions in other languages.
* Please read the translation guide before starting work.
* https://github.com/agalwood/Motrix/blob/master/CONTRIBUTING.md#-translation-guide
*
* Please keep the locale key in alphabetical order.
*/
export const supportLanguages = [
'en-US',
'zh-CN'
export const availableLanguages = [
{
value: 'de',
label: 'Deutsch'
},
{
value: 'en-US',
label: 'English'
},
{
value: 'fr',
label: 'Français'
},
{
value: 'pt-BR',
label: 'Português (Brasil)'
},
{
value: 'tr',
label: 'Türkçe'
},
{
value: 'zh-CN',
label: '简体中文'
},
{
value: 'zh-TW',
label: '繁體中文'
}
]
function checkLngIsAvailable (locale) {
return availableLanguages.some((lng) => lng.value === locale)
}
/**
* getLanguage
* @param { String } locale
* https://electronjs.org/docs/api/locales
*/
export function getLanguage (locale = 'en-US') {
if (supportLanguages.includes(locale)) {
if (checkLngIsAvailable(locale)) {
return locale
}
if (locale.startsWith('de')) {
return 'de'
}
if (locale.startsWith('en')) {
return 'en-US'
}
// If there is a pt-PT translation in the future,
// here will fallback to pt-PT.
if (locale.startsWith('pt')) {
return 'pt-BR'
}
if (locale.startsWith('zh')) {
return 'zh-CN'
}
if (locale.startsWith('fr')) {
return 'fr'
}
}
+6
View File
@@ -0,0 +1,6 @@
export default {
'engine-version': 'Versão da Engine',
'about': 'Sobre',
'release': 'Release',
'support': 'Suporte'
}
+30
View File
@@ -0,0 +1,30 @@
export default {
'task-list': 'Lista de Tarefas',
'add-task': 'Adicionar Tarefa',
'about': 'Sobre o Motrix',
'preferences': 'Preferências...',
'check-for-updates': 'Verificar por Atualizações...',
'check-for-updates-title': 'Verificar por Atualizações',
'update-available-message': 'Uma nova versão do Motrix está disponível, atualize agora?',
'update-not-available-message': 'Você esta atualizado!',
'update-downloaded-message': 'Pronto para instalar...',
'update-error-message': 'Atualizar erro',
'engine-damaged-message': 'O motor está danificado, por favor, reinstale : (',
'engine-missing-message': 'O motor está faltando, por favor, reinstale : (',
'system-error-title': 'Erro do sistema',
'system-error-message': 'O aplicativo falhou ao iniciar: {{message}}',
'hide': 'Ocultar Motrix',
'hide-others': 'Ocultar Outros',
'unhide': 'Exibir Todos',
'show': 'Exibir Motrix',
'quit': 'Sair do Motrix',
'under-development-message': 'Desculpe, essa funcionalidade está em desenvolvimento...',
'yes': 'Sim',
'no': 'Não',
'cancel': 'Cancelar',
'submit': 'Enviar',
'gt1d': '> 1 dia',
'hour': 'h',
'minute': 'm',
'second': 's'
}
+9
View File
@@ -0,0 +1,9 @@
export default {
'undo': 'Desfazer',
'redo': 'Refazer',
'cut': 'Recortar',
'copy': 'Copiar',
'paste': 'Copiar',
'delete': 'Apagar',
'select-all': 'Selecionar Tudo'
}
+7
View File
@@ -0,0 +1,7 @@
export default {
'official-website': 'Motrix Website',
'manual': 'Manual',
'release-notes': 'Notas de Lançamento...',
'report-problem': 'Reportar um Problema',
'toggle-dev-tools': 'Alternar Developer Tools'
}
+21
View File
@@ -0,0 +1,21 @@
import about from './about'
import app from './app'
import edit from './edit'
import help from './help'
import menu from './menu'
import preferences from './preferences'
import subnav from './subnav'
import task from './task'
import window from './window'
export default {
about,
app,
edit,
help,
menu,
preferences,
subnav,
task,
window
}

Some files were not shown because too many files have changed in this diff Show More