Compare commits

..

670 Commits

Author SHA1 Message Date
Dr_rOot e579146260 fix: select dropdown dark style 2023-05-19 23:31:35 +08:00
Dr_rOot 9d18333a93 feat: adjust task dialog top when show advanced 2023-05-19 23:30:04 +08:00
Dr_rOot 5daece6dab feat: task file filter add document extensions 2023-05-19 23:26:31 +08:00
Dr_rOot 8bfb7d906e chore: adjust icon template and size (#1486) 2023-05-13 14:13:50 +08:00
Dr_rOot f4ece13ceb Merge pull request #1485 from agalwood/hotfix/portable_20230511
fix: move some config files to make the target really portable
2023-05-11 22:39:48 +08:00
Dr_rOot 763ea6ee7a chore: update deps 2023-05-11 21:53:58 +08:00
Dr_rOot cc27cb3459 refactor: convert to arrow function 2023-05-11 21:40:07 +08:00
Dr_rOot b8c57df4f5 refactor: portable config file base dir 2023-05-11 21:39:35 +08:00
Dr_rOot e6765380bc fix: increase the rpc secret length limit to 64 (#1482) 2023-05-09 22:24:39 +08:00
Dr_rOot 0172a003d3 Merge pull request #1480 from agalwood/feature/task_detail_20230506
feat: protocol add motrix://reveal-in-folder
2023-05-07 22:20:49 +08:00
Dr_rOot ef2b3a04b2 refactor: show item in folder util 2023-05-07 21:25:45 +08:00
Dr_rOot 75f5760b33 chore: update deps 2023-05-06 18:16:14 +08:00
Dr_rOot 1f033d1e47 refactor: code format 2023-05-06 18:16:05 +08:00
Dr_rOot 458e21479b feat: motrix://reveal-in-folder 2023-05-06 18:09:29 +08:00
Dr_rOot 46e5324ae6 refactor: system config rpc listen port 2023-05-06 18:06:49 +08:00
Dr_rOot de8996b3b3 feat: show task gid on task detail general 2023-05-06 18:01:31 +08:00
Dr_rOot 1f83848358 fix: object has been destroyed 2023-05-05 18:14:32 +08:00
Dr_rOot 69d3ade305 docs: readme macOS add Motrix Install Assistant 2023-05-03 16:20:33 +08:00
Dr_rOot a0a1fe90f7 chore: update yarn lock & bump version to 1.8.18 2023-05-03 14:44:33 +08:00
Dr_rOot 553bf80960 chore: bump version to 1.8.18 2023-05-03 13:50:33 +08:00
Dr_rOot 04446b582e Merge pull request #1472 from agalwood/hotfix/bt_auto_download_20230503
fix: btAutoDownloadContent boolean is inverted
2023-05-03 13:49:14 +08:00
Dr_rOot f10f4a2588 fix: btAutoDownloadContent boolean is inverted 2023-05-03 13:46:07 +08:00
Dr_rOot 513f566a59 chore: bump version to 1.8.17 2023-05-02 18:08:49 +08:00
Dr_rOot f49f083044 fix: update-downloaded set progress bar value to 1 2023-05-02 18:06:44 +08:00
Dr_rOot 830bc9336e chore: bump version to 1.8.16 2023-05-02 17:35:14 +08:00
Dr_rOot 3b049219e4 chore: update deps 2023-05-02 17:33:51 +08:00
Dr_rOot bbc68b6a8a chore: github action remove notarization api key 2023-05-02 17:33:22 +08:00
Dr_rOot 0afc01080d fix: preference save relaunch application twice 2023-04-29 11:26:26 +08:00
Dr_rOot af1cc4db8e chore: bump version to 1.8.15 2023-04-28 22:54:29 +08:00
Dr_rOot 8defa9ee71 Merge pull request #1466 from agalwood/hotfix/aria2_x64_20230428
fix: rebuild darwin x64 aria2c bin
2023-04-28 22:51:56 +08:00
Dr_rOot cb6d9f2b20 chore: change node mini version to 16 2023-04-28 22:50:01 +08:00
Dr_rOot 9f6c31ffa3 fix: rebuild darwin x64 aria2c bin 2023-04-28 22:49:10 +08:00
greenhandzdl 0b3161ca6f docs: fix yay install script (#1465)
* Fix Doc
2023-04-28 22:39:06 +08:00
Dr_rOot c79bdff4b8 Merge pull request #1464 from agalwood/hotfix/aria2_arm64_20230428
fix: rebuild arm64 aria2c bin
2023-04-28 18:45:00 +08:00
Dr_rOot b92957668b chore: update deps 2023-04-28 18:19:57 +08:00
Dr_rOot b1b52e2640 fix: rebuild arm64 aria2c bin 2023-04-28 18:16:01 +08:00
Dr_rOot a39fa2979c chore: bump version to 1.8.14 2023-04-27 17:49:04 +08:00
Dr_rOot e0a74f7979 fix: selected task item border color in dark mode 2023-04-27 17:47:59 +08:00
Dr_rOot a7b8333710 chore: bump version to 1.8.13 2023-04-27 17:08:14 +08:00
Dr_rOot 77850da0fe Merge pull request #1455 from agalwood/hotfix/auto_update_20230427
fix: app auto update failed
2023-04-27 17:06:53 +08:00
Dr_rOot 71f4eeeb25 chore: change app update generic url 2023-04-27 16:51:28 +08:00
Dr_rOot e5eace479d fix: handle auto updater update canceled event 2023-04-27 16:51:06 +08:00
Dr_rOot 7e927fea10 chore: bump version to 1.8.12 2023-04-27 11:11:34 +08:00
Dr_rOot 38cd952b44 Merge pull request #1453 from agalwood/hotfix/stop_engine_20230427
fix: stop engine failed when app quit
2023-04-27 11:10:23 +08:00
Dr_rOot b07fedeba0 chore: electron build mac target add universal 2023-04-27 10:54:38 +08:00
Dr_rOot 2bbaae5d7d feat: preference advanced add log level setting 2023-04-27 10:53:27 +08:00
Dr_rOot 003e9ffccb fix: stop engine failed when app quit 2023-04-27 10:23:08 +08:00
Dr_rOot 7a51dbaf5e chore: update bug report issue template 2023-04-27 08:00:07 +08:00
Dr_rOot 4fa4878e61 fix: appx for ms store & bump version to 1.8.11 2023-04-26 21:14:33 +08:00
Dr_rOot daa04d995e fix: publisher for ms store & bump version to 1.8.10 2023-04-26 20:59:50 +08:00
Dr_rOot 74e4bce6bf fix: identity for ms store & bump version to 1.8.9 2023-04-26 20:55:29 +08:00
Dr_rOot a0aa100a99 fix: author for ms store & bump version to 1.8.8 2023-04-26 20:08:53 +08:00
Dr_rOot 4c3b248cc0 chore: bump version to 1.8.7 2023-04-26 18:59:56 +08:00
Dr_rOot 96d525832f fix: github action SNAPCRAFT_STORE_CREDENTIALS 2023-04-26 18:59:34 +08:00
Dr_rOot 9255c95ecc chore: bump version to 1.8.6 2023-04-26 18:31:00 +08:00
Dr_rOot e117d5925a fix: notarize apple id password 2023-04-26 18:29:35 +08:00
Dr_rOot 6a5d7637c2 chore: bump version to 1.8.5 2023-04-26 18:22:19 +08:00
Dr_rOot 93e8bdff00 chore: notarize tool 2023-04-26 18:21:55 +08:00
Dr_rOot a82afbf97b chore: bump version to 1.8.4 2023-04-26 17:48:52 +08:00
Dr_rOot e1363d3fe2 fix: electron build notarization tool 2023-04-26 17:48:43 +08:00
Dr_rOot 1338861dc3 chore: bump version to 1.8.3 2023-04-26 17:34:32 +08:00
Dr_rOot b9068559e2 refactor: electron build notarization 2023-04-26 17:34:07 +08:00
Dr_rOot b7ed072966 chore: bump version to 1.8.2 2023-04-26 16:56:36 +08:00
Dr_rOot e281b71d4e refactor: github electron build action 2023-04-26 16:56:21 +08:00
Dr_rOot 67d26e4b1f chore: bump version to 1.8.1 2023-04-26 16:01:41 +08:00
Dr_rOot 1b27980992 Merge pull request #1445 from agalwood/feature/show_progess_bar_20230426
feat: preference basic show progress bar
2023-04-26 15:04:08 +08:00
Dr_rOot 292ad15152 chore: update deps 2023-04-26 13:27:39 +08:00
Dr_rOot df1b30d6f4 chore: sign darwin aria2c bin 2023-04-26 13:27:31 +08:00
Dr_rOot 0d3aa86d31 chore: i18n show progress bar 2023-04-26 13:27:04 +08:00
Dr_rOot a07f81e20c feat: preference basic show progress bar 2023-04-26 13:26:47 +08:00
Dr_rOot 61365d738c chore: lint fix after sign hook js 2023-04-26 10:53:17 +08:00
Dr_rOot 33f13b51b0 fix: electron builder win targets artifact name 2023-04-25 11:35:07 +08:00
Dr_rOot 2bda3b40eb fix: github action snapcraft token env (#1441) 2023-04-24 21:14:20 +08:00
Dr_rOot e456ba660b Merge pull request #1440 from agalwood/feature/aria2_conf_path_20230423 2023-04-23 19:41:57 +08:00
Dr_rOot 342b2b2069 chore: aria2 max-overall-upload-limit default 0 2023-04-23 18:17:55 +08:00
Dr_rOot 91697aee42 chore: i18n aria2 conf path 2023-04-23 18:17:03 +08:00
Dr_rOot f4e56ca4b7 feat: preference advanced show aria2 conf path 2023-04-23 18:16:44 +08:00
Dr_rOot 363cef2959 Merge pull request #1439 from agalwood/feature/appx_20230421
feat: build output add windows appx
2023-04-21 21:19:57 +08:00
Dr_rOot e938f30377 chore: rename appId avoid linux .desktop 2023-04-21 21:02:24 +08:00
Dr_rOot ed622ade1f chore: build output add windows appx 2023-04-21 21:01:13 +08:00
Dr_rOot 06f0ccf2e5 Merge pull request #1436 from agalwood/feature/rpc_listen_port_20230419
feat: preference advanced config rpc listen port
2023-04-19 21:55:15 +08:00
Dr_rOot 6885da1b86 feat: linux build add mime types 2023-04-19 18:14:42 +08:00
Dr_rOot 3ffce0566b feat: task detail files show completed percent 2023-04-19 18:14:16 +08:00
Dr_rOot a215df0360 feat: preference advanced config rpc listen port 2023-04-19 18:13:22 +08:00
Dr_rOot 6bea4322c1 chore: upgrade electron builder action (#1435) 2023-04-18 10:45:52 +08:00
Dr_rOot 493df2b333 feat: release support arm arch linux (#1434)
* feat: release support arm arch linux

Aria2 build:
https://github.com/motrixapp/Aria2-Pro-Core/tree/build_for_motrix

* chore: update github action yml

* chore: revert github action ubuntu-arm64
2023-04-17 21:31:08 +08:00
Chiao-Wei Wang 73c5a6790a feat: Add cURL support for convenient download with cookie/referer information (#1430)
* Add CURL support

* Fix GET request parameters problem

* Add AppleSilicon build command

* Use patched curl-to-json

* Add AppleSilicon building instruction on README

* Update curl-to-json to get rid of warnings

* fix: cannot correctly parse curl -b option

* fix: curl cannot use -A -e options

* fix: update curl-to-json to patch

* chore: update curl-to-json to v1.2.7

* Use --arm64 instead of --universal for build::applesilicon
2023-04-17 11:29:46 +08:00
Dr_rOot 644966e438 feat: app menu add task list and bind hotkey 2023-04-15 21:50:57 +08:00
Chiao-Wei Wang af6e0f33c0 fix: bug regarding cookie/referer (#1428)
When cookie/referer are set at the same time, aria2 failed to parse the cookie/referer arguments.
2023-04-15 11:11:45 +08:00
Dr_rOot 81656a2cd0 Merge pull request #1427 from agalwood/feature/dir_history_20230412
feat: choose dir from history directory
2023-04-13 15:20:22 +08:00
Dr_rOot 74b9f465a1 fix: update nat-api to fix xml2js vulnerability 2023-04-13 14:44:17 +08:00
Dr_rOot 92177a2c4b feat: choose dir from history directory 2023-04-13 12:49:25 +08:00
Dr_rOot bc0114a164 refactor: tracker utils 2023-04-13 12:42:24 +08:00
Dr_rOot ff918c916c refactor: text direction 2023-04-13 12:24:49 +08:00
Dr_rOot d81c0bbb9a chore: update git ignore 2023-04-13 12:23:04 +08:00
Dr_rOot b240029a47 refactor: parseHeader replace substr to substring 2023-04-12 19:52:50 +08:00
Dr_rOot ba887bcc2b fix: directory history props 2023-04-12 14:40:01 +08:00
Dr_rOot 1d90231ebd feat: add task dir history 2023-04-12 11:21:07 +08:00
Dr_rOot 39d92907e9 Merge pull request #1426 from agalwood/hotfix/linux_rendering_bug_20230410
fix: BrowserWindow rendering bug under linux
2023-04-12 09:51:33 +08:00
Dr_rOot 4272a53f69 fix: preference basic need confirm but not changed
The modified preferences will be lost, are you sure you want to leave?
2023-04-11 12:02:06 +08:00
Dr_rOot 0bbe980d48 chore: declare node version >= 18 2023-04-10 21:24:23 +08:00
Dr_rOot d2017a6c25 fix: BrowserWindow rendering bug under linux 2023-04-10 18:23:37 +08:00
Dr_rOot e3da125cc7 refactor: update some aria2 default conf (#1425)
* chore: update deps

* chore: update axios

* chore: update default aria2 config

Some configurations are learned from
https://github.com/P3TERX/aria2.conf

* feat: preferences basic add bt-force-encryption ui
2023-04-09 21:43:04 +08:00
Shatyuka 41a81e7793 feat: add taskbar progress (#1424) 2023-04-09 21:12:19 +08:00
Dr_rOot 11c08b0dc2 chore: update new cn bug report issue template 2023-04-06 10:44:55 +08:00
Imamuzzaki Abu Salam dbc95965aa chore: Create New Bug Report Issue Template to prevent bad contributor experience 2023-04-06 10:16:18 +08:00
Dr_rOot 26b5662c82 refactor: adjust the style of the speed limit 2023-04-05 15:24:28 +08:00
Dr_rOot bb37d4f328 Merge branch 'l10n-tw-master'
chore: improve zh-TW localization quality
2023-04-05 14:23:01 +08:00
Dr_rOot b355bcf623 Merge branch 'master' of github.com:l10n-tw/Motrix into l10n-tw-master
# Conflicts:
#	src/shared/locales/zh-TW/preferences.js
2023-04-05 14:22:13 +08:00
Dr_rOot 9076ec08f8 chore: update pt-BR task stopped translate
closed #1045
2023-04-04 23:55:11 +08:00
Dr_rOot 65794cabab Merge pull request #1420 from agalwood/hotfix/mac_dmg_20230401
fix: electron-builder build mac dmg
2023-04-04 23:42:43 +08:00
Dr_rOot e3f506ec0c fix: electron-builder dmg build fail 2023-04-04 23:40:14 +08:00
Dr_rOot 70e7c99ff9 refactor: move dependencies to devDependencies
Reduce the final size of the app release
2023-04-04 23:39:57 +08:00
Dr_rOot bc66511647 refactor: remove electron-debug 2023-04-04 23:34:57 +08:00
Dr_rOot 002ef830dd fix: addTask autofillResourceLink this error 2023-04-04 23:29:15 +08:00
Shatyuka 06ffe6bd87 feat: lock AddTask dialog (#1416) 2023-04-04 23:23:32 +08:00
Sammy ecf59583d6 fix: add nullcheck for legacy speed settings (#1417) 2023-04-04 19:37:56 +08:00
Sammy 7201f17aed feat: Allow more customization for transfer speeds (#1413) 2023-04-03 10:57:51 +08:00
Dr_rOot b4df97b471 fix: hide tray not show when run mode changed 2023-04-01 22:34:08 +08:00
Dr_rOot 5ea19eb441 Merge pull request #1412 from agalwood/feature/hide_tray_20230401
feat: hide tray application
2023-04-01 17:51:02 +08:00
Dr_rOot 8857290a0a chore: update deps & bump version to 1.8.0 2023-04-01 17:26:53 +08:00
Dr_rOot 1dec09b005 feature: refactor run mode add hide tray 2023-04-01 17:13:16 +08:00
Dr_rOot d67ba74b44 refactor: application init 2023-04-01 17:11:58 +08:00
Dr_rOot 696d5c7f02 docs: update translation guide locales 2023-04-01 16:17:21 +08:00
Dr_rOot 106410cb23 docs: update lost nl locale 2023-04-01 15:36:29 +08:00
Dr_rOot 237df6011e chore: update task authorization i18n 2023-04-01 15:36:10 +08:00
Dr_rOot 20dbeb33ac refactor: mock ua 2023-03-31 20:57:07 +08:00
Dr_rOot 55e2a42f3d chore: upgrade aria2 version to 1.36 (#1411)
* chore: update build scripts

* fix: setup protocols client empty error

* refactor: auto change theme

* refactor: engine max connection per server

* refactor: adjust add task dialog style

* refactor: aria2 client lib import

* chore: update deps

* chore: striped darwin arm64 aria2c bin

* chore: strip darwin engine x64 aria2c bin

* chore: upgrade linux engine arai2c bin to 1.36

* chore: upgrade windows engine arai2c bin to 1.36
2023-03-31 20:08:19 +08:00
Dr_rOot 637d5e9a80 Merge pull request #1408 from agalwood/hotfix/some_url_fix_20230328
fix: some fix
2023-03-29 22:03:01 +08:00
Dr_rOot 9867c578dc chore: i18n update stop seeding tip 2023-03-29 21:22:45 +08:00
Dr_rOot a8bac652d1 chore: bump @motrix/nat-api version 2023-03-29 21:21:15 +08:00
Dr_rOot 7d0a94ee37 chore: change notarize deps 2023-03-29 11:54:11 +08:00
Dr_rOot 0276c8e5b4 refactor: simplified upnp mapping fail log 2023-03-29 11:53:25 +08:00
RaymondSalim e93d6a2c92 feat: add http authorization header (#1263)
Co-authored-by: Dr_rOot <agalwood.net@gmail.com>
2023-03-29 10:48:33 +08:00
Dr_rOot 8743e8a025 chore: change jsdelivr cdn url 2023-03-28 13:21:58 +08:00
Dr_rOot 680fdac38b refactor: dock manager 2023-03-28 13:21:32 +08:00
Dr_rOot e06850b5a2 chore: update Transmission mock version 2023-03-28 13:20:55 +08:00
Dr_rOot 038511fed4 fix: github actions mac skip notarize 2023-03-27 22:10:44 +08:00
Dr_rOot 6b2deb8303 fix: engine aria2 bin path 20230327 (#1405)
* fix: engine aria2 bin

* chore: upgrade github actions release node version

* chore: github actions skip notarization if not tag
2023-03-27 21:42:07 +08:00
Dr_rOot a8846eaf92 fix: update deps 20230324 (#1404)
* refactor: i18n thai language

* chore: rename renderer app name

* refactor: remove svg-innerhtml import

* refactor: update deps

* fix: protocol config save error

* fix: arch engine path copy

* chore: build arm64 arch aria2 v1.36.0
2023-03-27 21:19:56 +08:00
Dr_rOot 6039a89441 Merge pull request #1056 from 149segolte/update-windows-aria2-executables
Update Windows aria2 executables per architecture
2023-03-24 21:48:25 +08:00
Nesaku 2bfab8b9c8 fix: Improve English Translations (#1367) 2023-03-24 21:40:44 +08:00
Esteban Zapata e6c533e139 fix: spanish translation (#1361) 2023-03-24 21:40:14 +08:00
MagicLike 1c2fd0de05 fix: German translation (#1302)
- Fixed German translations for "preferences", "theme-auto", "thunder" & "auto-check-update"
2023-03-24 21:38:49 +08:00
Minseo Lee a91af1032c fix: Update Korean translation (#1290)
* Update about.js

* Update app.js

* Update edit.js

* Update help.js

* Update menu.js

* Update preferences.js

* Update app.js

* Update preferences.js

* Update task.js

* Update window.js

* Update task.js

* Update preferences.js

* Update app.js

* Update preferences.js

* Update preferences.js

* Update task.js
2023-03-24 21:38:20 +08:00
CDzungx c80102c5f5 refactor: Small Vietnamese translation update (#1162)
* refactor: Small Vietnamese translation fix

* Update edit.js

* Update task.js
2023-03-24 21:36:26 +08:00
Non-Official NPM Mirror Bot ff312df849 docs: update taobao npm registry address (#1155)
Co-authored-by: NPM Mirror Bot <npmmirror@localhost>
2023-03-24 21:35:56 +08:00
Nawapon Boonjua 65bf25dc1a feat: Translated to Thai Language (#1046) 2023-03-24 21:32:19 +08:00
toto6038 6f35e64c2a chore(l10n): Improve zh-tw localization quality 2022-04-08 23:11:21 +08:00
SiderealArt 4c5bba89ef chore: update zh-TW translation (#1107) 2022-02-13 22:37:37 +08:00
Nick Bouwhuis 51b1be7bbc feat: add Dutch language translations (#1104)
* add Dutch language translations

* fix typo

* add 'nl' to `src/shared/locales/app.js` and `src/shared/locales/all.js`

* fix indenting

Co-authored-by: Nick Bouwhuis <nick@bouwhuis.io>
Co-authored-by: Nick Bouwhuis <n.bouwhuis@speakup.nl>
2021-12-02 15:50:49 +08:00
Dr_rOot 1bf594b369 Merge pull request #1097 from tso1158687/chinese-traditional
refactor: adjust chinese traditional translation
2021-12-01 10:38:25 +08:00
Dr_rOot de1db5687b fix: add session-reset & session-reset-confirm to de language (#1103)
fix: add session-reset & session-reset-confirm to de language
2021-12-01 10:38:09 +08:00
Dr_rOot 98580fc094 Merge pull request #1093 from shatyuka/webpack_cli
fix: upgrade webpack cli parameters
2021-12-01 10:36:08 +08:00
Dr_rOot 8994312ee0 Merge pull request #1092 from shatyuka/save_preference
refactor: improve preference
2021-12-01 10:34:32 +08:00
Nick Bouwhuis bd9b5eca12 add session-reset & session-reset-confirm to de language 2021-11-27 19:44:34 +01:00
jason zheng 4ed0bba8ba adjust chinese traditional translation 2021-11-23 12:59:52 +08:00
Shatyuka 7868a4870b fix: update webpack cli parameters 2021-11-22 03:55:36 +08:00
Shatyuka 8052aa047e refactor: improve preference 2021-11-22 03:30:17 +08:00
Dr_rOot 559df6bb8f Merge pull request #1085 from shatyuka/macos_tray_tooltip
fix: do not show tray tooltip for macOS
2021-11-18 10:45:59 +08:00
Shatyuka c70a35e083 fix: do not show tray tooltip for macOS 2021-11-12 13:29:25 +08:00
149segolte 30817eac86 docs: Update Readme 2021-09-24 11:05:46 +05:30
149segolte 751efd6b00 feat: Update windows aria2 binaries to 1.36.0 2021-09-23 14:20:34 +05:30
149segolte 7688115bd4 build: Update Windows aria2 executables 2021-09-17 13:29:43 +05:30
Eshagh 732327f5a3 fix: update persian translation (#1024)
* update persian translation

* update persian translate
2021-09-13 10:48:07 +08:00
Dr_rOot 38fb29382b Merge pull request #1022 from shatyuka/fix_macos_dark_menu
fix: macos dark menu
2021-08-15 14:36:15 +08:00
Dr_rOot ee05252163 Merge pull request #1019 from shatyuka/fix_minimize
fix: showWindow won't restore minimized window
2021-08-15 14:36:04 +08:00
Shatyuka 74ba6ec5ab fix: macos dark menu icon 2021-08-09 12:10:09 +08:00
Shatyuka 1f5f5dc5f0 fix: showWindow won't restore minimized window 2021-08-06 00:17:54 +08:00
Dr_rOot 6be0afd5ff Merge pull request #998 from agalwood/feature/app_improve_20210530 2021-07-04 23:04:01 +08:00
Dr_rOot 2c269e3a52 Merge branch 'master' into feature/app_improve_20210530 2021-07-04 22:21:21 +08:00
Dr_rOot 79dea2f4b7 fix: update node version for electron-builder 2021-07-04 22:03:42 +08:00
Dr_rOot 9db5c52f13 chore: update deps 2021-07-04 22:02:48 +08:00
Dr_rOot 81a73557e8 refactor: sort i18n locale key 2021-07-04 22:02:21 +08:00
Dr_rOot 6fc02f752d chore: i18n bt-auto-download-content 2021-07-04 21:59:48 +08:00
Dr_rOot 6d893bd1ce refactor: drag select 2021-07-04 15:17:45 +08:00
albanobattistella 68ba9207f9 refactor: i18n update it (#990)
* Update app.js

* Update preferences.js

* Update task.js
2021-06-30 12:11:31 +08:00
Dr_rOot b01d43cf73 refactor: bt auto download content 2021-06-19 22:39:01 +08:00
Dr_rOot ba97bbfa66 refactor: set follow torrent metalink default true 2021-06-19 15:53:25 +08:00
dicarne b8dbc902a3 fix: reorganize the code 2021-06-19 15:51:13 +08:00
dicarne b79ef074dd feat: add switch for auto download magnet and torrent 2021-06-19 15:51:13 +08:00
dicarne 3ceccea9da fix: tasks list has old wrong items 2021-06-19 15:51:13 +08:00
CDzungx c591ea9655 refactor: Update Vietnamese translation (#978) 2021-06-19 15:51:13 +08:00
Dr_rOot 3245bbdaa1 Merge pull request #980 from dicarne/master
fix: tasks list has old wrong items and add switch for auto download torrent
2021-06-19 15:49:41 +08:00
dicarne 60161518c6 fix: reorganize the code 2021-06-15 19:50:27 +08:00
Dr_rOot 1de2acc505 fix: spawn ENAMETOOLONG by reduceTrackerString 2021-06-15 12:06:35 +08:00
dicarne a77e62066a feat: add switch for auto download magnet and torrent 2021-06-09 13:09:28 +08:00
dicarne c6722d141b fix: tasks list has old wrong items 2021-06-09 00:37:54 +08:00
CDzungx 509c79989b refactor: Update Vietnamese translation (#978) 2021-06-08 22:33:30 +08:00
Dr_rOot 333f01afd3 refactor: improve rtl support 2021-05-30 14:33:50 +08:00
Dr_rOot edd4053730 refactor: improve responsive style 2021-05-30 14:30:13 +08:00
Dr_rOot 7db1e4ff5b refactor: page init skeleton 2021-05-30 14:28:03 +08:00
Dr_rOot a9f5312a90 refactor: util bytesToSize precision 2021-05-30 14:22:17 +08:00
Dr_rOot 6d9a640030 fix: task item status 2021-05-30 13:51:03 +08:00
Dr_rOot 74c241f819 chore: remove task item action more button 2021-05-30 13:50:16 +08:00
Dr_rOot 3e0df405ee chore: update deps 2021-05-29 18:39:21 +08:00
Dr_rOot 4dd6e948f4 docs: update readme chocolatey 2021-05-29 18:35:42 +08:00
Dr_rOot c0b7612e3a Merge pull request #967 from agalwood/dependabot/npm_and_yarn/dns-packet-1.3.4
chore(deps): bump dns-packet from 1.3.1 to 1.3.4
2021-05-29 18:34:03 +08:00
dependabot[bot] 0486e4b417 chore(deps): bump dns-packet from 1.3.1 to 1.3.4
Bumps [dns-packet](https://github.com/mafintosh/dns-packet) from 1.3.1 to 1.3.4.
- [Release notes](https://github.com/mafintosh/dns-packet/releases)
- [Changelog](https://github.com/mafintosh/dns-packet/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mafintosh/dns-packet/compare/v1.3.1...v1.3.4)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-29 04:12:41 +00:00
Dr_rOot 160fe9725d docs: readme add chocolatey pkg 2021-05-21 11:26:44 +08:00
Dr_rOot 577a9b32a1 Merge pull request #957 from shatyuka/fix_windows_titlebar
fix: window resize
2021-05-20 10:37:42 +08:00
Shatyuka f05994d9f8 fix: window resize 2021-05-19 22:22:58 +08:00
Dr_rOot dec938f2f0 chore: setup github action codeql 2021-05-19 12:01:37 +08:00
Dr_rOot 084b5350fd docs: update readme add flatpak 2021-05-19 10:56:10 +08:00
Dr_rOot e971f86932 docs: update readme release status of nb 2021-05-18 21:18:52 +08:00
Dr_rOot 0be90dda31 docs: update i18n contributors add nb 2021-05-18 21:14:41 +08:00
Dr_rOot 2bc4a8c61e fix: i18n get language by electron locale 2021-05-18 21:14:34 +08:00
Dr_rOot 6baef42274 Merge pull request #953 from shatyuka/macos_vibrancy
feat: add vibrancy sidebar for macos
2021-05-18 21:06:48 +08:00
Shatyuka f4cc731e63 feat: add vibrancy sidebar for macos 2021-05-18 20:54:40 +08:00
rubjo 480039c4cc feat: Added Norwegian Bokmål (#952)
* feat: Added Norwegian Bokmål (nb-NO)

* fix: Escape apstrophe

* refactor: Rename from nb-NO to nb

* fix: Learn alphabet
2021-05-18 17:07:26 +08:00
Dr_rOot b0242d3d5b chore: bump version v1.6.11 2021-05-15 22:30:00 +08:00
Dr_rOot 58cfd2b873 Merge pull request #944 from agalwood/feature/improve_detail_20210513
feat: improve task detail
2021-05-15 22:27:00 +08:00
Dr_rOot 804f864709 chore: update deps 2021-05-15 22:12:19 +08:00
Dr_rOot 57fb4d95ae feat: get file selection util 2021-05-15 21:59:01 +08:00
Dr_rOot 8030699e15 chore: i18n task select at least one 2021-05-15 21:58:22 +08:00
Dr_rOot 1185a81c0c chore: i18n save & reset 2021-05-15 21:45:41 +08:00
Dr_rOot aa4941f842 feat: save task file selection 2021-05-15 21:44:21 +08:00
Dr_rOot 841bd8b923 fix: task detail activity graphic align center 2021-05-13 21:52:57 +08:00
Dr_rOot 85ae4cdbca Merge pull request #942 from agalwood/hotfix/auto_update_20210511
fix: some bug
2021-05-12 23:34:25 +08:00
Dr_rOot c257816608 fix: element ui message z-index 2021-05-12 22:32:53 +08:00
Dr_rOot 1b44ef725b fix: task detail not auto hide when remove task 2021-05-12 11:47:18 +08:00
Dr_rOot bffe919b93 fix: add one task triggered rename rule 2021-05-12 11:24:51 +08:00
Dr_rOot 87635ade34 fix: auto theme 2021-05-12 11:24:15 +08:00
Dr_rOot c6a9eb226d fix: auto update exception 2021-05-11 15:18:21 +08:00
Dr_rOot da2b6638d9 Merge pull request #939 from agalwood/feature/lab_dark_20210509
feat: preference lab panel dark theme
2021-05-11 15:06:22 +08:00
Dr_rOot 91072509d3 refactor: mo icon 2021-05-09 22:12:47 +08:00
Dr_rOot 0d75370f95 fix: drawer header close icon could not click 2021-05-09 22:12:21 +08:00
Dr_rOot 994d351998 feat: lab page dark theme 2021-05-09 12:07:15 +08:00
Dr_rOot 166aba7747 chore: bump version v1.6.10 2021-05-07 23:22:26 +08:00
Dr_rOot bc3ea97780 Merge pull request #928 from agalwood/hotfix/app_style_20210507
fix: app style
2021-05-07 22:37:43 +08:00
Dr_rOot 2beb6f14a8 chore: update app info icon 2021-05-07 21:49:32 +08:00
Dr_rOot 5d8566a934 feat: mock ua add more ua options 2021-05-07 21:36:52 +08:00
Dr_rOot 84b002d513 feat: add more speed options 2021-05-07 21:25:29 +08:00
Dr_rOot a4fb082088 refactor: style code format 2021-05-07 21:25:04 +08:00
Dr_rOot 3aa18e7f72 fix: revert mac target 2021-05-07 19:19:10 +08:00
Dr_rOot e939f9e5dc Merge pull request #925 from agalwood/hotfix/app_hang_20210507 2021-05-07 16:40:04 +08:00
Dr_rOot 53ec0b1dee chore: update deps 2021-05-07 14:11:34 +08:00
Dr_rOot fcfd32a71e refactor: task detail style 2021-05-07 14:06:35 +08:00
Dr_rOot 2ff56a3770 refactor: task item style 2021-05-07 14:06:28 +08:00
Dr_rOot 48768f0658 fix: copyright year 2021-05-07 14:03:32 +08:00
Dr_rOot 3e84230b33 fix: app reset engine not start 2021-05-07 14:03:13 +08:00
Dr_rOot 5490946267 fix: app hang caused by child_process spawn
https://github.com/electron/electron/issues/24329#issuecomment-760699187
2021-05-07 14:02:48 +08:00
Dr_rOot 9461381042 chore: bump version v1.6.8 2021-05-06 15:30:01 +08:00
Dr_rOot 364d7a8f66 chore: lock electron-builder version to 22.10.5 2021-05-06 15:27:39 +08:00
Dr_rOot 7a5a1554ca chore: bump version & electron-builder -> 22.10.5 2021-05-06 14:58:50 +08:00
Dr_rOot 8410be59b2 chore: bump version 1.6.6 2021-05-06 14:19:22 +08:00
Dr_rOot 795db0b926 chore: github action build force release 2021-05-06 14:18:30 +08:00
Dr_rOot 079cab8544 chore: bump version v1.6.5 2021-05-06 13:57:32 +08:00
Dr_rOot 7109747e00 chore: update github actions 2021-05-06 13:56:57 +08:00
Dr_rOot 9b698f5a0e chore: bump version v1.6.3 2021-05-06 12:05:25 +08:00
Dr_rOot 2b35fb9bc2 chore: bump version v1.6.1 2021-05-06 12:02:41 +08:00
Dr_rOot 2b80127ad0 docs: update readme i18n 2021-05-06 12:01:57 +08:00
Dr_rOot d47fa3d705 chore: bump version to 1.6.0 2021-05-06 11:24:16 +08:00
Dr_rOot 555db61ec0 Merge pull request #922 from agalwood/hotfix/theme_style_20210506
refactor: task detail dark theme style
2021-05-06 11:09:57 +08:00
Dr_rOot 7c2fc774ca chore: update deps 2021-05-06 10:48:31 +08:00
Dr_rOot 8eeab3d3fa feat: task graphic dark theme style 2021-05-06 10:36:33 +08:00
Dr_rOot 7a5b16aecc refactor: task status theme 2021-05-06 10:36:02 +08:00
Dr_rOot c5f72414e2 refactor: preference store actions 2021-05-06 10:35:26 +08:00
Dr_rOot 4016f5c02e Merge pull request #921 from agalwood/feature/task_detail_20210503 2021-05-05 23:20:09 +08:00
Dr_rOot af7eb1f359 Merge branch 'master' into feature/task_detail_20210503 2021-05-05 23:08:19 +08:00
Dr_rOot f30ed3c8f7 fix: update task peers table column width 2021-05-05 22:56:44 +08:00
Dr_rOot e9e86fbc83 refactor: task detail tab content scrollable 2021-05-05 22:36:14 +08:00
Dr_rOot d7b985bc3f docs: update app features 2021-05-05 16:54:40 +08:00
Dr_rOot e307240a60 fix: remove useless code 2021-05-05 16:52:28 +08:00
Dr_rOot 8dd1d84485 chore: i18n task detail 2021-05-05 16:51:12 +08:00
Dr_rOot 3c7b0b26e3 chore: i18n bt settings 2021-05-05 16:26:01 +08:00
Dr_rOot 778e092c17 docs: update contributing locale guide 2021-05-05 15:54:32 +08:00
Dr_rOot 6e462166d1 chore: i18n task files 2021-05-05 11:35:30 +08:00
Dr_rOot 812b419379 chore: update task list i18n 2021-05-05 10:39:21 +08:00
Dr_rOot 04dcddd3e1 docs: update translation contributors 2021-05-05 09:45:23 +08:00
أحمد الطبراني 1cfec289b7 fix: Complete translation into Arabic (#919)
* refactor: Complete translation into Arabic

* refactor: Complete translation into Arabic

* Update preferences.js
2021-05-05 09:41:03 +08:00
Dr_rOot 2dcfb8c25e refactor: change some log 2021-05-04 20:38:47 +08:00
Dr_rOot 482b9312b1 chore: i18n task detail 2021-05-04 15:30:16 +08:00
Dr_rOot dbb1889fc9 feat: task detail 2021-05-04 15:06:44 +08:00
Dr_rOot a6de12c875 feat: task activity 2021-05-04 15:04:02 +08:00
Dr_rOot d14ddef8e8 feat: task peers 2021-05-04 15:03:33 +08:00
Dr_rOot c8698e5b80 refactor: task files component 2021-05-04 15:03:10 +08:00
Dr_rOot e8c99caf87 feat: task trackers 2021-05-04 14:59:31 +08:00
Dr_rOot f70595915d feat: task general info 2021-05-04 14:58:39 +08:00
Dr_rOot c5962041cb feat: task bitfield graphic 2021-05-04 14:55:39 +08:00
Dr_rOot 28bbf26334 refactor: select torrent file list 2021-05-03 20:00:07 +08:00
Dr_rOot 3d6931f8d8 refactor: main menu quit 2021-05-03 19:43:14 +08:00
Dr_rOot 46d686bee5 fix: remove file to trash for electron v11.x 2021-05-03 19:41:41 +08:00
Dr_rOot 9ffaf1116f Merge pull request #915 from agalwood/feature/bt_config_202104231109 2021-05-03 19:19:57 +08:00
Dr_rOot 2d4a05f3b0 chore: update deps lock 2021-05-03 19:01:54 +08:00
Dr_rOot e04d3a582e fix: store task checkTaskIsBT 2021-05-03 18:51:12 +08:00
Hadi Alqattan 943830f2ed feat: Add Arabic Localization
* Partial Arabic Language support!

* Partial Arabic Language support!

* translate more words...
2021-05-03 18:35:58 +08:00
Dr_rOot 137927d44a chore: revert electron from 12.x to 11.x 2021-05-03 18:33:29 +08:00
Dr_rOot 819f86632e feat: task progress info show seeder number 2021-05-03 18:18:55 +08:00
Dr_rOot 06f881932c refactor: dev env add engine log 2021-05-03 18:17:41 +08:00
Dr_rOot cb845ea65a refactor: update pause task speed use force pause 2021-05-03 18:15:24 +08:00
Dr_rOot 60e4907be6 fix: stop seeding params gid 2021-04-26 15:00:59 +08:00
Dr_rOot bc38978d6a refactor: open url external 2021-04-23 17:37:16 +08:00
Dr_rOot 90c3bbff13 fix: deps electron remote 2021-04-23 17:36:45 +08:00
Dr_rOot 3116c53734 refactor: electron remote 2021-04-23 15:12:40 +08:00
Dr_rOot 78fb6ba455 refactor: css-minimizer-webpack-plugin
replace css-minimizer-webpack-plugin with css-minimizer-webpack-plugin
2021-04-23 14:51:41 +08:00
Dr_rOot 86304c126d chore: update deps 2021-04-23 11:48:56 +08:00
Dr_rOot 3424424e67 feat: preference bt setting bt-save-metadata 2021-04-23 11:39:34 +08:00
Dr_rOot 7206f2fc3c Merge pull request #892 from agalwood/feature/bt_202103131952
feat: new app icon & bt setting
2021-04-01 23:39:57 +08:00
Dr_rOot bd25e566c8 chore: i18n zh-TW bt keep seeding 2021-03-24 23:26:02 +08:00
Dr_rOot f54bc32e90 feat: bt keep seeding 2021-03-24 23:23:04 +08:00
Dr_rOot f6dde55234 feat: new app icon 2021-03-13 21:14:43 +08:00
Dr_rOot 1303713f5e feat: reset session 2021-03-13 20:08:14 +08:00
Dr_rOot 57a5c0c932 Merge pull request #877 from agalwood/feature/engine_refactor_202102182037
refactor: replace forever with child process
2021-03-13 19:50:43 +08:00
Dr_rOot 22a41c332f Merge branch 'master' into feature/engine_refactor_202102182037
# Conflicts:
#	yarn.lock
2021-03-13 18:37:25 +08:00
Dr_rOot 76e7223e85 Merge pull request #875 from agalwood/dependabot/npm_and_yarn/elliptic-6.5.4
chore(deps): bump elliptic from 6.5.3 to 6.5.4
2021-03-13 18:35:15 +08:00
Dr_rOot 014619ed46 chore: update deps 2021-03-13 18:29:02 +08:00
Dr_rOot aec3a25e3a chore: engine error code text remove # 2021-03-13 11:23:57 +08:00
dependabot[bot] 02f6ffa3cb chore(deps): bump elliptic from 6.5.3 to 6.5.4
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.3 to 6.5.4.
- [Release notes](https://github.com/indutny/elliptic/releases)
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.3...v6.5.4)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-11 07:16:59 +00:00
Dr_rOot 5d32fc633c feat: add more speed options 2021-03-01 11:12:49 +08:00
Dr_rOot cde2832ae3 chore: aria2 conf http accept gzip 2021-03-01 11:10:02 +08:00
Dr_rOot 8656fa0862 refactor: replace forever with child process 2021-03-01 11:09:14 +08:00
Dr_rOot 0cd1ed1e34 Merge pull request #865 from agalwood/feature/tracker_cdn_202102181833
feat: add tracker cdn source
2021-02-18 20:31:17 +08:00
Dr_rOot d58e485846 refactor: auto sync tracker 2021-02-18 19:03:19 +08:00
Dr_rOot a6aca44672 refactor: preference tracker cdn source select 2021-02-18 18:41:57 +08:00
Dr_rOot cc28e4b19b chore: replace default tracker source config 2021-02-18 18:41:14 +08:00
Dr_rOot 599dec1d6e feat: add tracker cdn urls 2021-02-18 18:35:10 +08:00
Dr_rOot d020359058 Merge pull request #851 from upuppz/master
fix: Function overload error, unable to trigger events bound in EngineClient.vue
2021-01-14 20:23:02 +08:00
upuppz 04d68e293b fix: Function overload error, unable to trigger events bound in EngineClient.vue(函数重载错误, 无法触发在 EngineClient.vue 中绑定的事件) 2021-01-12 18:25:48 +08:00
upuppz 6b93a80888 Merge pull request #4 from agalwood/master
Sync
2021-01-12 18:20:49 +08:00
Dr_rOot c3400d936e Merge pull request #844 from alyn3d/master
feat: Added Romanian translation
2021-01-05 11:12:11 +08:00
alyn3d 871be123d4 feat: Added Romanian translation 2021-01-03 00:29:01 +02:00
Dr_rOot bed2148ba0 Merge pull request #843 from agalwood/hotfix/tray_retina_202012292116
refactor: dynamic tray scale
2020-12-29 21:24:16 +08:00
Dr_rOot 8b97c90e88 refactor: dynamic tray scale 2020-12-29 21:16:36 +08:00
Dr_rOot 832befbafd Merge pull request #842 from agalwood/hotfix/style_202012291454
fix: some style improve
2020-12-29 21:05:31 +08:00
Dr_rOot ddbf27e2f9 refactor: form actions position sticky 2020-12-29 14:55:57 +08:00
Dr_rOot 64b30b6c26 fix: task progress info text font style normal 2020-12-29 14:55:38 +08:00
Dr_rOot 32c8767e65 Merge pull request #840 from agalwood/hotfix/multispinner_202012282315
chore: replace multispinner deps
2020-12-28 23:27:48 +08:00
Dr_rOot 69391c6de0 chore: update deps 2020-12-28 23:21:47 +08:00
Dr_rOot fbec4e7c4d Merge pull request #839 from shatyuka/big_sur_tray
fix: big sur tray color
2020-12-28 23:14:13 +08:00
Shatyuka 7640ba583d fix: big sur tray color 2020-12-28 19:45:53 +08:00
Dr_rOot 924b397727 Merge pull request #838 from agalwood/hotfix/tray_workder_202012271447
fix: tray worker cannot find module 'lodash'
2020-12-27 21:45:06 +08:00
Dr_rOot 565afdde74 chore: update deps & change npm to yarn 2020-12-27 20:07:53 +08:00
Dr_rOot 3dfd4ec4da fix: tray worker cannot find module 'lodash' 2020-12-27 14:47:55 +08:00
Dr_rOot 0a21f590ff Merge pull request #836 from shatyuka/apple_silicon
feat: Support Apple Silicon
2020-12-27 14:45:37 +08:00
カワリミ人形 79bf90bb3c docs: Fix installation instructions in README.md (#834) 2020-12-26 21:09:55 +08:00
Shatyuka f4602b4b68 fix: import JSONRPCError 2020-12-26 13:00:29 +08:00
Shatyuka 93a6f1cfbd fix: Shadow not complete 2020-12-26 12:00:08 +08:00
Shatyuka f0d14afb7e chore: update dependency sass-loader 2020-12-26 11:10:02 +08:00
Shatyuka d9a69ae009 fix: use iframe instead of webview 2020-12-26 09:29:26 +08:00
Shatyuka 0f5398b106 fix: engine failed to quit 2020-12-26 09:03:38 +08:00
Shatyuka c6eb96547a fix: tray menu crash 2020-12-26 07:39:00 +08:00
Shatyuka 31ab487d82 feat: Add native arm support for macos aria2
universal binary
2020-12-26 06:03:36 +08:00
Shatyuka 0b2e271663 feat: Update electron to 11 to support Apple Silicon
Update almost all of the dependencies.
This commit only promises the app would be successfully built and run.
2020-12-26 00:09:44 +08:00
jimman2003 a4a4b2321f fix: updated axios and forever-monitor to get rid of error in dev enviroment (#818) 2020-12-09 20:51:18 +08:00
XIU2 ef372da87b fix: replace TrackersListCollection other.txt with http.txt (#809) 2020-11-25 13:59:00 +08:00
Dr_rOot 10cab1a9a0 docs: readme i18n add Italiano 2020-10-09 21:08:55 +08:00
blackcat-917 a4a651b397 feat: Added Italian language (#794)
* Feat: added italian

* Small fix

* Update index.js to match to the original indent style
2020-10-09 20:56:06 +08:00
Dr_rOot b2770795ad docs: i18n add el (Greek) 2020-08-30 13:22:17 +08:00
Akis S f4c8ff66d5 feat: Added Greek language (#774)
* feat: Added Greek language

* Update index.js
2020-08-30 13:17:49 +08:00
Dr_rOot 1b450c8022 docs: i18n add missing locales es & hu 2020-08-04 21:52:14 +08:00
zalnars e5b8846286 feat: Added Hungarian language (#754)
* Added Hungarian language

* Update all.js

* Update app.js

* Update all.js
2020-07-26 21:06:19 +08:00
Samuel Martineau 8de8591725 fix: correction of the french locale (#742)
* Correction of the French locale

- `transfer-speed-upload`and `transfer-speed-download` were the same
- `transfer-speed-unlimited` was still in English

* fix: correction of the french locale

* fix: correction of the french locale
2020-07-15 20:55:17 +08:00
Dr_rOot 20c30279b0 docs: update readme cn 2020-07-04 21:43:00 +08:00
Stanisław Nieradko 9000be502b feat: Added Polish (#731)
* Added Polish

* Sorted imports in src/shared/locales/app.js
2020-07-04 21:36:34 +08:00
Dr_rOot cfe66cf337 Merge pull request #720 from agalwood/feature/tray_speedometer_202006211216
feat: menu bar tray speedometer #643
2020-06-21 21:30:51 +08:00
Dr_rOot 3557d17bb6 chore: update deps, upgrade electron to 9.x
> That was a bug in Chromium, which got fixed by this [commit](https://chromium.googlesource.com/chromium/src/+/09514b7fbd4fb14ce12a43bc7f4807179612fa94) (available in Chrome v83).

https://stackoverflow.com/questions/61268950/offscreen-converttoblob-very-slow
2020-06-21 21:10:22 +08:00
Dr_rOot 2af891aab8 chore: i18n tray speedometer 2020-06-21 16:23:07 +08:00
Dr_rOot 0d276de39b feat: preference tray speedometer setting 2020-06-21 16:12:35 +08:00
Dr_rOot 8a6beda335 feat: tray speedometer 2020-06-21 16:12:04 +08:00
Dr_rOot 68f1cdc4de chore: update copyright year 2020-06-21 15:30:28 +08:00
Dr_rOot 5290fcfa14 feat: dockmanager add handleSpeedChange 2020-06-21 15:21:06 +08:00
Dr_rOot d865b630a3 refactor: rename enable args 2020-06-21 15:19:50 +08:00
Dr_rOot 9d95d294cd refactor: rename store actions mutations 2020-06-21 13:47:02 +08:00
Dr_rOot ea46d9b3c6 refactor: load config fn use ipc invoke 2020-06-21 12:33:28 +08:00
Dr_rOot ef2c992af9 refactor: remove deprecated fns 2020-06-21 12:30:43 +08:00
Dr_rOot 64ee097c85 Merge pull request #718 from agalwood/feature/stop_seeding_202006201236
fix: stop bt task seeding notification #604
2020-06-20 18:29:48 +08:00
Dr_rOot 31517f93cb chore: i18n stopping seeding tip 2020-06-20 15:51:24 +08:00
Dr_rOot 6d54e557b9 fix: oddly stop seeding notify #604 2020-06-20 15:50:18 +08:00
Dr_rOot 3e61adcea3 Merge pull request #716 from agalwood/feature/url_protocol_202005290826
refactor: redesign motrix scheme
2020-06-20 12:34:52 +08:00
Dr_rOot 84d9ced137 Merge pull request #714 from agalwood/hotfix/hide_run_mode_202006192140
fix: preference show run mode only in macOS
2020-06-19 23:01:36 +08:00
Dr_rOot bc45ed9d5b refactor: add jsconfig 2020-06-19 21:44:53 +08:00
Dr_rOot 3d98104dbf fix: preference show run mode only in macOS 2020-06-19 21:42:00 +08:00
Dr_rOot fb6986ff6e docs: update readme app icon 2020-06-19 20:55:07 +08:00
Dr_rOot b8507570c6 refactor: rename initialForm to initForm 2020-06-12 17:22:38 +08:00
Dr_rOot cf3ef7606c fix: new task uri 2020-06-06 23:31:24 +08:00
Dr_rOot 12a9fa92c1 chore: bump version 2020-06-05 23:54:14 +08:00
Dr_rOot 0fd6617eba docs: update readme i18n 2020-06-05 23:52:34 +08:00
Dr_rOot 7ebbf929d5 fix: i18n no-confirm-before-delete-task missed 2020-06-05 23:49:27 +08:00
Dr_rOot 14223c2204 chore: bump version 2020-06-05 23:26:11 +08:00
Dr_rOot 2cfb6b1914 Merge pull request #689 from agalwood/hotfix/handle_url_202006051331
fix: open app with url handle fail
2020-06-05 14:04:27 +08:00
Dr_rOot c38cf80589 chore: update deps 2020-06-05 13:40:30 +08:00
Dr_rOot 3ee98eae1d fix: open app with resource url 2020-06-05 13:33:22 +08:00
Dr_rOot d2cff6356a Merge pull request #686 from NickoAilus/master
fix: edited Russian locale
2020-06-01 22:12:46 +08:00
NickoAilus 3ee432d683 Fixed Russian locale 2020-06-01 16:10:36 +03:00
Dmitry Kalinin 7f1822bb7e feat: Added bulgarian (bg) translations (#685)
* Added bulgarian (bg) translations

* Improve structure

* Fixed bugs

* Deleted comma
2020-06-01 17:33:46 +08:00
Dr_rOot 0223e691ff docs: readme i18n add vi 2020-05-31 22:57:56 +08:00
Duy–Thanh Doan 117dba9f37 feat: Add vietnamese translation (#680)
* Add vietnamese translation

* Update app.js and index.js

* Translated about.js

* Translated app.js

* first draft

* final draft

* final update - ready to review

* Update format
2020-05-31 22:52:26 +08:00
Dr_rOot e5241d09d7 refactor: protocol manager init 2020-05-29 17:28:03 +08:00
Dr_rOot c9ea1dece2 refactor: motrix url protocol 2020-05-29 17:02:43 +08:00
Dr_rOot 60d4108ddc refactor: promise all to allSettled 2020-05-29 17:00:47 +08:00
Dr_rOot ffc8de4766 refactor: add task utils 2020-05-29 16:58:35 +08:00
Dr_rOot 66f114bf72 Merge pull request #674 from agalwood/hotfix/upnp_cb_202005271904
fix: nat-api autoUpdate cb is not a function
2020-05-28 15:28:28 +08:00
Dr_rOot 44f00483f9 chore: update deps 2020-05-28 14:42:43 +08:00
Dr_rOot 1866e3fd4f fix: nat-api autoUpdate cb is not a function
replace nat-api to @motrix/nat-api

@motrix/nat-api forked from https://github.com/alxhotel/nat-api
2020-05-28 14:42:05 +08:00
Dr_rOot cfac883cbf chore: remove deprecated vue-html-loader 2020-05-28 12:11:30 +08:00
Dr_rOot 1431bab366 Merge pull request #670 from agalwood/hotfix/full_screen_preference_202005271103
fix: full screen save preference issue #663
2020-05-27 11:20:23 +08:00
Dr_rOot bb373947ff fix: full screen save preference issue #663 2020-05-27 11:06:51 +08:00
Dr_rOot 8f0dc65341 refactor: rename auto hide window 2020-05-27 11:06:31 +08:00
Dr_rOot 402185e1a2 chore: bump version 2020-05-25 22:35:09 +08:00
Dr_rOot d59b5c9841 Merge pull request #667 from agalwood/hotfix/refactor_202005231656
fix: upnp client & full screen issues
2020-05-25 22:15:36 +08:00
Dr_rOot eb442e4a7a fix: windows auto launch config lose 2020-05-25 21:55:23 +08:00
Dr_rOot e82e567069 refactor: time constants 2020-05-24 20:15:20 +08:00
Dr_rOot dc2876098d fix: upnp client is destroyed #662 2020-05-24 20:13:43 +08:00
Dr_rOot 6287942fbc fix: full screen mode no traffic light #663 2020-05-24 17:04:08 +08:00
Dr_rOot 389dc080b6 refactor: improve macOS fullscreen mode usability 2020-05-24 15:30:50 +08:00
Dr_rOot 45a23d73e6 fix: code error 2020-05-23 17:16:16 +08:00
Dr_rOot 8303dd305b refactor: fn rename & format 2020-05-23 17:03:45 +08:00
Dr_rOot a98292ce1e refactor: remove title bar buttons spacer 2020-05-23 16:57:01 +08:00
Dr_rOot 8df97b8433 fix: switching system theme will not auto switch app theme 2020-05-22 11:21:45 +08:00
Dr_rOot f29e95c9bc chore: add electron apps banner 2020-05-21 16:32:10 +08:00
Dr_rOot 52e045c886 docs: update readme for github markdown 2020-05-21 08:56:28 +08:00
Dr_rOot 4632c3619a docs: update readme 2020-05-21 08:54:01 +08:00
Dr_rOot 54c48be29b chore: bump version 2020-05-21 07:51:47 +08:00
Dr_rOot 301f1403df Merge pull request #658 from aarestu/translation/indonesia
feat: add Indonesian translations
2020-05-21 07:17:12 +08:00
Dr_rOot 88de047778 Merge pull request #659 from agalwood/hotfix/webpack_copy_202005210655
fix: webpack copy plugin path
2020-05-21 07:07:29 +08:00
Dr_rOot c119de78ce fix: webpack copy plugin path 2020-05-21 06:56:04 +08:00
Restu Suhendar 9d381e16da add translation Indonesia 2020-05-21 04:24:07 +07:00
Dr_rOot e4c6d6a9c0 Merge pull request #655 from agalwood/hotfix/linux_tray_202005202115
fix: linux tray context menu
2020-05-20 21:33:13 +08:00
Dr_rOot 5bb727cb6f chore: update deps 2020-05-20 21:16:35 +08:00
Dr_rOot 00f3209c68 refactor: improve logs 2020-05-20 21:16:11 +08:00
Dr_rOot 3f8b0e6f5f fix: tray popUpContextMenu linux not support 2020-05-20 21:16:01 +08:00
Dr_rOot 0543bc4e2c chore: bump version 2020-05-20 16:32:55 +08:00
Dr_rOot 9ded42f127 chore: update docs 2020-05-20 13:53:20 +08:00
Dr_rOot 834a1ad839 docs: update readme linux section 2020-05-20 11:30:50 +08:00
Dr_rOot 8f830f6a0d fix: too fast to toggle tracker syncing spinner 2020-05-20 11:10:59 +08:00
Dr_rOot ee111c92ee fix: too fast to shut down the engine 2020-05-20 11:09:50 +08:00
Dr_rOot 74c3a3c696 Merge pull request #650 from agalwood/hotfix/linux_tray_20200519
fix: linux tray not support right-click event
2020-05-19 22:06:45 +08:00
Dr_rOot 4d964ae16e fix: tray destroy remove listener 2020-05-19 21:50:36 +08:00
Dr_rOot be2c2e8383 docs: update readme snapcraft markdown 2020-05-19 12:23:31 +08:00
Dr_rOot 4e6164816f fix: linux tray not support right click 2020-05-19 12:23:00 +08:00
Dr_rOot fa7daf377f docs: update app screenshots 2020-05-18 14:24:06 +08:00
Dr_rOot afbe364525 docs: fix release badge 2020-05-18 13:43:36 +08:00
Dr_rOot ece5cea512 docs: update readme 2020-05-18 13:37:36 +08:00
Dr_rOot dc8fa5c647 chore: bump version v1.5.10 2020-05-15 21:54:16 +08:00
Dr_rOot 4fd96e7cae chore: bump version v1.5.9 2020-05-15 21:45:22 +08:00
Dr_rOot 1f22b5efba Merge pull request #640 from agalwood/hotfix/task_manager_202005151229
fix: save session delay too long
fix: hide delete selected tasks on stopped task list
2020-05-15 16:44:31 +08:00
Dr_rOot 801db0ed38 chore: upgrade electron 2020-05-15 12:34:39 +08:00
Dr_rOot f72577de65 fix: hide delete selected tasks on stopped task list 2020-05-15 12:33:58 +08:00
Dr_rOot dd21c76dea fix: save session delay too long 2020-05-15 12:29:51 +08:00
Dr_rOot 5a5a932735 Merge pull request #639 from agalwood/feature/no_confirm_202005062312
feat: no confirm before delete task
feat: add task select video include sub files
feat: preference support add custom tracker source #627
feat: Ctrl or ⌘ + Enter quick submit task #638
feat: improve task total length is zero ui #614
fix: split & max-connection-per-server failed #270
fix: npm build:clean script
2020-05-15 00:03:54 +08:00
Dr_rOot d63c1d431d feat: improve task total length is zero ui #614 2020-05-14 23:43:42 +08:00
Dr_rOot 1a12256c4c feat: Ctrl or ⌘ + Enter quick submit task 2020-05-14 23:40:37 +08:00
Dr_rOot 9394a0a79b chore: update deps & bump version 2020-05-14 22:27:44 +08:00
Dr_rOot 5e66205298 chore: disable electron security warnings 2020-05-14 22:26:34 +08:00
Dr_rOot eb796c3c5f feat: add task select video include sub files 2020-05-14 22:26:11 +08:00
Dr_rOot 9d17b3e9b2 fix: split & max-connection-per-server failed #270 2020-05-14 22:25:35 +08:00
Dr_rOot 7ee8d4fa0f refactor: engine instance listeners 2020-05-14 22:21:57 +08:00
Dr_rOot dba4bfb0e7 fix: perference sync tracker empty 2020-05-14 22:20:23 +08:00
Dr_rOot f9755f69cd chore: improve aria2 bt config 2020-05-14 22:20:02 +08:00
Dr_rOot 7a68e1bb82 fix: npm build:clean script 2020-05-14 22:14:18 +08:00
Dr_rOot 3b12f3960f refactor: code format 2020-05-14 22:13:56 +08:00
Dr_rOot dbe26dfa98 feat: preference support add custom tracker source 2020-05-14 22:12:34 +08:00
Dr_rOot 3be8952cff refactor: task actions commands 2020-05-14 22:08:59 +08:00
Dr_rOot dc5a368e00 Merge pull request #630 from agalwood/hotfix/aria2c_darwin_202005081709
fix: rebuild darwin aria2c v1.35

closed #628
2020-05-08 17:30:53 +08:00
Dr_rOot 11aca7ea0b chore: remove bt-force-encryption 2020-05-08 17:16:48 +08:00
Dr_rOot c35af2b109 fix: rebuild aria2c #628
static build script:
https://github.com/aria2/aria2/blob/master/
makerelease-osx.mk
2020-05-08 17:12:04 +08:00
Dr_rOot b33b505ccb refactor: upnp close client 2020-05-06 23:21:49 +08:00
Dr_rOot dd22cc0306 fix: remove enable egg features config 2020-05-06 23:19:58 +08:00
Dr_rOot 206eda08aa refactor: renderer native utils 2020-05-06 23:19:08 +08:00
Dr_rOot f6e29700d0 feat: no confirm before delete config 2020-05-06 23:16:50 +08:00
Dr_rOot c17ceb365d chore: upgrade electron-builder 2020-05-03 23:00:41 +08:00
Dr_rOot a1851c6b31 chore: bump version v1.5.6 2020-05-03 22:10:32 +08:00
Dr_rOot 071b0a21c2 chore: bump version v1.5.5 2020-05-03 21:58:39 +08:00
Dr_rOot e25dfb143c Merge pull request #621 from agalwood/hotfix/prepare_release_202004280758
refactor: redesigned the lab page
2020-05-03 21:32:12 +08:00
Dr_rOot 652f04bada chore: bump version 2020-05-03 20:26:06 +08:00
Dr_rOot 5962334f3d feat: new lab page 2020-05-03 20:25:32 +08:00
Dr_rOot f984b175dc refactor: code format 2020-05-03 20:25:05 +08:00
Dr_rOot ad1979417a refactor: engine config 2020-04-30 22:22:48 +08:00
Dr_rOot 16822b9b55 Merge pull request #618 from agalwood/feature/upgrade_aria2_202004302143
feat: upgrade aria2 to v1.35.0
2020-04-30 22:15:34 +08:00
Dr_rOot 36551da19e refactor: arai2 config 2020-04-30 21:46:01 +08:00
Dr_rOot f3426fdc90 chore: upgrade aria2 version to 1.35.0
Compile it with reference to the script of q3aql/aria2-static-builds. The difference from the official version of Aria2 is that the max-connection-per-server is modified to 64.

https://github.com/q3aql/aria2-static-builds
2020-04-30 21:45:46 +08:00
Dr_rOot 94ead296bf docs: update readme 2020-04-30 13:26:40 +08:00
Dr_rOot 22a6f73e51 Merge pull request #616 from agalwood/feature/github_action_202004292314
feat: github action
2020-04-30 11:47:28 +08:00
Dr_rOot 94b4c08da9 fix: travis ci rpm 2020-04-30 11:03:52 +08:00
Dr_rOot 041b7701c2 fix: remove pacman 2020-04-30 00:23:27 +08:00
Dr_rOot c20d9b65ee fix: github action mac build notarize 2020-04-30 00:10:57 +08:00
Dr_rOot 47c5daea81 feat: test github action 2020-04-29 23:15:45 +08:00
Dr_rOot 9676e2a060 fix: remove ci node-sass config 2020-04-28 22:50:52 +08:00
Dr_rOot bb75fa6dcc refactor: change drag select color 2020-04-28 13:28:36 +08:00
Dr_rOot b547ef8f2e refactor: improve shutdown upnp speed 2020-04-28 13:22:20 +08:00
Dr_rOot cc44e21d0e feat: implemented menu pause & resume task 2020-04-28 13:22:20 +08:00
Dr_rOot 20ac050514 Merge pull request #615 from agalwood/hotfix/update_deps_202004271523
chore: update dependencies
2020-04-28 08:27:31 +08:00
Dr_rOot 7eeafb6c93 chore: update deps 2020-04-28 08:15:52 +08:00
Dr_rOot 6fd63c872f fix: windows aria2 cmd
revert forever-monitor version to 1.7.2

https://github.com/foreversd/forever-monitor/commit/93cfbef1c5248eeccf00f4d760c04625476aeb51#commitcomment-37379168
2020-04-28 07:56:54 +08:00
Dr_rOot b8b4f04423 chore: bump version 2020-04-27 23:36:30 +08:00
Dr_rOot e3e2abac6f chore: js code format 2020-04-27 23:33:48 +08:00
Dr_rOot b34f3ceb89 chore: vue code format 2020-04-27 23:30:17 +08:00
Dr_rOot feb07a43e1 chore: upgrade babel & eslint 2020-04-27 23:28:38 +08:00
Dr_rOot 4652672ef4 refactor: replace node-sass to dart-sass 2020-04-27 23:23:45 +08:00
Dr_rOot 8b375c019d refactor: code format 2020-04-27 17:59:45 +08:00
Dr_rOot e232e4af70 fix: upnp config watch 2020-04-27 10:02:12 +08:00
Dr_rOot f57d71cebe Merge pull request #611 from agalwood/feature/upnp_202004222153
feat: UPnP support

Closed #411
2020-04-26 23:08:27 +08:00
Dr_rOot 90daf4cb19 chore: bump version 2020-04-22 22:01:37 +08:00
Dr_rOot d1f759ec44 fix: update task progress info with 2020-04-22 22:00:22 +08:00
Dr_rOot 45ad6dfbda chore: update chrome ua 2020-04-22 21:59:35 +08:00
Dr_rOot 65d45f69fe fix: engine shutdown 2020-04-22 21:59:25 +08:00
Dr_rOot 7e626704ac feat: router upnp mapping 2020-04-22 21:58:53 +08:00
Dr_rOot e0f9dce952 Merge pull request #605 from agalwood/hotfix/app_improve_202004062214
refactor: app improve
Closed #588 #547 #491 #484 #481 #439 #425 #410 #376 #174 #106 #85 #27 #560 #413 #598 #551 #603
2020-04-21 18:01:26 +08:00
Dr_rOot edf627923e fix: after sign hook 2020-04-21 17:47:24 +08:00
Dr_rOot 40f7abcc22 fix: drag select components path at linux 2020-04-21 17:36:13 +08:00
Dr_rOot d837e97d02 fix: dev build html webpack plugin 2020-04-21 17:32:48 +08:00
Dr_rOot 13034b4e90 chore: update deps & bump version to 1.5.x 2020-04-21 17:32:30 +08:00
Dr_rOot b3826032ea refactor: max connection per server 2020-04-20 21:40:31 +08:00
Dr_rOot d5e9ada2c9 chore: i18n batch delete task 2020-04-19 15:32:51 +08:00
Dr_rOot 724a2a7f76 fix: aria2 bt conf 2020-04-18 18:02:07 +08:00
Dr_rOot 64326a11af feat: select all task hotkey 2020-04-18 18:01:26 +08:00
Dr_rOot b00536a0c7 feat: task list drag select & batch delete task 2020-04-18 17:31:11 +08:00
Dr_rOot 8885e63474 feat: drag select component
forked from andi23rosca/drag-select-vue
2020-04-18 16:47:14 +08:00
Dr_rOot 28936fd13e feat: batch remove task api 2020-04-18 16:21:00 +08:00
Dr_rOot 08a419f209 refactor: task progress info 2020-04-18 13:18:30 +08:00
Dr_rOot 8a3391c9f4 fix: restart task option split 2020-04-18 11:26:58 +08:00
Dr_rOot 3777a1f753 refactor: remove task 2020-04-18 11:26:11 +08:00
Dr_rOot b81298d6eb refactor: batch change task option api 2020-04-18 11:20:18 +08:00
Dr_rOot f67b9b8dd6 refactor: task status 2020-04-18 10:38:05 +08:00
Dr_rOot a303afb9a5 refactor: improve max connection per server 2020-04-17 22:44:35 +08:00
Dr_rOot eee07b1b7d chore: update readme features 2020-04-15 23:57:00 +08:00
Dr_rOot a27c49a376 chore: update readme 2020-04-15 21:23:21 +08:00
Dr_rOot fd81dc5194 fix: get random int util 2020-04-13 21:24:21 +08:00
Dr_rOot 394dfdfffc chore: i18n bt listen ports 2020-04-13 21:22:25 +08:00
Dr_rOot 99e9aa8046 feat: advanced preference bt listen ports setting 2020-04-12 22:23:43 +08:00
Dr_rOot ec295b3d72 refactor: is renderer linux mas 2020-04-12 19:57:10 +08:00
Dr_rOot 8208440987 feat: bt listen ports config 2020-04-12 19:52:37 +08:00
Dr_rOot 47426f2d66 refactor: import code format 2020-04-12 15:41:16 +08:00
Dr_rOot ac75a05511 refactor: tray manager 2020-04-12 15:31:23 +08:00
Dr_rOot c3ff1f3b23 refactor: log format 2020-04-11 14:22:15 +08:00
Dr_rOot 0f3157980c refactor: remove outdated trackers 2020-04-10 21:12:59 +08:00
Dr_rOot 36929f9dc5 feat: fetch task item peers api 2020-04-07 11:19:19 +08:00
Dr_rOot 11c507008b refactor: app quit 2020-04-06 22:32:44 +08:00
Dr_rOot 3d66549849 fix: preference diff changed 2020-04-06 22:15:44 +08:00
Dr_rOot 47ca535268 fix: main engine client add catch 2020-04-06 22:15:12 +08:00
Dr_rOot 7d102f9fcb fix: constants duplicate declaration 2020-04-06 22:11:22 +08:00
Dr_rOot edf350adf3 Merge pull request #596 from agalwood/hotfix/task_dir_202004061122
fix: several file path related issues

closed #575
2020-04-06 16:56:03 +08:00
Dr_rOot 651f28e7e8 refactor: add task type constant 2020-04-06 16:36:36 +08:00
Dr_rOot 4d7acb7c0a refactor: app theme constant 2020-04-06 16:31:42 +08:00
Dr_rOot b75e969a01 refactor: move task files to trash 2020-04-06 14:46:55 +08:00
Dr_rOot 0b6f5e7d43 refactor: show item in folder 2020-04-06 14:46:45 +08:00
Dr_rOot a82000a13b refactor: temp disabled prettifyDir 2020-04-06 11:27:44 +08:00
Dr_rOot edee889a1a docs: update travis-ci build status badge url 2020-04-05 23:19:29 +08:00
Dr_rOot afd2fdeabf Merge pull request #594 from agalwood/feature/proxy_setting_20200405227
feat: improve proxy setting
2020-04-05 23:18:43 +08:00
Dr_rOot 34011d7bc8 refactor: move rename utils location 2020-04-05 22:50:30 +08:00
Dr_rOot 6cf6b69f8e chore: i18n add task proxy 2020-04-05 22:49:58 +08:00
Dr_rOot a386c704e4 feat: add task support use proxy 2020-04-05 22:49:40 +08:00
Dr_rOot 0994244b0e chore: i18n no proxy input tip 2020-04-05 22:48:37 +08:00
Dr_rOot 777977e001 feat: advanced preference no proxy setting 2020-04-05 22:48:07 +08:00
Dr_rOot af5ac44dc8 Merge pull request #592 from agalwood/hotfix/update_ci_conf_202004052048
chore: update ci conf
2020-04-05 21:46:02 +08:00
Dr_rOot 23382a9415 chore: update ci conf 2020-04-05 20:50:55 +08:00
Dr_rOot 7b2da0f35b Merge pull request #590 from agalwood/feature/tracker_source_202002091515
feat: sync tracker add more source and support auto sync tracker data daily
2020-04-05 12:36:19 +08:00
Dr_rOot 4037dad582 docs: update readme add install electron guide 2020-03-22 23:32:45 +08:00
Dr_rOot 353ee23cfc feat: preference show last sync tracker time 2020-02-23 22:19:45 +08:00
Dr_rOot 29b0d90bc7 fix: Application showPage fn may cause memory leak
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 ready-to-show listeners added to [BrowserWindow]. Use emitter.setMaxListeners() to increase limit
2020-02-23 12:08:41 +08:00
Jiaqi Gu 073e514f95 feat: Automatically hide window when losing focus (#557)
Automatically hide window when losing focus
2020-02-23 11:59:19 +08:00
Dr_rOot a35fba4820 fix: i18n uk transfer settings 2020-02-22 15:47:28 +08:00
Dr_rOot 828d854eb5 chore: i18n sync tracker 2020-02-22 15:46:04 +08:00
Dr_rOot 5dbe157170 feat: auto sync tracker when app launch 2020-02-21 22:26:22 +08:00
Dr_rOot cdc196c2b0 refactor: save preference config 2020-02-21 22:21:05 +08:00
Dr_rOot 3d26445953 refactor: app updater auto check 2020-02-21 22:15:41 +08:00
Dr_rOot f887878b9e feat: main init engine client 2020-02-21 22:11:07 +08:00
Dr_rOot 908f60df1a feat: advanced preference auto sync tracker 2020-02-21 22:04:45 +08:00
Dr_rOot 56c9b58d87 refactor: advanced preference sync tracker 2020-02-20 19:29:54 +08:00
Dr_rOot d56983d45d refactor: fetch bt tracker data 2020-02-20 19:23:48 +08:00
Dr_rOot 8775e12587 refactor: launcher callback 2020-02-19 20:45:48 +08:00
Dr_rOot df2e01813e feat: add trackers blacklist constant 2020-02-18 17:08:01 +08:00
Dr_rOot d77a6faf36 fix: aria2 bt conf 2020-02-16 13:42:46 +08:00
Dr_rOot 5e735b513d feat: task show connections 2020-02-12 16:12:57 +08:00
Dr_rOot 64f0a3db80 fix: sync old data when tracker source changed 2020-02-10 11:05:38 +08:00
Dr_rOot e470ed00d6 refactor: engine rpc config 2020-02-09 15:51:01 +08:00
Dr_rOot 36a27bae46 feat: preference select sync tracker source 2020-02-09 15:44:55 +08:00
Dr_rOot 5d900806e8 fix: system engine config keys 2020-02-09 15:34:45 +08:00
Dr_rOot ace14c85dc refactor: improve ui style 2020-02-09 15:33:13 +08:00
Dr_rOot 3ec4bd26e6 refactor: update manager last check update time 2020-02-09 15:32:04 +08:00
Dr_rOot b9bc5e6c07 feat: auto remove aria2c unrecognized options 2020-02-09 15:23:00 +08:00
Dr_rOot 021fbc243a refactor: rename & add tracker source 2020-02-09 15:21:55 +08:00
Dr_rOot 8b66f2ea6e refactor: make tracker unique 2020-02-09 15:18:11 +08:00
Dr_rOot 7703c28c6e Merge pull request #544 from agalwood/feature/win_title_bar_202002081321
feat: improve win & linux title bar style

Closes #461
2020-02-08 16:07:08 +08:00
Dr_rOot 26db88ec51 refactor: adjust close btn color for win & linux 2020-02-08 13:23:35 +08:00
Dr_rOot 51b7ea4030 refactor: remove title bar button spacing 2020-02-08 13:22:02 +08:00
Dr_rOot 1e2368dd3b docs: update contribution guide 2020-02-08 12:50:04 +08:00
Dr_rOot f28c3ae5c5 fix: adapt the new api of Electron's TouchBar 2020-02-06 22:22:00 +08:00
Dr_rOot ebdd125d91 Merge pull request #529 from agalwood/feature/proxy_tip_202001311802
feat: Perference advanced panel add proxy tip

close #488
2020-01-31 18:50:14 +08:00
Dr_rOot 9bcc386269 feat: perference advanced proxy tip i18n 2020-01-31 18:16:04 +08:00
Dr_rOot 27c48af278 feat: advanced perference add proxy tip 2020-01-31 18:15:37 +08:00
Dr_rOot 4b4df884dc Merge pull request #528 from agalwood/feature/run_mode_202001311505
feature: Preferences add Run Mode setting

close #345 #350
2020-01-31 16:02:10 +08:00
Dr_rOot 64082ddd70 fix: i18n rename appLocalePtBr to appLocalePtBR 2020-01-31 15:45:12 +08:00
Dr_rOot 188a39d0d2 refactor: i18n rename ru-RU to ru 2020-01-31 15:44:30 +08:00
Dr_rOot 44f8f23a7c feat: run mode i18n 2020-01-31 15:37:56 +08:00
Dr_rOot 32340218e2 refactor: change dock state use DockManager 2020-01-31 15:20:01 +08:00
Dr_rOot 85a8430c3f refactor: ipc change update menu state to command 2020-01-31 15:17:45 +08:00
Dr_rOot e47816e273 refactor: save preference use ipc message 2020-01-31 15:15:55 +08:00
Dr_rOot b7356702fc feat: add DockManager 2020-01-31 15:10:51 +08:00
Dr_rOot a61c857e11 feat: add run mode config 2020-01-31 15:09:31 +08:00
Dr_rOot d3ef30d943 refactor: speed options i18n 2020-01-31 15:07:49 +08:00
Dr_rOot b8d5eb5ac1 fix: add task out i18n 2020-01-31 15:06:14 +08:00
Dr_rOot aeaf0fe9ca Merge pull request #527 from agalwood/feature/improve_responsive_202001311239
feature: improve responsive 202001311239
2020-01-31 14:20:24 +08:00
Dr_rOot 8bebb942ca fix: remove TaskSwitch 2020-01-31 14:11:25 +08:00
Dr_rOot f0e795f00c refactor: code format 2020-01-31 12:49:24 +08:00
Dr_rOot 7d4eec6b02 feat: preference responsive subnav switcher 2020-01-31 12:45:30 +08:00
Dr_rOot fe2dc7a541 refactor: task subnav switcher 2020-01-31 12:42:39 +08:00
Dr_rOot 848b9e78e1 Merge pull request #525 from agalwood/hotfix/fix_open_dialog_202001301122
fix: electron v7 dialog showOpenDialog promisify
2020-01-30 15:14:00 +08:00
Dr_rOot 2fa33f75e5 fix: electron v7 dialog showOpenDialog promisify 2020-01-30 11:25:34 +08:00
Dr_rOot 1f6c2a6ff0 Merge pull request #524 from agalwood/hotfix/upgrade_deps_202001232019
fix: upgrade deps 202001232019
2020-01-30 00:05:09 +08:00
Dr_rOot a8e3c7843c fix: ci node sass 2020-01-29 23:52:04 +08:00
Dr_rOot 8b1ba2425c chore: update ci 2020-01-29 23:37:19 +08:00
Dr_rOot 47acf4fad1 fix: remove select torrent checkbox ellipsis 2020-01-28 13:55:53 +08:00
Dr_rOot 9beb48be92 fix: wrong eslint rule place 2020-01-28 13:55:17 +08:00
Dr_rOot bbe52a2a18 chore: update chrome ua 2020-01-28 13:54:27 +08:00
Dr_rOot 0b73028412 refactor: app info engine title style 2020-01-26 23:21:33 +08:00
Dr_rOot 2311a7ed86 fix: catch vue router NavigationDuplicated error 2020-01-25 02:41:46 +08:00
Dr_rOot 95ed300d1b refactor: nativeTheme.shouldUseDarkColors
systemPreferences.isDarkMode()
**Deprecated:** Should use the new `nativeTheme.shouldUseDarkColors` API.
2020-01-25 02:37:28 +08:00
Dr_rOot dcd2d50c83 refactor: dialog.showMessageBox promisify 2020-01-24 22:17:06 +08:00
Dr_rOot 57ed6c7941 chore: upgrade deps 2020-01-23 21:40:12 +08:00
Dr_rOot 870c4089fb refactor: replace babili with terser 2020-01-23 21:39:00 +08:00
Dr_rOot 1082f9330e refactor: upgrade sass loader 2020-01-23 21:37:15 +08:00
Dr_rOot a7f33869a0 chore: daysUntilLock increase to 60 2020-01-05 17:12:01 +08:00
han 89336dda37 feat: make Motrix layout more responsive (#505) 2020-01-05 17:07:09 +08:00
Dr_rOot 4240dee426 Merge pull request #472 from kant/patch-6
fix: Typos fixed and some translation redone
2019-12-12 16:20:33 +08:00
Dr_rOot 83c1c1340e Merge pull request #471 from kant/patch-5
fix: Typos fixed and some translations redone
2019-12-12 16:20:24 +08:00
Dr_rOot 408e33adb1 Merge pull request #470 from kant/patch-4
fix: Typos and bad translations redone
2019-12-12 16:20:15 +08:00
Dr_rOot d2dde274d3 Merge pull request #469 from kant/patch-2
fix: Typo fixed on line 02
2019-12-12 16:20:03 +08:00
Darío Hereñú 7b27f82f1e Typos fixed and some translation redone 2019-11-11 01:49:12 -03:00
Darío Hereñú 2d32a2848c Typos fixed and some translations redone 2019-11-11 01:39:32 -03:00
Darío Hereñú c128689b2e Typos and translation redone 2019-11-11 01:32:57 -03:00
Darío Hereñú 7702aa6ca1 Typos and bad translations redone 2019-11-11 01:29:28 -03:00
Darío Hereñú 2fb32fa347 Typo fixed on line 02 2019-11-11 01:24:48 -03:00
Dr_rOot 2744db2d75 docs: update readme i18n add ca 2019-11-05 23:15:31 +08:00
Dr_rOot adb060b076 Merge pull request #467 from marcizhu/master
feat: add Catalan translation
2019-11-05 23:07:21 +08:00
marcizhu 561d7608d8 feat: add Catalan translation 2019-11-05 11:53:01 +01:00
Dr_rOot 06d9a95827 Merge pull request #424 from agalwood/hotfix/webpack_config_4node12_201909161132
fix: process is not defined at node 12.x #267
2019-09-16 12:08:32 +08:00
Dr_rOot 9c386c4bdc fix: process is not defined at node 12.x #267
https://github.com/SimulatedGREG/electron-vue/issues/871#issuecomment-490370237
2019-09-16 11:34:12 +08:00
Dr_rOot a1eb48926a Merge pull request #420 from agalwood/feature/custom_tracker_source_201909091524
feat: user config custom tracker source
2019-09-09 16:03:58 +08:00
Dr_rOot c1ed827244 feat: add custom tracker source to user config 2019-09-09 15:49:28 +08:00
Dr_rOot 663e1a2db1 refactor: empty string constant 2019-09-09 15:47:56 +08:00
Dr_rOot c0a2b50b9f Merge pull request #419 from agalwood/hotfix/fix_energy_manager_201909091450
fix: stopPowerSaveBlocker when psbId = 0

closed #418
2019-09-09 15:22:04 +08:00
Dr_rOot a843ae4553 fix: stopPowerSaveBlocker when psbId = 0 2019-09-09 14:49:35 +08:00
Rodolfo Robles d195b23512 feat: Spanish Translation (#385) 2019-08-08 11:16:39 +08:00
Zaoqi f6c84b7e57 docs: add extra/README.md 2019-08-06 10:41:46 +08:00
Dr_rOot 98df9c3f2a fix: magnet and thunder protocol handle 2019-07-22 20:04:36 +08:00
Dr_rOot 7e703eb552 chore: update license copyright 2019-07-21 12:38:34 +08:00
Dr_rOot 87bcac6122 fix: update copyright #365
Closed #365
2019-07-21 12:38:27 +08:00
Dr_rOot 6935a12289 chore: readme i18n add ru 2019-07-13 22:49:40 +08:00
Dr_rOot 39688b667e Merge pull request #358 from bladeaweb/feature/ru
feat: Added Russian localisation.
2019-07-13 22:43:53 +08:00
Alexander Sharkov f174887f9f fix: Removed not requirement changes. 2019-07-13 17:08:37 +03:00
Alexander Sharkov caba086651 fix: Fixed some required changes of language short name. 2019-07-13 16:06:41 +03:00
Dr_rOot b627b38985 Merge pull request #357 from bladeaweb/feature/uk
fix: Fixed spelling issue.
2019-07-13 20:31:12 +08:00
Alexander Sharkov 1c35d72aa5 fix: Fixed spelling issue. 2019-07-13 15:06:17 +03:00
Alexander Sharkov 8ecbfdd66d feat: Added Russian localisation. 2019-07-13 15:03:39 +03:00
Dr_rOot 3be568f6ab Merge pull request #354 from agalwood/hotfix/preferences_changed_201907042031
fix: preferences changed data outdated
2019-07-11 11:35:01 +08:00
Dr_rOot fa29c11c73 Merge pull request #353 from agalwood/feature/shift_delete_201907032126
feat: shift delete task with files
2019-07-10 21:42:00 +08:00
Dr_rOot 6b153d68b4 docs: add tips of first launch in linux 2019-07-08 15:55:18 +08:00
Dr_rOot 852266dc16 refactor: preferences function 2019-07-04 21:09:39 +08:00
Dr_rOot 4170cd3419 refactor: lab preferences 2019-07-04 21:04:34 +08:00
Dr_rOot a15870871f fix: advanced preferences changed 2019-07-04 20:57:24 +08:00
Dr_rOot 571499caad fix: basic preferences changed 2019-07-04 20:37:56 +08:00
Dr_rOot 766c2c26b8 feat: shift trash task auto checked remove files 2019-07-03 21:34:27 +08:00
Dr_rOot 1f27f88aa7 feat: shift delete task auto checked remove files 2019-07-03 21:34:11 +08:00
Dr_rOot e06888e998 chore: add pull request template 2019-07-02 20:21:11 +08:00
Dr_rOot 91a2d0a270 Merge pull request #341 from agalwood/feature/download_outs_201907011638
feat: add task out support rule #326

Closed #326
2019-07-01 20:33:06 +08:00
Dr_rOot 8e3fe4c980 refactor: buildRule operator default PLUS 2019-07-01 20:16:26 +08:00
Dr_rOot f3724107f0 refactor: rule operators 2019-07-01 20:14:02 +08:00
Dr_rOot 580c32a2b9 Merge pull request #340 from agalwood/feature/save_preferences_201906271147
fix: check changed preferences is need restart
2019-07-01 18:56:10 +08:00
Dr_rOot 575712ba9f feat: add task support out rule #326
Out rule sample:
abc_(001+).jpg
xyz_(100-2).html
2019-07-01 18:35:10 +08:00
Dr_rOot 84006f348c feat: add buildOuts util 2019-07-01 18:22:04 +08:00
Dr_rOot a9759441d3 chore: update readme 2019-06-30 10:44:11 +08:00
Dr_rOot 728f8e9019 fix: readme i18n typo #338
closed #338
2019-06-30 10:43:27 +08:00
Dr_rOot e814210896 chore: update getLanguage comments 2019-06-29 00:24:54 +08:00
Dr_rOot a0c6877524 fix: remove useless fallback 2019-06-29 00:24:44 +08:00
Dr_rOot 29b0dd627d Merge pull request #334 from bladeaweb/feature/uk
feat: added Ukrainian localisation.
2019-06-29 00:10:16 +08:00
Alexander Sharkov dc48cad7e8 Added: Ukrainian localisation. 2019-06-28 12:47:26 +03:00
Dr_rOot 35df1c799b fix: check changed preferences is need restart 2019-06-27 15:03:08 +08:00
Dr_rOot 912e661c02 chore: update developer tools tips 2019-06-27 11:32:58 +08:00
407 changed files with 25865 additions and 25573 deletions
+7 -17
View File
@@ -2,19 +2,11 @@
"comments": false,
"env": {
"main": {
"presets": [
["env", {
"targets": { "node": 7 }
}],
"stage-0"
]
"presets": ["@babel/preset-env"]
},
"renderer": {
"presets": [
["env", {
"modules": false
}],
"stage-0"
"@babel/preset-env"
],
"plugins": [
[
@@ -27,12 +19,7 @@
]
},
"web": {
"presets": [
["env", {
"modules": false
}],
"stage-0"
],
"presets": ["@babel/preset-env"],
"plugins": [
[
"component",
@@ -44,5 +31,8 @@
]
}
},
"plugins": ["transform-runtime"]
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-transform-runtime"
]
}
+26 -19
View File
@@ -5,10 +5,8 @@ process.env.NODE_ENV = 'production'
const { say } = require('cfonts')
const chalk = require('chalk')
const del = require('del')
const { spawn } = require('child_process')
const webpack = require('webpack')
const Multispinner = require('multispinner')
const Webpack = require('webpack')
const Multispinner = require('@motrix/multispinner')
const mainConfig = require('./webpack.main.config')
const rendererConfig = require('./webpack.renderer.config')
@@ -19,12 +17,16 @@ const errorLog = chalk.bgRed.white(' ERROR ') + ' '
const okayLog = chalk.bgBlue.white(' OKAY ') + ' '
const isCI = process.env.CI || false
if (process.env.BUILD_TARGET === 'clean') clean()
else if (process.env.BUILD_TARGET === 'web') web()
else build()
if (process.env.BUILD_TARGET === 'clean') {
clean()
} else if (process.env.BUILD_TARGET === 'web') {
web()
} else {
build()
}
function clean () {
del.sync(['build/*', '!build/icons', '!build/icons/icon.*'])
del.sync(['release/*', '!.gitkeep'])
console.log(`\n${doneLog}\n`)
process.exit()
}
@@ -73,9 +75,10 @@ function build () {
function pack (config) {
return new Promise((resolve, reject) => {
config.mode = 'production'
webpack(config, (err, stats) => {
if (err) reject(err.stack || err)
else if (stats.hasErrors()) {
Webpack(config, (err, stats) => {
if (err) {
reject(err.stack || err)
} else if (stats.hasErrors()) {
let err = ''
stats.toString({
@@ -99,9 +102,9 @@ function pack (config) {
}
function web () {
del.sync(['dist/web/*', '!.gitkeep'])
deleteSync(['dist/web/*', '!.gitkeep'])
webConfig.mode = 'production'
webpack(webConfig, (err, stats) => {
Webpack(webConfig, (err, stats) => {
if (err || stats.hasErrors()) console.log(err)
console.log(stats.toString({
@@ -117,16 +120,20 @@ function greeting () {
const cols = process.stdout.columns
let text = ''
if (cols > 85) text = 'lets-build'
else if (cols > 60) text = 'lets-|build'
else text = false
if (cols > 85) {
text = 'lets-build'
} else if (cols > 60) {
text = 'lets-|build'
} else {
text = false
}
if (text && !isCI) {
say(text, {
colors: ['yellow'],
colors: ['magentaBright'],
font: 'simple3d',
space: false
})
} else console.log(chalk.yellow.bold('\n lets-build'))
} else console.log(chalk.magentaBright.bold('\n lets-build'))
console.log()
}
}
+29 -46
View File
@@ -1,20 +1,18 @@
'use strict'
const chalk = require('chalk')
const electron = require('electron')
const path = require('path')
const path = require('node:path')
const { spawn } = require('node:child_process')
const { say } = require('cfonts')
const { spawn } = require('child_process')
const webpack = require('webpack')
const electron = require('electron')
const chalk = require('chalk')
const Webpack = require('webpack')
const WebpackDevServer = require('webpack-dev-server')
const webpackHotMiddleware = require('webpack-hot-middleware')
const mainConfig = require('./webpack.main.config')
const rendererConfig = require('./webpack.renderer.config')
let electronProcess = null
let manualRestart = false
let hotMiddleware
function logStats (proc, data) {
let log = ''
@@ -39,41 +37,22 @@ function logStats (proc, data) {
}
function startRenderer () {
return new Promise((resolve, reject) => {
rendererConfig.entry.index = [path.join(__dirname, 'dev-client')].concat(rendererConfig.entry.index)
return new Promise(async (resolve, reject) => {
rendererConfig.entry.index = rendererConfig.entry.index
rendererConfig.mode = 'development'
const compiler = webpack(rendererConfig)
hotMiddleware = webpackHotMiddleware(compiler, {
log: false,
heartbeat: 2500
})
compiler.hooks.compilation.tap('compilation', compilation => {
compilation.hooks.htmlWebpackPluginAfterEmit.tapAsync('html-webpack-plugin-after-emit', (data, cb) => {
hotMiddleware.publish({ action: 'reload' })
cb()
})
})
const compiler = Webpack(rendererConfig)
const devServerOptions = {
...rendererConfig.devServer,
port: 9080,
static: {
directory: path.resolve(__dirname, "../"),
},
};
compiler.hooks.done.tap('done', stats => {
logStats('Renderer', stats)
})
const server = new WebpackDevServer(
compiler,
{
contentBase: path.join(__dirname, '../'),
quiet: true,
before (app, ctx) {
app.use(hotMiddleware)
ctx.middleware.waitUntilValid(() => {
resolve()
})
}
}
)
server.listen(9080)
const server = new WebpackDevServer(devServerOptions, compiler)
await server.start()
resolve()
})
}
@@ -81,11 +60,11 @@ function startMain () {
return new Promise((resolve, reject) => {
mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.js')].concat(mainConfig.entry.main)
mainConfig.mode = 'development'
const compiler = webpack(mainConfig)
const compiler = Webpack(mainConfig)
compiler.hooks.watchRun.tapAsync('watch-run', (compilation, done) => {
logStats('Main', chalk.white.bold('compiling...'))
hotMiddleware.publish({ action: 'compiling' })
// hotMiddleware.publish({ action: 'compiling' })
done()
})
@@ -149,17 +128,21 @@ function greeting () {
const cols = process.stdout.columns
let text = ''
if (cols > 104) text = 'electron-vue'
else if (cols > 76) text = 'electron-|vue'
else text = false
if (cols > 104) {
text = 'motrix-dev'
} else if (cols > 76) {
text = 'motrix-|dev'
} else {
text = false
}
if (text) {
say(text, {
colors: ['yellow'],
colors: ['magentaBright'],
font: 'simple3d',
space: false
})
} else console.log(chalk.yellow.bold('\n electron-vue'))
} else console.log(chalk.magentaBright.bold('\n motrix-dev'))
console.log(chalk.blue(' getting ready...') + '\n')
}
+23 -23
View File
@@ -2,12 +2,13 @@
process.env.BABEL_ENV = 'main'
const path = require('node:path')
const Webpack = require('webpack')
const ESLintPlugin = require('eslint-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const { dependencies } = require('../package.json')
const { appId } = require('../electron-builder.json')
const devMode = process.env.NODE_ENV !== 'production'
const path = require('path')
const { dependencies, build } = require('../package.json')
const webpack = require('webpack')
const BabiliWebpackPlugin = require('babili-webpack-plugin')
let mainConfig = {
entry: {
@@ -18,17 +19,6 @@ let mainConfig = {
],
module: {
rules: [
{
test: /\.(js)$/,
enforce: 'pre',
exclude: /node_modules/,
use: {
loader: 'eslint-loader',
options: {
formatter: require('eslint-friendly-formatter')
}
}
},
{
test: /\.js$/,
use: 'babel-loader',
@@ -50,7 +40,10 @@ let mainConfig = {
path: path.join(__dirname, '../dist/electron')
},
plugins: [
new webpack.NoEmitOnErrorsPlugin()
new Webpack.NoEmitOnErrorsPlugin(),
new ESLintPlugin({
formatter: require('eslint-friendly-formatter')
})
],
resolve: {
alias: {
@@ -59,7 +52,15 @@ let mainConfig = {
},
extensions: ['.js', '.json', '.node']
},
target: 'electron-main'
target: 'electron-main',
optimization: {
minimize: !devMode,
minimizer: [
new TerserPlugin({
extractComments: false,
})
],
},
}
/**
@@ -67,9 +68,9 @@ let mainConfig = {
*/
if (devMode) {
mainConfig.plugins.push(
new webpack.DefinePlugin({
new Webpack.DefinePlugin({
'__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`,
'appId': `"${build.appId}"`
'appId': `"${appId}"`
})
)
}
@@ -79,10 +80,9 @@ if (devMode) {
*/
if (!devMode) {
mainConfig.plugins.push(
new BabiliWebpackPlugin(),
new webpack.DefinePlugin({
new Webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"',
'appId': `"${build.appId}"`
'appId': `"${appId}"`
})
)
}
+57 -66
View File
@@ -2,17 +2,17 @@
process.env.BABEL_ENV = 'renderer'
const devMode = process.env.NODE_ENV !== 'production'
const path = require('path')
const { dependencies } = require('../package.json')
const webpack = require('webpack')
const BabiliWebpackPlugin = require('babili-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('node:path')
const Webpack = require('webpack')
const { VueLoaderPlugin } = require('vue-loader')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const ESLintPlugin = require('eslint-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const { dependencies } = require('../package.json')
const devMode = process.env.NODE_ENV !== 'production'
/**
* List of node_modules to include in webpack bundle
@@ -24,7 +24,6 @@ const { VueLoaderPlugin } = require('vue-loader')
let whiteListedModules = ['vue']
let rendererConfig = {
devtool: '#cheap-module-eval-source-map',
entry: {
index: path.join(__dirname, '../src/renderer/pages/index/main.js')
},
@@ -34,14 +33,10 @@ let rendererConfig = {
module: {
rules: [
{
test: /\.(js|vue)$/,
enforce: 'pre',
exclude: /node_modules/,
test: /\.worker\.js$/,
use: {
loader: 'eslint-loader',
options: {
formatter: require('eslint-friendly-formatter')
}
loader: 'worker-loader',
options: { filename: '[name].js' }
}
},
{
@@ -52,8 +47,11 @@ let rendererConfig = {
{
loader: 'sass-loader',
options: {
data: '@import "@/components/Theme/Variables.scss";',
includePaths:[__dirname, 'src']
implementation: require('sass'),
additionalData: '@import "@/components/Theme/Variables.scss";',
sassOptions: {
includePaths:[__dirname, 'src']
}
},
}
]
@@ -66,9 +64,12 @@ let rendererConfig = {
{
loader: 'sass-loader',
options: {
implementation: require('sass'),
indentedSyntax: true,
data: '@import "@/components/Theme/Variables.scss";',
includePaths:[__dirname, 'src']
additionalData: '@import "@/components/Theme/Variables.scss";',
sassOptions: {
includePaths:[__dirname, 'src']
}
},
}
]
@@ -88,10 +89,6 @@ let rendererConfig = {
'css-loader'
]
},
{
test: /\.html$/,
use: 'vue-html-loader'
},
{
test: /\.js$/,
use: 'babel-loader',
@@ -117,31 +114,15 @@ let rendererConfig = {
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: {
loader: 'url-loader',
query: {
limit: 10000,
name: 'imgs/[name]--[folder].[ext]'
}
}
type: 'asset/inline'
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'media/[name]--[folder].[ext]'
}
type: 'asset/resource'
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: {
loader: 'url-loader',
query: {
limit: 10000,
name: 'fonts/[name]--[folder].[ext]'
}
}
type: 'asset/inline'
}
]
},
@@ -155,12 +136,6 @@ let rendererConfig = {
filename: '[name].css',
chunkFilename: '[id].css'
}),
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true,
discardComments: { removeAll: true }
}
}),
new HtmlWebpackPlugin({
title: 'Motrix',
filename: 'index.html',
@@ -171,17 +146,25 @@ let rendererConfig = {
// removeAttributeQuotes: true,
// removeComments: true
// },
isBrowser: false,
isDev: process.env.NODE_ENV !== 'production',
nodeModules: devMode
? path.resolve(__dirname, '../node_modules')
: false
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
new Webpack.HotModuleReplacementPlugin(),
new Webpack.NoEmitOnErrorsPlugin(),
new ESLintPlugin({
extensions: ['js', 'vue'],
formatter: require('eslint-friendly-formatter')
})
],
output: {
filename: '[name].js',
libraryTarget: 'commonjs2',
path: path.join(__dirname, '../dist/electron')
path: path.join(__dirname, '../dist/electron'),
globalObject: 'this',
publicPath: ''
},
resolve: {
alias: {
@@ -191,15 +174,26 @@ let rendererConfig = {
},
extensions: ['.js', '.vue', '.json', '.css', '.node']
},
target: 'electron-renderer'
target: 'electron-renderer',
optimization: {
minimize: !devMode,
minimizer: [
new TerserPlugin({
extractComments: false,
}),
new CssMinimizerPlugin(),
],
},
}
/**
* Adjust rendererConfig for development settings
*/
if (devMode) {
rendererConfig.devtool = 'eval-cheap-module-source-map'
rendererConfig.plugins.push(
new webpack.DefinePlugin({
new Webpack.DefinePlugin({
'__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
})
)
@@ -209,21 +203,18 @@ if (devMode) {
* Adjust rendererConfig for production settings
*/
if (!devMode) {
rendererConfig.devtool = ''
rendererConfig.plugins.push(
new BabiliWebpackPlugin(),
new CopyWebpackPlugin([
{
new CopyWebpackPlugin({
patterns: [{
from: path.join(__dirname, '../static'),
to: path.join(__dirname, '../dist/electron/static'),
ignore: ['.*']
}
]),
new webpack.DefinePlugin({
globOptions: { ignore: [ '.*' ] }
}]
}),
new Webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
}),
new webpack.LoaderOptionsPlugin({
new Webpack.LoaderOptionsPlugin({
minimize: false
})
)
+72 -55
View File
@@ -2,17 +2,17 @@
process.env.BABEL_ENV = 'web'
const devMode = process.env.NODE_ENV !== 'production'
const path = require('path')
const path = require('node:path')
const { dependencies } = require('../package.json')
const webpack = require('webpack')
const BabiliWebpackPlugin = require('babili-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const Webpack = require('webpack')
const { VueLoaderPlugin } = require('vue-loader')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const ESLintPlugin = require('eslint-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const devMode = process.env.NODE_ENV !== 'production'
/**
* List of node_modules to include in webpack bundle
@@ -24,7 +24,6 @@ const { VueLoaderPlugin } = require('vue-loader')
let whiteListedModules = ['vue']
let webConfig = {
devtool: '#cheap-module-eval-source-map',
entry: {
index: path.join(__dirname, '../src/renderer/pages/index/main.js')
},
@@ -34,14 +33,10 @@ let webConfig = {
module: {
rules: [
{
test: /\.(js|vue)$/,
enforce: 'pre',
exclude: /node_modules/,
test: /\.worker\.js$/,
use: {
loader: 'eslint-loader',
options: {
formatter: require('eslint-friendly-formatter')
}
loader: 'worker-loader',
options: { filename: '[name].js' }
}
},
{
@@ -49,7 +44,16 @@ let webConfig = {
use: [
devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader'
{
loader: 'sass-loader',
options: {
implementation: require('sass'),
additionalData: '@import "@/components/Theme/Variables.scss"',
sassOptions: {
includePaths:[__dirname, 'src']
}
},
}
]
},
{
@@ -57,7 +61,17 @@ let webConfig = {
use: [
devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader?indentedSyntax'
{
loader: 'sass-loader',
options: {
implementation: require('sass'),
indentedSyntax: true,
additionalData: '@import "@/components/Theme/Variables.scss"',
sassOptions: {
includePaths:[__dirname, 'src']
}
},
}
]
},
{
@@ -97,23 +111,11 @@ let webConfig = {
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: {
loader: 'url-loader',
query: {
limit: 10000,
name: 'imgs/[name].[ext]'
}
}
type: 'asset/inline'
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: {
loader: 'url-loader',
query: {
limit: 10000,
name: 'fonts/[name].[ext]'
}
}
type: 'asset/inline'
}
]
},
@@ -123,12 +125,6 @@ let webConfig = {
filename: '[name].css',
chunkFilename: '[id].css'
}),
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true,
discardComments: { removeAll: true }
}
}),
new HtmlWebpackPlugin({
title: 'Motrix',
filename: 'index.html',
@@ -139,19 +135,27 @@ let webConfig = {
// removeAttributeQuotes: true,
// removeComments: true
// },
isBrowser: true,
isDev: process.env.NODE_ENV !== 'production',
nodeModules: devMode
? path.resolve(__dirname, '../node_modules')
: false
}),
new webpack.DefinePlugin({
new Webpack.DefinePlugin({
'process.env.IS_WEB': 'true'
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
new Webpack.HotModuleReplacementPlugin(),
new Webpack.NoEmitOnErrorsPlugin(),
new ESLintPlugin({
extensions: ['js', 'vue'],
formatter: require('eslint-friendly-formatter')
})
],
output: {
filename: '[name].js',
path: path.join(__dirname, '../dist/web')
path: path.join(__dirname, '../dist/web'),
globalObject: 'this',
publicPath: ''
},
resolve: {
alias: {
@@ -161,28 +165,41 @@ let webConfig = {
},
extensions: ['.js', '.vue', '.json', '.css']
},
target: 'web'
target: 'web',
optimization: {
minimize: !devMode,
minimizer: [
new TerserPlugin({
extractComments: false,
}),
new CssMinimizerPlugin(),
],
},
}
/**
* Adjust webConfig for development settings
*/
if (devMode) {
webConfig.devtool = 'eval-cheap-module-source-map'
}
/**
* Adjust webConfig for production settings
*/
if (!devMode) {
webConfig.devtool = ''
webConfig.plugins.push(
new BabiliWebpackPlugin(),
new CopyWebpackPlugin([
{
new CopyWebpackPlugin({
patterns: [{
from: path.join(__dirname, '../static'),
to: path.join(__dirname, '../dist/web/static'),
ignore: ['.*']
}
]),
new webpack.DefinePlugin({
to: path.join(__dirname, '../dist/electron/static'),
globOptions: { ignore: [ '.*' ] }
}]
}),
new Webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
}),
new webpack.LoaderOptionsPlugin({
new Webpack.LoaderOptionsPlugin({
minimize: true
})
)
+7
View File
@@ -0,0 +1,7 @@
src/renderer/components/Icons/*.js
src/shared/locales/*
!src/shared/locales/all.js
!src/shared/locales/app.js
!src/shared/locales/index.js
!src/shared/locales/LocalManager.js
+23 -16
View File
@@ -1,27 +1,34 @@
module.exports = {
root: true,
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module'
},
env: {
browser: true,
node: true
},
extends: 'standard',
extends: [
'plugin:vue/essential',
'@vue/standard'
],
parserOptions: {
parser: 'babel-eslint'
},
globals: {
appId: true,
__static: true
},
plugins: [
'html'
],
'rules': {
// allow paren-less arrow functions
'arrow-parens': 0,
// allow async-await
'generator-star-spacing': 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
}
rules: {
'no-console': 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
indent: ['error', 2],
'vue/script-indent': ['error', 2, {
baseIndent: 1
}]
},
overrides: [
{
files: ['*.vue'],
rules: {
indent: 'off'
}
}
]
}
+76
View File
@@ -0,0 +1,76 @@
name: 🐛 [NEW] Bug Report
description: File a bug report here
title: "[BUG]: "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report 🤗
Make sure there aren't any open/closed issues for this topic 😃
- type: textarea
id: bug-description
attributes:
label: Description of the bug
description: Give us a brief description of what happened and what should have happened
validations:
required: true
- type: textarea
id: app-version
attributes:
label: Motrix Version
description: Please provide detailed version information and installation method, such as macOS Apple silicon dmg, Windows Universal installation file, etc.
validations:
required: true
- type: textarea
attributes:
label: Environment
description: |
Run this command in your project's root folder and paste the result:
```sh
npx envinfo --system --binaries --browsers
```
add `| pbcopy` if you're in macOS for easy copy paste.
Alternatively, you can manually gather the version information from your environment.
validations:
required: true
- type: textarea
id: steps-to-reproduce
attributes:
label: Steps To Reproduce
description: Steps to reproduce the behavior.
placeholder: |
1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. See error
More info: A [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) is **required**, otherwise the issue might be closed without further notice. [**Why & How?**](https://antfu.me/posts/why-reproductions-are-required)
validations:
required: true
- type: textarea
id: additional-information
attributes:
label: Additional Information
description: |
Provide any additional information such as logs, screenshots, likes, scenarios in which the bug occurs so that it facilitates resolving the issue.
- type: checkboxes
id: checkboxes
attributes:
label: Validations
description: Before submitting the issue, please make sure you do the following
options:
- label: Follow our [Code of Conduct](https://github.com/agalwood/Motrix/blob/master/CODE_OF_CONDUCT.md)
required: true
- label: Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
required: true
- label: Check that this is a concrete bug. For Q&A, please open a [GitHub Discussion](https://github.com/agalwood/Motrix/discussions) instead.
required: true
- label: The provided reproduction is a [minimal reproducible](https://stackoverflow.com/help/minimal-reproducible-example) of the bug.
required: true
@@ -0,0 +1,76 @@
name: 🐛 [新] Bug 报告
description: 在这里提交 Bug 报告
title: "[BUG]: "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
感谢您抽出时间来填写这份 Bug 报告 🤗
请确保此问题没有已存在的开放/关闭问题 😃
- type: textarea
id: bug-description
attributes:
label: Bug 描述
description: 给我们一个简短的描述,说明发生了什么以及应该发生什么。
validations:
required: true
- type: textarea
id: app-version
attributes:
label: Motrix 版本
description: 请提供详细的版本信息以及安装的方式,如 macOS Apple silicon dmg、Windows Universal 安装文件等
validations:
required: true
- type: textarea
attributes:
label: 环境
description: |
在项目的根目录下运行以下命令,并将结果粘贴到下方:
```sh
npx envinfo --system --binaries --browsers
```
在 macOS 中,如果您需要轻松复制粘贴,可以添加 `| pbcopy`。
或者,您也可以手动收集您的环境版本信息。
validations:
required: true
- type: textarea
id: steps-to-reproduce
attributes:
label: 复现步骤
description: 复现该问题的步骤。
placeholder: |
1. 前往 '...'
2. 点击 '...'
3. 滚动到 '...'
4. 查看错误
更多信息:[最小复现例子](https://stackoverflow.com/help/minimal-reproducible-example) 是必需的,否则该问题可能会被关闭而没有进一步的通知。[**为什么 & 如何?**](https://antfu.me/posts/why-reproductions-are-required)
validations:
required: true
- type: textarea
id: additional-information
attributes:
label: 额外信息
description: |
提供任何额外的信息,例如日志、截图、喜欢、发生该 Bug 的场景,以便有助于解决问题。
- type: checkboxes
id: checkboxes
attributes:
label: 验证
description: 在提交问题之前,请确保您完成了以下操作
options:
- label: 遵循我们的[行为准则](https//github.com/agalwood/Motrix/blob/master/CODE_OF_CONDUCT.md)
required: true
- label: 确认是否已经有一个报告了相同的 Bug,以避免创建重复的问题。
required: true
- label: 确认此问题是一个具体的 Bug。若要进行问答,请开启 [GitHub 讨论](https://github.com/agalwood/Motrix/discussions)。
required: true
- label: 提供的复现是该 Bug 的 [最小复现例子](https://stackoverflow.com/help/minimal-reproducible-example)。
required: true
-39
View File
@@ -1,39 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
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.**
<!-- Windows and Linux versions hide the application menu by default. Please close the "Hide Menu Bar" in Preferences - Advanced Settings - Appearance. After saving and applying, the menu bar will appear. -->
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**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.
-43
View File
@@ -1,43 +0,0 @@
---
name: 错误反馈
about: 创建一个错误报告帮助改进「请按照模板提交,提供详细的信息,方便我们复现之后处理」
title: ''
labels: ''
assignees: ''
---
<!--
反馈之前请搜索一下已有 issues 和 帮助文档,看是否有类似问题可以解决你的问题
https://github.com/agalwood/Motrix/issues
http://motrix.app/support
按以下格式填写反馈信息,谢谢
-->
**错误描述**
清楚简洁地描述错误,方便我们复现之后处理。
**如何重现**
重现步骤,如:
1. 点击新建任务按钮
2. 黏贴链接(如链接不涉及到隐私和版权问题,请顺便提供)
3. 点击提交
4. 发现报错
**预期的行为**
清楚简洁地描述你期望发生的事情。
**截图**
请添加屏幕截图以帮助解释你的问题:
打开应用菜单中的「帮助」——「开发者工具」—— 切换到 console,然后**完整**截图。
<!-- Windows 和 Linux 版本默认隐藏了应用菜单,请到偏好设置-进阶设置-外观里关闭“隐藏菜单栏”,保存并应用之后菜单栏就出现了 -->
**运行环境**
- 操作系统类型: [如 macOS, Windows, Linux]
- 具体版本: [如 macOS 10.14.2, Windows 10, Ubuntu 18.04]
- Motrix 版本: [如 v1.1.3, v1.1.0]
- 安装包类型:[如 dmg, AppImage]
**更多信息**
补充有关该问题的其他信息。
+16
View File
@@ -0,0 +1,16 @@
<!-- You can erase any parts of this template not applicable to your Pull Request. -->
## Description
<!-- Write a brief description of the changes introduced by this PR -->
## Related Issues
<!--
Link to the issue that is fixed by this PR (if there is one)
e.g. Fixes #1234, Addresses #1234, Related to #1234, etc.
-->
### Checklist:
* [ ] Have you checked to ensure there aren't other open [Pull Requests](../../../pulls) for the same update/change?
* [ ] Have you linted your code locally prior to submission?
* [ ] Have you successfully ran app with your changes locally?
+1 -1
View File
@@ -1,7 +1,7 @@
# 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
daysUntilLock: 60
# Skip issues and pull requests created before a given timestamp. Timestamp must
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
+71
View File
@@ -0,0 +1,71 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '23 8 * * 5'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
+60
View File
@@ -0,0 +1,60 @@
name: Build/release
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
release:
runs-on: ${{ matrix.os }}
# Platforms to build on/for
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v3
- name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Snapcraft
uses: samuelmeuli/action-snapcraft@v2
# Only install Snapcraft on Ubuntu
if: startsWith(matrix.os, 'ubuntu')
env:
# Snapcraft
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.snapcraft_token }}
- name: Test Snapcraft
if: startsWith(matrix.os, 'ubuntu')
run: snapcraft --help
- name: Build/release Electron app
uses: motrixapp/action-electron-builder@v2
with:
build_script_name: 'build:github'
# GitHub token, automatically provided to the action
# (No need to define this secret in the repo settings)
github_token: ${{ secrets.github_token }}
# macOS code signing certificate
mac_certs: ${{ secrets.mac_certs }}
mac_certs_password: ${{ secrets.mac_certs_password }}
# If the commit is tagged with a version (e.g. "v1.0.0"),
# release the app after building
release: ${{ vars.skip_publish != 'true' }}
env:
# Snapcraft
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.snapcraft_token }}
# macOS notarization
TEAM_ID: ${{ secrets.team_id }}
APPLE_ID: ${{ secrets.apple_id }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.apple_app_specific_password }}
+21 -8
View File
@@ -1,12 +1,25 @@
!.gitkeep
.DS_Store
dist/electron/*
dist/web/*
.env
.idea/
.vs/
.vscode/
*.log
node_modules/
thumbs.db
# npm package
.npmrc
npm-debug.log.*
# Eslint Cache
.eslintcache*
# electron builder
*.provisionprofile
build/*.plist
node_modules/
npm-debug.log
npm-debug.log.*
thumbs.db
!.gitkeep
dist/electron/*
dist/web/*
# release
release/*
.idea/
+17 -5
View File
@@ -1,32 +1,44 @@
osx_image: xcode10.1
sudo: required
dist: trusty
language: c
matrix:
jobs:
include:
- os: osx
osx_image: xcode11.3
- os: linux
env: CC=clang CXX=clang++ npm_config_clang=1
compiler: clang
cache:
directories:
- node_modules
- "$HOME/.electron"
- "$HOME/.cache"
- $HOME/.cache/electron
- $HOME/.cache/electron-builder
addons:
apt:
packages:
- libgnome-keyring-dev
- icnsutils
- rpm
before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils; fi
install:
- nvm install 10
- nvm install 12.14.1
- source ~/.bashrc
- npm install -g xvfb-maybe
- npm install
script:
- npm run release
before_cache:
- rm -rf $HOME/.cache/electron-builder/wine
branches:
only:
- master
+3 -1
View File
@@ -1,8 +1,10 @@
# Motrix 贡献指南
开始贡献之前,确保你已经理解了 [GitHub 的协作流程](https://guides.github.com/introduction/flow/)。
## 🌍 翻译指南
首先你要确定一个语言的英文简写作为 **locale**,如 en-US,这个 locale 值请严格参考 [Electron 的 Locales 文档](https://electronjs.org/docs/api/locales)
首先你要确定一个语言的英文简写作为 **locale**,如 en-US,这个 locale 值请严格参考 [Electron 的 Locales 文档](https://www.electronjs.org/docs/api/app#appgetlocale) 和 [Chromium 源代码](https://source.chromium.org/chromium/chromium/src/+/main:ui/base/l10n/l10n_util.cc)
Motrix 的国际化分两部分:
+3 -1
View File
@@ -1,8 +1,10 @@
# Motrix Contributing Guide
Before you start contributing, make sure you already understand [GitHub flow](https://guides.github.com/introduction/flow/).
## 🌍 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).
First you need to determine the English abbreviation of a language as **locale**, such as en-US, this locale value should strictly refer to the [Electron's Documentation](https://www.electronjs.org/docs/api/app#appgetlocale) and [Chromium Source Code](https://source.chromium.org/chromium/chromium/src/+/main:ui/base/l10n/l10n_util.cc).
The internationalization of Motrix is divided into two parts:
+3 -1
View File
@@ -1,4 +1,6 @@
Copyright 2018 Dr_rOot
The MIT License
Copyright 2018-present Dr_rOot
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+114 -24
View File
@@ -1,18 +1,20 @@
# Motrix
<a href="https://motrix.app">
<img src="https://cdn.nlark.com/yuque/0/2018/png/129147/1543735425232-a5d2c99f-d788-43e4-9781-558ff6d21027.png" width="256" alt="App Icon" />
</a>
[English](./README.md) | 简体中文
<p>
<a href="https://motrix.app">
<img src="./static/512x512.png" width="256" alt="Motrix App Icon" />
</a>
</p>
## 一款全能的下载工具
[![GitHub release](https://img.shields.io/github/release/agalwood/Motrix.svg)](https://github.com/agalwood/Motrix/releases) [![Build Status](https://travis-ci.org/agalwood/Motrix.svg?branch=master)](https://travis-ci.org/agalwood/Motrix) [![Build status](https://ci.appveyor.com/api/projects/status/l11d5h05xwwcvoux/branch/master?svg=true)](https://ci.appveyor.com/project/agalwood/motrix/branch/master) [![Total Downloads](https://img.shields.io/github/downloads/agalwood/Motrix/total.svg)](https://github.com/agalwood/Motrix/releases) ![Support Platforms](https://camo.githubusercontent.com/a50c47295f350646d08f2e1ccd797ceca3840e52/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d6d61634f5325323025374325323057696e646f77732532302537432532304c696e75782d6c69676874677265792e737667)
[![GitHub release](https://img.shields.io/github/v/release/agalwood/Motrix.svg)](https://github.com/agalwood/Motrix/releases) ![Build/release](https://github.com/agalwood/Motrix/workflows/Build/release/badge.svg) ![Total Downloads](https://img.shields.io/github/downloads/agalwood/Motrix/total.svg) ![Support Platforms](https://camo.githubusercontent.com/a50c47295f350646d08f2e1ccd797ceca3840e52/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d6d61634f5325323025374325323057696e646f77732532302537432532304c696e75782d6c69676874677265792e737667)
[English](./README.md) | 简体中文
我是个兴趣使然的桌面应用开发者🤓,利用搬砖之余开发了 Motrix。
Motrix 是一款全能的下载工具,支持下载 HTTP、FTP、BT、磁力链、百度网盘等资源。它的界面简洁易用,希望大家喜欢 👻。
Motrix 是一款全能的下载工具,支持下载 HTTP、FTP、BT、磁力链等资源。它的界面简洁易用,希望大家喜欢 👻。
✈️ 去 [官网](https://motrix.app/zh-CN) 逛逛 | 📖 查看 [帮助手册](http://motrix.app/support/issues)
@@ -24,6 +26,20 @@ Motrix 是一款全能的下载工具,支持下载 HTTP、FTP、BT、磁力链
建议使用安装包(Motrix-Setup-x.y.z.exe)安装 Motrix 以确保完整的体验,例如关联 torrent 文件,捕获磁力链等。
如果你在 Windows 是用包管理工具来管理应用,如 [Chocolatey](https://chocolatey.org)、[scoop](https://github.com/lukesampson/scoop),你可以使用它们安装 Motrix。
#### Chocolatey
感谢 [@Yato](https://github.com/iYato) 持续维护着 [Motrix Chocolatey](https://community.chocolatey.org/packages/motrix) 包。要安装 Motrix,请从 `命令行``PowerShell` 中运行以下命令:
```bash
# 安装
choco install motrix
# 升级
choco upgrade motrix
```
#### scoop
如果你更喜欢便携版,你可以使用 [scoop](https://github.com/lukesampson/scoop)(需要 Windows 7+,天朝用户可能需要设置 Git 代理)安装最新便携版本的 Motrix。
```bash
@@ -33,45 +49,96 @@ scoop install motrix
### macOS
macOS 用户可以使用 `brew cask` 安装 Motrix,感谢 [Mitscherlich](https://github.com/Mitscherlich) 的 [PR](https://github.com/Homebrew/homebrew-cask/pull/59494)。
macOS 用户可以使用 `brew` 安装 Motrix,感谢 [@Mitscherlich](https://github.com/Mitscherlich) 的 [PR](https://github.com/Homebrew/homebrew-cask/pull/59494)。
```bash
brew update && brew cask install motrix
brew update && brew install motrix
```
#### 自动更新
Motrix v1.8.0+ 版本更改了应用 BundleID ( `net.agalwood.Motrix` => `app.motrix.native` ), Motrix v1.6.11 的自动更新会因为签名不一致而失败。[Motrix 安装助手](https://github.com/motrixapp/motrix-install-assistant)将帮助您安装最新的 Motrix 应用程序。
<p>
<a href="https://github.com/motrixapp/motrix-install-assistant">
<img src="https://raw.githubusercontent.com/motrixapp/motrix-install-assistant/main/build/256x256.png" width="192" alt="Motrix Install Assistant Icon" />
</a>
</p>
### Linux
你可以下载 AppImage(适用于所有 Linux 发行版)软件包或 snap 或从源代码构建安装 Motrix
你可以下载 `AppImage` (适用于所有 Linux 发行版)`snap` 来安装 Motrix,更多 Linux 安装包格式请查看 [GitHub/release](https://github.com/agalwood/Motrix/releases)
构建请阅读 **编译打包** 部分
Motrix 在 Linux 中首次启动可能需要使用 `sudo` 运行,因为可能没有创建下载会话文件的权限 (`/var/cache/aria2.session`)
对于 Arch Linux 用户,可以使用 [aur](https://aur.archlinux.org/packages/motrix/) 安装 Motrix,感谢维护者 [weearc](https://github.com/weearc)
如果你想自己通过编译源码来安装,请阅读 **编译打包** 部分
#### AppImage
最新版的 Motrix AppImage 需要自己手动进执行桌面集成。请查看 [AppImageLauncher](https://github.com/TheAssassin/AppImageLauncher) 的文档进行操作。
> 桌面集成
> electron-builder v21 之后,桌面集成不再是 AppImage 文件的一部分。
> 推荐使用 [AppImageLauncher](https://github.com/TheAssassin/AppImageLauncher) 集成 AppImage。
Deepin 20 Beta 用户安装 Motrix 失败的问题,请按照以下方法处理:
打开`终端`,黏贴运行如下命令之后再次安装 Motrix。
```bash
sudo apt --fix-broken install
```
#### Snap
Motrix 已经上架 [Snapcraft](https://snapcraft.io/motrix) Ubuntu 用户推荐从 Snap 商店下载。
v1.5.10 提示
系统托盘可能无法正常显示指示器,导致退出应用程序不方便。
请取消勾选 偏好设置——基本设置——隐藏应用程序菜单(仅限Windows和Linux),点击保存并应用。然后点击 "文件 "菜单中的 "退出",退出应用程序。
请更新到 v1.5.12 及以上版本,可以使用键盘组合快捷键 <kbd>Ctrl</kbd> + <kbd>q</kbd> 快速退出应用。
#### AUR
对于 Arch Linux 用户,可以使用 [aur](https://aur.archlinux.org/packages/motrix/) 安装 Motrix,感谢维护者 [@weearc](https://github.com/weearc)。
运行以下命令进行安装:
```bash
yay motrix
yay -S motrix
```
#### Flatpak
感谢 [@proletarius101](https://github.com/proletarius101) 的 [PR](https://github.com/flathub/flathub/pull/2334)Motrix 已经上架 [Flathub](https://flathub.org/apps/details/net.agalwood.Motrix),喜欢 Flatpak 的 Linux 用户可以尝试。
```bash
# 安装
flatpak install flathub net.agalwood.Motrix
# 运行
flatpak run net.agalwood.Motrix
```
## ✨ 特性
- 🕹 简洁明了的图形操作界面
- 🦄 支持BT和磁力链任务
- 💾 支持下载百度云盘资源
- ☑️ 支持选择性下载BT部分文件
- 📡 每天自动更新 Tracker 服务器列表
- 🔌 UPnP & NAT-PMP 端口映射
- 🎛 最高支持 10 个任务同时下载
- 🚀 单任务最高支持 64 线程下载
- 🚥 设置上传/下载限速
- 🕶 模拟用户代理UA
- 🔔 下载完成后通知
- 💻 支持触控栏快捷键 (Mac 专享)
- 🤖 常驻系统托盘,操作更加便捷
- 📟 系统托盘速度仪表显示实时速度 (Mac 专享)
- 🌑 深色模式
- 🗑 移除任务时可同时删除相关文件
- 🌍 国际化,[查看已可选的语言](#-国际化)
- 🎏 ...
- 🛠 更多特性开发中
## 🖥 应用界面
![motrix-screenshot-task-cn.png](https://cdn.nlark.com/yuque/0/2019/png/129147/1550151234585-e513bd4f-e127-402f-accb-1ebbba9b3c41.png)
![motrix-screenshot-task-cn.png](https://cdn.nlark.com/yuque/0/2020/png/129147/1589782239990-fecb9065-19ac-4c35-938b-0be45621ca3a.png)
## ⌨️ 本地开发
@@ -85,38 +152,45 @@ git clone git@github.com:agalwood/Motrix.git
```bash
cd Motrix
npm install
yarn
```
天朝大陆用户建议使用淘宝的 npm 源
```bash
npm config set registry 'https://registry.npm.taobao.org'
yarn config set registry 'https://registry.npmmirror.com'
npm config set registry 'https://registry.npmmirror.com'
export ELECTRON_MIRROR='https://npm.taobao.org/mirrors/electron/'
export SASS_BINARY_SITE='https://npm.taobao.org/mirrors/node-sass'
```
如果喜欢 [Yarn](https://yarnpkg.com/),也可以使用 `yarn` 安装依赖
> Error: Electron failed to install correctly, please delete node_modules/electron and try installing again
`Electron` 下载安装失败的问题,解决方式请参考 https://github.com/electron/electron/issues/8466#issuecomment-571425574
### 开发模式
```bash
npm run dev
yarn run dev
```
### 编译打包
```bash
npm run build
yarn run build
```
#### 编译 Apple Silicon 版本
```bash
yarn run build:applesilicon
```
完成之后可以在项目的 `release` 目录看到编译打包好的应用文件
## 🛠 技术栈
- [Electron](https://electronjs.org/)
- [Vue](https://vuejs.org/) + [VueX](https://vuex.vuejs.org/) + [Element](https://element.eleme.io)
- [Aria2](https://aria2.github.io/) (注:macOS 和 Linux 版本使用的是 64 位的 aria2cWindows 版使用的 32 位的)
- [Aria2](https://aria2.github.io/)
## ☑️ TODO
@@ -132,16 +206,32 @@ npm run build
| Key | Name | Status |
|-------|:--------------------|:-------------|
| de | German | ✔️ [@Schloemicher](https://github.com/Schloemicher) |
| ar | Arabic | ✔️ [@hadialqattan](https://github.com/hadialqattan), [@AhmedElTabarani](https://github.com/AhmedElTabarani) |
| bg | Българският език | ✔️ [@null-none](https://github.com/null-none) |
| ca | Català | ✔️ [@marcizhu](https://github.com/marcizhu) |
| de | Deutsch | ✔️ [@Schloemicher](https://github.com/Schloemicher) |
| el | Ελληνικά | ✔️ [@Likecinema](https://github.com/Likecinema) |
| en-US | English | ✔️ |
| es | Español | ✔️ [@Chofito](https://github.com/Chofito)|
| fa | فارسی | ✔️ [@Nima-Ra](https://github.com/Nima-Ra) |
| fr | Français | ✔️ [@gpatarin](https://github.com/gpatarin) |
| hu | Hungarian | ✔️ [@zalnaRs](https://github.com/zalnaRs) |
| id | Indonesia | ✔️ [@aarestu](https://github.com/aarestu) |
| it | Italiano | ✔️ [@blackcat-917](https://github.com/blackcat-917) |
| ja | 日本語 | ✔️ [@hbkrkzk](https://github.com/hbkrkzk) |
| ko | 한국어 | ✔️ [@KOZ39](https://github.com/KOZ39) |
| nb | Norsk Bokmål | ✔️ [@rubjo](https://github.com/rubjo) |
| nl | Nederlands | ✔️ [@nickbouwhuis](https://github.com/nickbouwhuis) |
| pl | Polski | ✔️ [@KanarekLife](https://github.com/KanarekLife) |
| pt-BR | Portuguese (Brazil) | ✔️ [@andrenoberto](https://github.com/andrenoberto) |
| ro | Română | ✔️ [@alyn3d](https://github.com/alyn3d) |
| ru | Русский | ✔️ [@bladeaweb](https://github.com/bladeaweb) |
| th | แบบไทย | ✔️ [@nxanywhere](https://github.com/nxanywhere) |
| tr | Türkçe | ✔️ [@abdullah](https://github.com/abdullah) |
| uk | Українська | ✔️ [@bladeaweb](https://github.com/bladeaweb) |
| vi | Tiếng Việt | ✔️ [@duythanhvn](https://github.com/duythanhvn) |
| zh-CN | 简体中文 | ✔️ |
| zh-TW | 繁體中文 | ✔️ [@Yukaii](https://github.com/Yukaii) |
| zh-TW | 繁體中文 | ✔️ [@Yukaii](https://github.com/Yukaii) [@5idereal](https://github.com/5idereal) |
## 📜 开源许可
+114 -21
View File
@@ -1,16 +1,18 @@
# Motrix
<a href="https://motrix.app">
<img src="https://cdn.nlark.com/yuque/0/2018/png/129147/1543735425232-a5d2c99f-d788-43e4-9781-558ff6d21027.png" width="256" alt="App Icon" />
</a>
<p>
<a href="https://motrix.app">
<img src="./static/512x512.png" width="256" alt="Motrix App Icon" />
</a>
</p>
## A full-featured download manager
[![GitHub release](https://img.shields.io/github/release/agalwood/Motrix.svg)](https://github.com/agalwood/Motrix/releases) [![Build Status](https://travis-ci.org/agalwood/Motrix.svg?branch=master)](https://travis-ci.org/agalwood/Motrix) [![Build status](https://ci.appveyor.com/api/projects/status/l11d5h05xwwcvoux/branch/master?svg=true)](https://ci.appveyor.com/project/agalwood/motrix/branch/master) [![Total Downloads](https://img.shields.io/github/downloads/agalwood/Motrix/total.svg)](https://github.com/agalwood/Motrix/releases) ![Support Platforms](https://camo.githubusercontent.com/a50c47295f350646d08f2e1ccd797ceca3840e52/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d6d61634f5325323025374325323057696e646f77732532302537432532304c696e75782d6c69676874677265792e737667)
[![GitHub release](https://img.shields.io/github/v/release/agalwood/Motrix.svg)](https://github.com/agalwood/Motrix/releases) ![Build/release](https://github.com/agalwood/Motrix/workflows/Build/release/badge.svg) ![Total Downloads](https://img.shields.io/github/downloads/agalwood/Motrix/total.svg) ![Support Platforms](https://camo.githubusercontent.com/a50c47295f350646d08f2e1ccd797ceca3840e52/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d6d61634f5325323025374325323057696e646f77732532302537432532304c696e75782d6c69676874677265792e737667)
English | [简体中文](./README-CN.md)
Motrix is a full-featured download manager that supports downloading HTTP, FTP, BitTorrent, Magnet, Baidu Net Disk, etc.
Motrix is a full-featured download manager that supports downloading HTTP, FTP, BitTorrent, Magnet, etc.
Motrix has a clean and easy to use interface. I hope you will like it 👻.
@@ -24,6 +26,20 @@ Download from [GitHub Releases](https://github.com/agalwood/Motrix/releases) and
It is recommended to install Motrix using the installation package (Motrix-Setup-x.y.z.exe) to ensure a complete experience, such as associating torrent files, capturing magnet links, etc.
If you use package management tools to manage applications on Windows, such as [Chocolatey](https://chocolatey.org), [scoop](https://github.com/lukesampson/scoop). You can use them to install Motrix.
#### Chocolatey
Thanks to [@Yato](https://github.com/iYato) for continuing to maintain the [Motrix Chocolatey](https://community.chocolatey.org/packages/motrix) package. To install motrix, run the following command from the `command line` or from `PowerShell`:
```bash
# Install
choco install motrix
# Upgrade
choco upgrade motrix
```
#### scoop
If you prefer the portable version, you can use [scoop](https://github.com/lukesampson/scoop) (need Windows 7+) to install Motrix.
```bash
@@ -33,45 +49,99 @@ scoop install motrix
### macOS
The macOS users can install Motrix using `brew cask`, thanks to [PR](https://github.com/Homebrew/homebrew-cask/pull/59494) of [Mitscherlich](https://github.com/Mitscherlich).
The macOS users can install Motrix using `brew`, thanks to [PR](https://github.com/Homebrew/homebrew-cask/pull/59494) of [@Mitscherlich](https://github.com/Mitscherlich).
```bash
brew update && brew cask install motrix
brew update && brew install motrix
```
#### Auto Update
Since Motrix v1.8.0 and later versions changed the App BundleID ( `net.agalwood.Motrix` => `app.motrix.native` ), the automatic update of Motrix v1.6.11 will fail. [Motrix Install Assistant](https://github.com/motrixapp/motrix-install-assistant) will help you install the latest Motrix application.
<p>
<a href="https://github.com/motrixapp/motrix-install-assistant">
<img src="https://raw.githubusercontent.com/motrixapp/motrix-install-assistant/main/build/256x256.png" width="192" alt="Motrix Install Assistant Icon" />
</a>
</p>
### Linux
You can download the AppImage (for all Linux distributions) package or snap or just build from source code to install Motrix.
You can download the `AppImage` (for all Linux distributions) or `snap` to install Motrix, see [GitHub/release](https://github.com/agalwood/Motrix/releases) for more Linux installation package formats.
Please read the **Build** section.
Motrix may need to run with `sudo` for the first time in Linux because there is no permission to create the download session file (`/var/cache/aria2.session`).
For Arch Linux users, Motrix is available in [aur](https://aur.archlinux.org/packages/motrix/), thanks to the maintainer [weearc](https://github.com/weearc).
If you want to build from source code, please read the **Build** section.
#### AppImage
The latest version of Motrix AppImage requires you to manually perform desktop integration. Please check the documentation of [AppImageLauncher](https://github.com/TheAssassin/AppImageLauncher) .
> Desktop Integration
> Since electron-builder 21 desktop integration is not a part of produced AppImage file.
> [AppImageLauncher](https://github.com/TheAssassin/AppImageLauncher) is the recommended way to integrate AppImages.
Deepin 20 Beta users failed to install Motrix, please follow the steps below:
Open the `Terminal`, paste and run the following command to install Motrix again.
```bash
sudo apt --fix-broken install
```
#### Snap
Motrix has been listed on [Snapcraft](https://snapcraft.io/motrix) , Ubuntu users recommend downloading from the Snap Store.
Tips for v1.5.10
The tray may not display the indicator normally, which makes it inconvenient to exit the application.
Please unchecked Preferences--Basic Settings--Hide App Menu (Windows & Linux Only), click Save & Apply. Then click "Exit" in the File menu to exit the application.
Please update to v1.5.12 and above, you can use the keyboard shortcut <kbd>Ctrl</kbd> + <kbd>q</kbd> to quickly exit the application.
#### AUR
For Arch Linux users, Motrix is available in [aur](https://aur.archlinux.org/packages/motrix/), thanks to the maintainer [@weearc](https://github.com/weearc).
Run the following command to install:
```bash
yay motrix
yay -S motrix
```
#### Flatpak
Thanks to the [PR](https://github.com/flathub/flathub/pull/2334) of [@proletarius101](https://github.com/proletarius101), Motrix has been listed [Flathub](https://flathub.org/apps/details/net.agalwood.Motrix), Linux users who like the Flatpak can try it.
```bash
# Install
flatpak install flathub net.agalwood.Motrix
# Run
flatpak run net.agalwood.Motrix
```
## ✨ Features
- 🕹 Simple and clear user interface
- 🦄 Supports BitTorrent & Magnet
- 💾 Supports downloading Baidu Net Disk
- ☑️ BitTorrent selective download
- 📡 Update tracker list every day automatically
- 🔌 UPnP & NAT-PMP Port Mapping
- 🎛 Up to 10 concurrent download tasks
- 🚀 Supports 64 threads in a single task
- 🚥 Supports speed limit
- 🕶 Mock User-Agent
- 🔔 Download completed Notification
- 💻 Ready for Touch Bar (Mac only)
- 🤖 Resident system tray for quick operation
- 📟 Tray speed meter displays real-time speed (Mac only)
- 🌑 Dark mode
- 🗑 Delete related files when removing tasks (optional)
- 🌍 I18n, [View supported languages](#-internationalization).
- 🎏 ...
- 🛠 More features in development
## 🖥 User Interface
![motrix-screenshot-task-en.png](https://cdn.nlark.com/yuque/0/2019/png/129147/1550151166169-94b4bfb0-746e-42b8-aad7-0b6890f89abb.png)
![motrix-screenshot-task-en.png](https://cdn.nlark.com/yuque/0/2020/png/129147/1589782238501-e7b39166-da58-4152-ae34-65a061cafa48.png)
## ⌨️ Development
@@ -85,21 +155,28 @@ git clone git@github.com:agalwood/Motrix.git
```bash
cd Motrix
npm install
yarn
```
If you like [Yarn](https://yarnpkg.com/), you can also use `yarn` to install dependencies.
> Error: Electron failed to install correctly, please delete node_modules/electron and try installing again
`Electron` failed to install correctly, please refer to https://github.com/electron/electron/issues/8466#issuecomment-571425574
### Dev Mode
```bash
npm run dev
yarn run dev
```
### Build Release
```bash
npm run build
yarn run build
```
#### Build for Apple Silicon
```bash
yarn run build:applesilicon
```
After building, the application will be found in the project's `release` directory.
@@ -108,7 +185,7 @@ After building, the application will be found in the project's `release` directo
- [Electron](https://electronjs.org/)
- [Vue](https://vuejs.org/) + [VueX](https://vuex.vuejs.org/) + [Element](https://element.eleme.io)
- [Aria2](https://aria2.github.io/) (Note: macOS and Linux versions use 64-bit aria2c, Windows version uses 32-bit)
- [Aria2](https://aria2.github.io/)
## ☑️ TODO
@@ -124,16 +201,32 @@ Translations into versions for other languages are welcome 🧐! Please read the
| Key | Name | Status |
|-------|:--------------------|:-------------|
| de | German | ✔️ [@Schloemicher](https://github.com/Schloemicher) |
| ar | Arabic | ✔️ [@hadialqattan](https://github.com/hadialqattan), [@AhmedElTabarani](https://github.com/AhmedElTabarani) |
| bg | Българският език | ✔️ [@null-none](https://github.com/null-none) |
| ca | Català | ✔️ [@marcizhu](https://github.com/marcizhu) |
| de | Deutsch | ✔️ [@Schloemicher](https://github.com/Schloemicher) |
| el | Ελληνικά | ✔️ [@Likecinema](https://github.com/Likecinema) |
| en-US | English | ✔️ |
| es | Español | ✔️ [@Chofito](https://github.com/Chofito)|
| fa | فارسی | ✔️ [@Nima-Ra](https://github.com/Nima-Ra) |
| fr | Français | ✔️ [@gpatarin](https://github.com/gpatarin) |
| hu | Hungarian | ✔️ [@zalnaRs](https://github.com/zalnaRs) |
| id | Indonesia | ✔️ [@aarestu](https://github.com/aarestu) |
| it | Italiano | ✔️ [@blackcat-917](https://github.com/blackcat-917) |
| ja | 日本語 | ✔️ [@hbkrkzk](https://github.com/hbkrkzk) |
| ko | 한국어 | ✔️ [@KOZ39](https://github.com/KOZ39) |
| nb | Norsk Bokmål | ✔️ [@rubjo](https://github.com/rubjo) |
| nl | Nederlands | ✔️ [@nickbouwhuis](https://github.com/nickbouwhuis) |
| pl | Polski | ✔️ [@KanarekLife](https://github.com/KanarekLife) |
| pt-BR | Portuguese (Brazil) | ✔️ [@andrenoberto](https://github.com/andrenoberto) |
| ro | Română | ✔️ [@alyn3d](https://github.com/alyn3d) |
| ru | Русский | ✔️ [@bladeaweb](https://github.com/bladeaweb) |
| th | แบบไทย | ✔️ [@nxanywhere](https://github.com/nxanywhere) |
| tr | Türkçe | ✔️ [@abdullah](https://github.com/abdullah) |
| uk | Українська | ✔️ [@bladeaweb](https://github.com/bladeaweb) |
| vi | Tiếng Việt | ✔️ [@duythanhvn](https://github.com/duythanhvn) |
| zh-CN | 简体中文 | ✔️ |
| zh-TW | 繁體中文 | ✔️ [@Yukaii](https://github.com/Yukaii) |
| zh-TW | 繁體中文 | ✔️ [@Yukaii](https://github.com/Yukaii) [@5idereal](https://github.com/5idereal) |
## 📜 License
+1 -1
View File
@@ -1,2 +1,2 @@
provider: generic
url: 'https://dl.motrix.app/release/'
url: 'https://dl.motrix.app/releases/'
+6 -9
View File
@@ -1,24 +1,17 @@
version: 1.0.{build}
branches:
only:
- master
image: Visual Studio 2017
platform:
- x64
cache:
- node_modules
- '%APPDATA%\npm-cache'
- '%USERPROFILE%\.electron'
- '%USERPROFILE%\AppData\Local\Yarn\cache'
init:
- git config --global core.autocrlf input
install:
- ps: Install-Product node 10 x64
- ps: Install-Product node 12.14.1 x64
- git reset --hard HEAD
- npm install
- node --version
@@ -27,3 +20,7 @@ build_script:
- npm run release
test: off
branches:
only:
- master
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 103 KiB

+94
View File
@@ -0,0 +1,94 @@
// Forked from https://github.com/samuelmeuli/mini-diary/blob/master/scripts/after-pack.js
/**
* Source: https://github.com/patrikx3/redis-ui/blob/master/src/build/after-pack.js
*
* Copyright (c) 2019 Patrik Laszlo / P3X / Corifeus and contributors.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// TODO: Remove script once https://github.com/electron/electron/issues/17972 is solved by
// `electron-builder`
const fs = require('node:fs')
const { spawn } = require('node:child_process')
const { chdir } = require('node:process')
const pkg = require('../package.json')
const binName = `${pkg.name}`.toLowerCase()
const exec = async function exec (cmd, args = []) {
const child = spawn(cmd, args, { shell: true })
redirectOutputFor(child)
await waitFor(child)
}
const redirectOutputFor = child => {
const printStdout = data => {
process.stdout.write(data.toString())
}
const printStderr = data => {
process.stderr.write(data.toString())
}
child.stdout.on('data', printStdout)
child.stderr.on('data', printStderr)
child.once('close', () => {
child.stdout.off('data', printStdout)
child.stderr.off('data', printStderr)
})
}
const waitFor = async function (child) {
return new Promise(resolve => {
child.once('close', () => resolve())
})
}
const linuxTargets = [
'AppImage',
'deb',
'rpm',
'snap'
]
module.exports = async function (context) {
console.warn('after build; disable sandbox')
const isLinux = context.targets.find(
target => linuxTargets.includes(target)
)
if (!isLinux) {
return
}
const originalDir = process.cwd()
const dirname = context.appOutDir
chdir(dirname)
await exec('mv', [binName, binName + '.bin'])
const wrapperScript = `#!/bin/bash
"\${BASH_SOURCE%/*}"/${binName}.bin "$@" --no-sandbox
`
fs.writeFileSync(binName, wrapperScript)
await exec('chmod', ['+x', binName])
chdir(originalDir)
}
+36
View File
@@ -0,0 +1,36 @@
require('dotenv').config()
const { join } = require('node:path')
const { notarize } = require('@electron/notarize')
const { appId } = require('../electron-builder.json')
exports.default = async function (context) {
const { electronPlatformName, appOutDir } = context
if (electronPlatformName !== 'darwin') {
return
}
const skipNotarize = process.env.SKIP_NOTARIZE
if (skipNotarize === 'true') {
console.log('Skipping notarize')
return
}
const appBundleId = appId
const appName = context.packager.appInfo.productFilename
const appPath = join(appOutDir, `${appName}.app`)
try {
await notarize({
tool: 'notarytool',
appBundleId,
appPath,
teamId: process.env.TEAM_ID,
appleId: process.env.APPLE_ID,
appleIdPassword: process.env.APPLE_APP_SPECIFIC_PASSWORD
})
} catch (error) {
console.error(error)
}
console.log(`Done notarizing ${appId}`)
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 451 KiB

Binary file not shown.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 530 KiB

+200
View File
@@ -0,0 +1,200 @@
{
"productName": "Motrix",
"appId": "app.motrix.native",
"afterPack": "./build/afterPackHook.js",
"afterSign": "./build/afterSignHook.js",
"fileAssociations": [
{
"ext": "torrent",
"mimeType": "application/x-bittorrent",
"name": "Torrent",
"role": "Viewer"
}
],
"asar": true,
"directories": {
"output": "release"
},
"files": [
"dist/electron/**/*"
],
"protocols": [
{
"name": "Motrix Protocol",
"schemes": [
"mo",
"motrix"
]
},
{
"name": "Magnet Protocol",
"schemes": [
"magnet"
]
},
{
"name": "Thunder Protocol",
"schemes": [
"thunder"
]
}
],
"dmg": {
"window": {
"width": 540,
"height": 380
},
"contents": [
{
"x": 410,
"y": 230,
"type": "link",
"path": "/Applications"
},
{
"x": 130,
"y": 230,
"type": "file"
}
]
},
"mac": {
"target": [
{
"target": "dmg",
"arch": [
"x64",
"arm64",
"universal"
]
},
{
"target": "zip",
"arch": [
"x64",
"arm64",
"universal"
]
}
],
"type": "development",
"darkModeSupport": true,
"hardenedRuntime": false,
"notarize": false,
"extraResources": {
"from": "./extra/darwin/${arch}/",
"to": "./",
"filter": [
"**/*"
]
},
"category": "public.app-category.utilities"
},
"win": {
"target": [
{
"target": "nsis",
"arch": [
"x64",
"ia32"
]
},
{
"target": "appx",
"arch": [
"x64",
"ia32"
]
},
{
"target": "zip",
"arch": [
"x64",
"ia32"
]
},
{
"target": "portable",
"arch": [
"x64",
"ia32"
]
}
],
"extraResources": {
"from": "./extra/win32/${arch}/",
"to": "./",
"filter": [
"**/*"
]
}
},
"nsis": {
"artifactName": "${productName}-Setup-${version}.${ext}",
"oneClick": false,
"allowToChangeInstallationDirectory": true
},
"appx": {
"artifactName": "${productName}-${version}-${arch}.${ext}",
"applicationId": "app.motrix.native",
"identityName": "59744DrrOot.Motrix",
"publisher": "CN=5BB4961D-30D8-4993-9ADF-05E1E1F5A395",
"publisherDisplayName": "Dr_rOot"
},
"portable": {
"artifactName": "${productName}-${version}-${arch}.${ext}"
},
"linux": {
"category": "Network",
"mimeTypes": [
"application/x-bittorrent",
"x-scheme-handler/magnet"
],
"target": [
{
"target": "AppImage",
"arch": [
"x64",
"arm64",
"armv7l"
]
},
{
"target": "deb",
"arch": [
"x64",
"arm64",
"armv7l"
]
},
{
"target": "rpm",
"arch": [
"x64"
]
},
{
"target": "snap",
"arch": [
"x64"
]
}
],
"extraResources": {
"from": "./extra/linux/${arch}/",
"to": "./",
"filter": [
"**/*"
]
}
},
"publish": [
{
"provider": "generic",
"url": "https://dl.motrix.app/releases/"
},
{
"provider": "github"
}
]
}
+3
View File
@@ -0,0 +1,3 @@
# aria2
Source code: https://github.com/agalwood/aria2
+91
View File
@@ -0,0 +1,91 @@
###############################
# Motrix macOS Aria2 config file
#
# @see https://aria2.github.io/manual/en/html/aria2c.html
#
###############################
################ RPC ################
# Enable JSON-RPC/XML-RPC server.
enable-rpc=true
# Add Access-Control-Allow-Origin header field with value * to the RPC response.
rpc-allow-origin-all=true
# Listen incoming JSON-RPC/XML-RPC requests on all network interfaces.
rpc-listen-all=true
################ File system ################
# Save a control file(*.aria2) every SEC seconds.
auto-save-interval=10
# Enable disk cache.
disk-cache=64M
# Specify file allocation method.
file-allocation=none
# No file allocation is made for files whose size is smaller than SIZE
no-file-allocation-limit=64M
# Save error/unfinished downloads to a file specified by --save-session option every SEC seconds.
save-session-interval=10
################ Task ################
# Exclude seed only downloads when counting concurrent active downloads
bt-detach-seed-only=true
# Verify the peer using certificates specified in --ca-certificate option.
check-certificate=false
# If aria2 receives "file not found" status from the remote HTTP/FTP servers NUM times
# without getting a single byte, then force the download to fail.
max-file-not-found=10
# Set number of tries.
max-tries=0
# Set the seconds to wait between retries. When SEC > 0, aria2 will retry downloads when the HTTP server returns a 503 response.
retry-wait=10
# Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server. After the connection is established, this option makes no effect and --timeout option is used instead.
connect-timeout=10
# Set timeout in seconds.
timeout=10
# aria2 does not split less than 2*SIZE byte range.
min-split-size=1M
# Send Accept: deflate, gzip request header.
http-accept-gzip=true
# Retrieve timestamp of the remote file from the remote HTTP/FTP server and if it is available, apply it to the local file.
remote-time=true
# Set interval in seconds to output download progress summary. Setting 0 suppresses the output.
summary-interval=0
# Handle quoted string in Content-Disposition header as UTF-8 instead of ISO-8859-1, for example, the filename parameter, but not the extended version filename*.
content-disposition-default-utf8=true
################ BT Task ################
# Enable Local Peer Discovery.
bt-enable-lpd=true
# Requires BitTorrent message payload encryption with arc4.
# bt-force-encryption=true
# If true is given, after hash check using --check-integrity option and file is complete, continue to seed file.
bt-hash-check-seed=true
# Specify the maximum number of peers per torrent.
bt-max-peers=128
# Try to download first and last pieces of each file first. This is useful for previewing files.
bt-prioritize-piece=head
# Removes the unselected files when download is completed in BitTorrent.
bt-remove-unselected-file=true
# Seed previously downloaded files without verifying piece hashes.
bt-seed-unverified=false
# Set the connect timeout in seconds to establish connection to tracker. After the connection is established, this option makes no effect and --bt-tracker-timeout option is used instead.
bt-tracker-connect-timeout=10
# Set timeout in seconds.
bt-tracker-timeout=10
# Set host and port as an entry point to IPv4 DHT network.
dht-entry-point=dht.transmissionbt.com:6881
# Set host and port as an entry point to IPv6 DHT network.
dht-entry-point6=dht.transmissionbt.com:6881
# Enable IPv4 DHT functionality. It also enables UDP tracker support.
enable-dht=true
# Enable IPv6 DHT functionality.
enable-dht6=true
# Enable Peer Exchange extension.
enable-peer-exchange=true
# Specify the string used during the bitorrent extended handshake for the peer's client version.
peer-agent=Transmission/3.00
# Specify the prefix of peer ID.
peer-id-prefix=-TR3000-
BIN
View File
Binary file not shown.
-122
View File
@@ -1,122 +0,0 @@
## '#'开头为注释内容, 选项都有相应的注释说明, 根据需要修改 ##
## 被注释的选项填写的是默认值, 建议在需要修改时再取消注释 ##
## 添加了@和默认启用的选项都是系统需要调用的,请不要随意改动否则可能无法正常运行
## 文件保存相关 ##
# 文件的保存路径(可使用绝对路径或相对路径), 默认: 当前启动位置
# 此项 OS X 无法使用 $HOME 及 ~/ 设置路径 建议使用 /users/用户名/downloads
#@dir=$HOME/downloads
# 启用磁盘缓存, 0为禁用缓存, 需1.16以上版本, 默认:16M
#@disk-cache=32M
# 文件预分配方式, 能有效降低磁盘碎片, 默认:prealloc
# 预分配所需时间: none < falloc ? trunc < prealloc
# falloc和trunc则需要文件系统和内核支持
# NTFS建议使用falloc, EXT3/4建议trunc, MAC 下需要注释此项
# file-allocation=none
# 断点续传
#@continue=true
## 下载连接相关 ##
# 最大同时下载任务数, 运行时可修改, 默认:5
#@max-concurrent-downloads=10
# 同一服务器连接数, 添加时可指定, 默认:1
#@max-connection-per-server=15
# 最小文件分片大小, 添加时可指定, 取值范围1M -1024M, 默认:20M
# 假定size=10M, 文件为20MiB 则使用两个来源下载; 文件为15MiB 则使用一个来源下载
#@min-split-size=10M
# 单个任务最大线程数, 添加时可指定, 默认:5
#@split=15
# 整体下载速度限制, 运行时可修改, 默认:0
#@max-overall-download-limit=0
# 单个任务下载速度限制, 默认:0
#@max-download-limit=0
# 整体上传速度限制, 运行时可修改, 默认:0
max-overall-upload-limit=128K
# 单个任务上传速度限制, 默认:0
#@max-upload-limit=0
# 禁用IPv6, 默认:false
disable-ipv6=false
#运行覆盖已存在文件
#@allow-overwrite=true
#自动重命名
#@auto-file-renaming=true
## 进度保存相关 ##
# 从会话文件中读取下载任务
#@input-file=/Users/Shared/aria2.session
# 在Aria2退出时保存`错误/未完成`的下载任务到会话文件
#@save-session=/Users/Shared/aria2.session
# 定时保存会话, 0为退出时才保存, 需1.16.1以上版本, 默认:0
save-session-interval=30
## RPC相关设置 ##
# 启用RPC, 默认:false
enable-rpc=true
# 允许所有来源, 默认:false
rpc-allow-origin-all=true
# 允许非外部访问, 默认:false
rpc-listen-all=true
# 事件轮询方式, 取值:[epoll, kqueue, port, poll, select], 不同系统默认值不同
#event-poll=select
# RPC监听端口, 端口被占用时可以修改, 默认:6800
# 使用本客户端请勿修改此项
# rpc-listen-port=6800
# 设置的RPC授权令牌, v1.18.4新增功能, 取代 --rpc-user 和 --rpc-passwd 选项
#rpc-secret=token
## BT/PT下载相关 ##
# 当下载的是一个种子(以.torrent结尾)时, 自动开始BT任务, 默认:true
#follow-torrent=true
# BT监听端口, 当端口被屏蔽时使用, 默认:6881-6999
listen-port=50101-50109
# 单个种子最大连接数, 默认:55
#bt-max-peers=55
# 打开DHT功能, PT需要禁用, 默认:true
enable-dht=true
# 打开IPv6 DHT功能, PT需要禁用
enable-dht6=true
# DHT网络监听端口, 默认:6881-6999
dht-listen-port=50101-50109
# Set host and port as an entry point to IPv4 DHT network.
dht-entry-point=dht.transmissionbt.com:6881
# Set host and port as an entry point to IPv6 DHT network.
dht-entry-point6=dht.transmissionbt.com:6881
# 本地节点查找, PT需要禁用, 默认:false
bt-enable-lpd=true
# 种子交换, PT需要禁用, 默认:true
enable-peer-exchange=true
# 每个种子限速, 对少种的PT很有用, 默认:50K
#bt-request-peer-speed-limit=50K
# 客户端伪装, PT需要
peer-id-prefix=-TR2770-
user-agent=Transmission/2.94
# 当种子的分享率达到这个数时, 自动停止做种, 0为一直做种, 默认:1.0
seed-ratio=1.0
# 强制保存会话, 即使任务已经完成, 默认:false
# 较新的版本开启后会在任务完成后依然保留.aria2文件
#force-save=false
# BT校验相关, 默认:true
#bt-hash-check-seed=true
# 继续之前的BT任务时, 无需再次校验, 默认:false
bt-seed-unverified=true
# 保存磁力链接元数据为种子文件(.torrent文件), 默认:false
bt-save-metadata=false
# Removes the unselected files when download is completed in BitTorrent.
# To select files, use --select-file option. If it is not used,
# all files are assumed to be selected. Please use this option with care
# because it will actually remove files from your disk. Default: false
bt-remove-unselected-file=true
# Verify the peer using certificates specified
# in --ca-certificate option. Default: true
check-certificate=false
# Exclude seed only downloads when counting concurrent active downloads (See -j option).
# This means that if -j3 is given and this option is turned on and 3 downloads are active and one of those enters seed mode,
# then it is excluded from active download count (thus it becomes 2),
# and the next download waiting in queue gets started.
# But be aware that seeding item is still recognized as active download in RPC method. Default: false
bt-detach-seed-only=true
Binary file not shown.
+91
View File
@@ -0,0 +1,91 @@
###############################
# Motrix macOS Aria2 config file
#
# @see https://aria2.github.io/manual/en/html/aria2c.html
#
###############################
################ RPC ################
# Enable JSON-RPC/XML-RPC server.
enable-rpc=true
# Add Access-Control-Allow-Origin header field with value * to the RPC response.
rpc-allow-origin-all=true
# Listen incoming JSON-RPC/XML-RPC requests on all network interfaces.
rpc-listen-all=true
################ File system ################
# Save a control file(*.aria2) every SEC seconds.
auto-save-interval=10
# Enable disk cache.
disk-cache=64M
# Specify file allocation method.
file-allocation=none
# No file allocation is made for files whose size is smaller than SIZE
no-file-allocation-limit=64M
# Save error/unfinished downloads to a file specified by --save-session option every SEC seconds.
save-session-interval=10
################ Task ################
# Exclude seed only downloads when counting concurrent active downloads
bt-detach-seed-only=true
# Verify the peer using certificates specified in --ca-certificate option.
check-certificate=false
# If aria2 receives "file not found" status from the remote HTTP/FTP servers NUM times
# without getting a single byte, then force the download to fail.
max-file-not-found=10
# Set number of tries.
max-tries=0
# Set the seconds to wait between retries. When SEC > 0, aria2 will retry downloads when the HTTP server returns a 503 response.
retry-wait=10
# Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server. After the connection is established, this option makes no effect and --timeout option is used instead.
connect-timeout=10
# Set timeout in seconds.
timeout=10
# aria2 does not split less than 2*SIZE byte range.
min-split-size=1M
# Send Accept: deflate, gzip request header.
http-accept-gzip=true
# Retrieve timestamp of the remote file from the remote HTTP/FTP server and if it is available, apply it to the local file.
remote-time=true
# Set interval in seconds to output download progress summary. Setting 0 suppresses the output.
summary-interval=0
# Handle quoted string in Content-Disposition header as UTF-8 instead of ISO-8859-1, for example, the filename parameter, but not the extended version filename*.
content-disposition-default-utf8=true
################ BT Task ################
# Enable Local Peer Discovery.
bt-enable-lpd=true
# Requires BitTorrent message payload encryption with arc4.
# bt-force-encryption=true
# If true is given, after hash check using --check-integrity option and file is complete, continue to seed file.
bt-hash-check-seed=true
# Specify the maximum number of peers per torrent.
bt-max-peers=128
# Try to download first and last pieces of each file first. This is useful for previewing files.
bt-prioritize-piece=head
# Removes the unselected files when download is completed in BitTorrent.
bt-remove-unselected-file=true
# Seed previously downloaded files without verifying piece hashes.
bt-seed-unverified=false
# Set the connect timeout in seconds to establish connection to tracker. After the connection is established, this option makes no effect and --bt-tracker-timeout option is used instead.
bt-tracker-connect-timeout=10
# Set timeout in seconds.
bt-tracker-timeout=10
# Set host and port as an entry point to IPv4 DHT network.
dht-entry-point=dht.transmissionbt.com:6881
# Set host and port as an entry point to IPv6 DHT network.
dht-entry-point6=dht.transmissionbt.com:6881
# Enable IPv4 DHT functionality. It also enables UDP tracker support.
enable-dht=true
# Enable IPv6 DHT functionality.
enable-dht6=true
# Enable Peer Exchange extension.
enable-peer-exchange=true
# Specify the string used during the bitorrent extended handshake for the peer's client version.
peer-agent=Transmission/3.00
# Specify the prefix of peer ID.
peer-id-prefix=-TR3000-
BIN
View File
Binary file not shown.
+91
View File
@@ -0,0 +1,91 @@
###############################
# Motrix Linux Aria2 config file
#
# @see https://aria2.github.io/manual/en/html/aria2c.html
#
###############################
################ RPC ################
# Enable JSON-RPC/XML-RPC server.
enable-rpc=true
# Add Access-Control-Allow-Origin header field with value * to the RPC response.
rpc-allow-origin-all=true
# Listen incoming JSON-RPC/XML-RPC requests on all network interfaces.
rpc-listen-all=true
################ File system ################
# Save a control file(*.aria2) every SEC seconds.
auto-save-interval=10
# Enable disk cache.
disk-cache=64M
# Specify file allocation method.
file-allocation=trunc
# No file allocation is made for files whose size is smaller than SIZE
no-file-allocation-limit=64M
# Save error/unfinished downloads to a file specified by --save-session option every SEC seconds.
save-session-interval=10
################ Task ################
# Exclude seed only downloads when counting concurrent active downloads
bt-detach-seed-only=true
# Verify the peer using certificates specified in --ca-certificate option.
check-certificate=false
# If aria2 receives "file not found" status from the remote HTTP/FTP servers NUM times
# without getting a single byte, then force the download to fail.
max-file-not-found=10
# Set number of tries.
max-tries=0
# Set the seconds to wait between retries. When SEC > 0, aria2 will retry downloads when the HTTP server returns a 503 response.
retry-wait=10
# Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server. After the connection is established, this option makes no effect and --timeout option is used instead.
connect-timeout=10
# Set timeout in seconds.
timeout=10
# aria2 does not split less than 2*SIZE byte range.
min-split-size=1M
# Send Accept: deflate, gzip request header.
http-accept-gzip=true
# Retrieve timestamp of the remote file from the remote HTTP/FTP server and if it is available, apply it to the local file.
remote-time=true
# Set interval in seconds to output download progress summary. Setting 0 suppresses the output.
summary-interval=0
# Handle quoted string in Content-Disposition header as UTF-8 instead of ISO-8859-1, for example, the filename parameter, but not the extended version filename*.
content-disposition-default-utf8=true
################ BT Task ################
# Enable Local Peer Discovery.
bt-enable-lpd=true
# Requires BitTorrent message payload encryption with arc4.
# bt-force-encryption=true
# If true is given, after hash check using --check-integrity option and file is complete, continue to seed file.
bt-hash-check-seed=true
# Specify the maximum number of peers per torrent.
bt-max-peers=128
# Try to download first and last pieces of each file first. This is useful for previewing files.
bt-prioritize-piece=head
# Removes the unselected files when download is completed in BitTorrent.
bt-remove-unselected-file=true
# Seed previously downloaded files without verifying piece hashes.
bt-seed-unverified=false
# Set the connect timeout in seconds to establish connection to tracker. After the connection is established, this option makes no effect and --bt-tracker-timeout option is used instead.
bt-tracker-connect-timeout=10
# Set timeout in seconds.
bt-tracker-timeout=10
# Set host and port as an entry point to IPv4 DHT network.
dht-entry-point=dht.transmissionbt.com:6881
# Set host and port as an entry point to IPv6 DHT network.
dht-entry-point6=dht.transmissionbt.com:6881
# Enable IPv4 DHT functionality. It also enables UDP tracker support.
enable-dht=true
# Enable IPv6 DHT functionality.
enable-dht6=true
# Enable Peer Exchange extension.
enable-peer-exchange=true
# Specify the string used during the bitorrent extended handshake for the peer's client version.
peer-agent=Transmission/3.00
# Specify the prefix of peer ID.
peer-id-prefix=-TR3000-
BIN
View File
Binary file not shown.
+91
View File
@@ -0,0 +1,91 @@
###############################
# Motrix Linux Aria2 config file
#
# @see https://aria2.github.io/manual/en/html/aria2c.html
#
###############################
################ RPC ################
# Enable JSON-RPC/XML-RPC server.
enable-rpc=true
# Add Access-Control-Allow-Origin header field with value * to the RPC response.
rpc-allow-origin-all=true
# Listen incoming JSON-RPC/XML-RPC requests on all network interfaces.
rpc-listen-all=true
################ File system ################
# Save a control file(*.aria2) every SEC seconds.
auto-save-interval=10
# Enable disk cache.
disk-cache=64M
# Specify file allocation method.
file-allocation=trunc
# No file allocation is made for files whose size is smaller than SIZE
no-file-allocation-limit=64M
# Save error/unfinished downloads to a file specified by --save-session option every SEC seconds.
save-session-interval=10
################ Task ################
# Exclude seed only downloads when counting concurrent active downloads
bt-detach-seed-only=true
# Verify the peer using certificates specified in --ca-certificate option.
check-certificate=false
# If aria2 receives "file not found" status from the remote HTTP/FTP servers NUM times
# without getting a single byte, then force the download to fail.
max-file-not-found=10
# Set number of tries.
max-tries=0
# Set the seconds to wait between retries. When SEC > 0, aria2 will retry downloads when the HTTP server returns a 503 response.
retry-wait=10
# Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server. After the connection is established, this option makes no effect and --timeout option is used instead.
connect-timeout=10
# Set timeout in seconds.
timeout=10
# aria2 does not split less than 2*SIZE byte range.
min-split-size=1M
# Send Accept: deflate, gzip request header.
http-accept-gzip=true
# Retrieve timestamp of the remote file from the remote HTTP/FTP server and if it is available, apply it to the local file.
remote-time=true
# Set interval in seconds to output download progress summary. Setting 0 suppresses the output.
summary-interval=0
# Handle quoted string in Content-Disposition header as UTF-8 instead of ISO-8859-1, for example, the filename parameter, but not the extended version filename*.
content-disposition-default-utf8=true
################ BT Task ################
# Enable Local Peer Discovery.
bt-enable-lpd=true
# Requires BitTorrent message payload encryption with arc4.
# bt-force-encryption=true
# If true is given, after hash check using --check-integrity option and file is complete, continue to seed file.
bt-hash-check-seed=true
# Specify the maximum number of peers per torrent.
bt-max-peers=128
# Try to download first and last pieces of each file first. This is useful for previewing files.
bt-prioritize-piece=head
# Removes the unselected files when download is completed in BitTorrent.
bt-remove-unselected-file=true
# Seed previously downloaded files without verifying piece hashes.
bt-seed-unverified=false
# Set the connect timeout in seconds to establish connection to tracker. After the connection is established, this option makes no effect and --bt-tracker-timeout option is used instead.
bt-tracker-connect-timeout=10
# Set timeout in seconds.
bt-tracker-timeout=10
# Set host and port as an entry point to IPv4 DHT network.
dht-entry-point=dht.transmissionbt.com:6881
# Set host and port as an entry point to IPv6 DHT network.
dht-entry-point6=dht.transmissionbt.com:6881
# Enable IPv4 DHT functionality. It also enables UDP tracker support.
enable-dht=true
# Enable IPv6 DHT functionality.
enable-dht6=true
# Enable Peer Exchange extension.
enable-peer-exchange=true
# Specify the string used during the bitorrent extended handshake for the peer's client version.
peer-agent=Transmission/3.00
# Specify the prefix of peer ID.
peer-id-prefix=-TR3000-
BIN
View File
Binary file not shown.
-122
View File
@@ -1,122 +0,0 @@
## '#'开头为注释内容, 选项都有相应的注释说明, 根据需要修改 ##
## 被注释的选项填写的是默认值, 建议在需要修改时再取消注释 ##
## 添加了@和默认启用的选项都是系统需要调用的,请不要随意改动否则可能无法正常运行
## 文件保存相关 ##
# 文件的保存路径(可使用绝对路径或相对路径), 默认: 当前启动位置
# 此项 OS X 无法使用 $HOME 及 ~/ 设置路径 建议使用 /users/用户名/downloads
#@dir=$HOME/downloads
# 启用磁盘缓存, 0为禁用缓存, 需1.16以上版本, 默认:16M
#@disk-cache=32M
# 文件预分配方式, 能有效降低磁盘碎片, 默认:prealloc
# 预分配所需时间: none < falloc ? trunc < prealloc
# falloc和trunc则需要文件系统和内核支持
# NTFS建议使用falloc, EXT3/4建议trunc, MAC 下需要注释此项
file-allocation=trunc
# 断点续传
#@continue=true
## 下载连接相关 ##
# 最大同时下载任务数, 运行时可修改, 默认:5
#@max-concurrent-downloads=10
# 同一服务器连接数, 添加时可指定, 默认:1
#@max-connection-per-server=15
# 最小文件分片大小, 添加时可指定, 取值范围1M -1024M, 默认:20M
# 假定size=10M, 文件为20MiB 则使用两个来源下载; 文件为15MiB 则使用一个来源下载
#@min-split-size=10M
# 单个任务最大线程数, 添加时可指定, 默认:5
#@split=15
# 整体下载速度限制, 运行时可修改, 默认:0
#@max-overall-download-limit=0
# 单个任务下载速度限制, 默认:0
#@max-download-limit=0
# 整体上传速度限制, 运行时可修改, 默认:0
max-overall-upload-limit=128K
# 单个任务上传速度限制, 默认:0
#@max-upload-limit=0
# 禁用IPv6, 默认:false
disable-ipv6=false
#运行覆盖已存在文件
#@allow-overwrite=true
#自动重命名
#@auto-file-renaming=true
## 进度保存相关 ##
# 从会话文件中读取下载任务
#@input-file=/Users/Shared/aria2.session
# 在Aria2退出时保存`错误/未完成`的下载任务到会话文件
#@save-session=/Users/Shared/aria2.session
# 定时保存会话, 0为退出时才保存, 需1.16.1以上版本, 默认:0
save-session-interval=30
## RPC相关设置 ##
# 启用RPC, 默认:false
enable-rpc=true
# 允许所有来源, 默认:false
rpc-allow-origin-all=true
# 允许非外部访问, 默认:false
rpc-listen-all=true
# 事件轮询方式, 取值:[epoll, kqueue, port, poll, select], 不同系统默认值不同
#event-poll=select
# RPC监听端口, 端口被占用时可以修改, 默认:6800
# 使用本客户端请勿修改此项
# rpc-listen-port=6800
# 设置的RPC授权令牌, v1.18.4新增功能, 取代 --rpc-user 和 --rpc-passwd 选项
#rpc-secret=token
## BT/PT下载相关 ##
# 当下载的是一个种子(以.torrent结尾)时, 自动开始BT任务, 默认:true
#follow-torrent=true
# BT监听端口, 当端口被屏蔽时使用, 默认:6881-6999
listen-port=50101-50109
# 单个种子最大连接数, 默认:55
#bt-max-peers=55
# 打开DHT功能, PT需要禁用, 默认:true
enable-dht=true
# 打开IPv6 DHT功能, PT需要禁用
enable-dht6=true
# DHT网络监听端口, 默认:6881-6999
dht-listen-port=50101-50109
# Set host and port as an entry point to IPv4 DHT network.
dht-entry-point=dht.transmissionbt.com:6881
# Set host and port as an entry point to IPv6 DHT network.
dht-entry-point6=dht.transmissionbt.com:6881
# 本地节点查找, PT需要禁用, 默认:false
bt-enable-lpd=true
# 种子交换, PT需要禁用, 默认:true
enable-peer-exchange=true
# 每个种子限速, 对少种的PT很有用, 默认:50K
#bt-request-peer-speed-limit=50K
# 客户端伪装, PT需要
peer-id-prefix=-TR2770-
user-agent=Transmission/2.94
# 当种子的分享率达到这个数时, 自动停止做种, 0为一直做种, 默认:1.0
seed-ratio=1.0
# 强制保存会话, 即使任务已经完成, 默认:false
# 较新的版本开启后会在任务完成后依然保留.aria2文件
#force-save=false
# BT校验相关, 默认:true
#bt-hash-check-seed=true
# 继续之前的BT任务时, 无需再次校验, 默认:false
bt-seed-unverified=true
# 保存磁力链接元数据为种子文件(.torrent文件), 默认:false
bt-save-metadata=false
# Removes the unselected files when download is completed in BitTorrent.
# To select files, use --select-file option. If it is not used,
# all files are assumed to be selected. Please use this option with care
# because it will actually remove files from your disk. Default: false
bt-remove-unselected-file=true
# Verify the peer using certificates specified
# in --ca-certificate option. Default: true
check-certificate=false
# Exclude seed only downloads when counting concurrent active downloads (See -j option).
# This means that if -j3 is given and this option is turned on and 3 downloads are active and one of those enters seed mode,
# then it is excluded from active download count (thus it becomes 2),
# and the next download waiting in queue gets started.
# But be aware that seeding item is still recognized as active download in RPC method. Default: false
bt-detach-seed-only=true
+91
View File
@@ -0,0 +1,91 @@
###############################
# Motrix Linux Aria2 config file
#
# @see https://aria2.github.io/manual/en/html/aria2c.html
#
###############################
################ RPC ################
# Enable JSON-RPC/XML-RPC server.
enable-rpc=true
# Add Access-Control-Allow-Origin header field with value * to the RPC response.
rpc-allow-origin-all=true
# Listen incoming JSON-RPC/XML-RPC requests on all network interfaces.
rpc-listen-all=true
################ File system ################
# Save a control file(*.aria2) every SEC seconds.
auto-save-interval=10
# Enable disk cache.
disk-cache=64M
# Specify file allocation method.
file-allocation=trunc
# No file allocation is made for files whose size is smaller than SIZE
no-file-allocation-limit=64M
# Save error/unfinished downloads to a file specified by --save-session option every SEC seconds.
save-session-interval=10
################ Task ################
# Exclude seed only downloads when counting concurrent active downloads
bt-detach-seed-only=true
# Verify the peer using certificates specified in --ca-certificate option.
check-certificate=false
# If aria2 receives "file not found" status from the remote HTTP/FTP servers NUM times
# without getting a single byte, then force the download to fail.
max-file-not-found=10
# Set number of tries.
max-tries=0
# Set the seconds to wait between retries. When SEC > 0, aria2 will retry downloads when the HTTP server returns a 503 response.
retry-wait=10
# Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server. After the connection is established, this option makes no effect and --timeout option is used instead.
connect-timeout=10
# Set timeout in seconds.
timeout=10
# aria2 does not split less than 2*SIZE byte range.
min-split-size=1M
# Send Accept: deflate, gzip request header.
http-accept-gzip=true
# Retrieve timestamp of the remote file from the remote HTTP/FTP server and if it is available, apply it to the local file.
remote-time=true
# Set interval in seconds to output download progress summary. Setting 0 suppresses the output.
summary-interval=0
# Handle quoted string in Content-Disposition header as UTF-8 instead of ISO-8859-1, for example, the filename parameter, but not the extended version filename*.
content-disposition-default-utf8=true
################ BT Task ################
# Enable Local Peer Discovery.
bt-enable-lpd=true
# Requires BitTorrent message payload encryption with arc4.
# bt-force-encryption=true
# If true is given, after hash check using --check-integrity option and file is complete, continue to seed file.
bt-hash-check-seed=true
# Specify the maximum number of peers per torrent.
bt-max-peers=128
# Try to download first and last pieces of each file first. This is useful for previewing files.
bt-prioritize-piece=head
# Removes the unselected files when download is completed in BitTorrent.
bt-remove-unselected-file=true
# Seed previously downloaded files without verifying piece hashes.
bt-seed-unverified=false
# Set the connect timeout in seconds to establish connection to tracker. After the connection is established, this option makes no effect and --bt-tracker-timeout option is used instead.
bt-tracker-connect-timeout=10
# Set timeout in seconds.
bt-tracker-timeout=10
# Set host and port as an entry point to IPv4 DHT network.
dht-entry-point=dht.transmissionbt.com:6881
# Set host and port as an entry point to IPv6 DHT network.
dht-entry-point6=dht.transmissionbt.com:6881
# Enable IPv4 DHT functionality. It also enables UDP tracker support.
enable-dht=true
# Enable IPv6 DHT functionality.
enable-dht6=true
# Enable Peer Exchange extension.
enable-peer-exchange=true
# Specify the string used during the bitorrent extended handshake for the peer's client version.
peer-agent=Transmission/3.00
# Specify the prefix of peer ID.
peer-id-prefix=-TR3000-
BIN
View File
Binary file not shown.
-122
View File
@@ -1,122 +0,0 @@
## '#'开头为注释内容, 选项都有相应的注释说明, 根据需要修改 ##
## 被注释的选项填写的是默认值, 建议在需要修改时再取消注释 ##
## 添加了@和默认启用的选项都是系统需要调用的,请不要随意改动否则可能无法正常运行
## 文件保存相关 ##
# 文件的保存路径(可使用绝对路径或相对路径), 默认: 当前启动位置
# 此项 OS X 无法使用 $HOME 及 ~/ 设置路径 建议使用 /users/用户名/downloads
#@dir=$HOME/downloads
# 启用磁盘缓存, 0为禁用缓存, 需1.16以上版本, 默认:16M
#@disk-cache=32M
# 文件预分配方式, 能有效降低磁盘碎片, 默认:prealloc
# 预分配所需时间: none < falloc ? trunc < prealloc
# falloc和trunc则需要文件系统和内核支持
# NTFS建议使用falloc, EXT3/4建议trunc, MAC 下需要注释此项
file-allocation=falloc
# 断点续传
#@continue=true
## 下载连接相关 ##
# 最大同时下载任务数, 运行时可修改, 默认:5
#@max-concurrent-downloads=10
# 同一服务器连接数, 添加时可指定, 默认:1
#@max-connection-per-server=15
# 最小文件分片大小, 添加时可指定, 取值范围1M -1024M, 默认:20M
# 假定size=10M, 文件为20MiB 则使用两个来源下载; 文件为15MiB 则使用一个来源下载
#@min-split-size=10M
# 单个任务最大线程数, 添加时可指定, 默认:5
#@split=15
# 整体下载速度限制, 运行时可修改, 默认:0
#@max-overall-download-limit=0
# 单个任务下载速度限制, 默认:0
#@max-download-limit=0
# 整体上传速度限制, 运行时可修改, 默认:0
max-overall-upload-limit=128K
# 单个任务上传速度限制, 默认:0
#@max-upload-limit=0
# 禁用IPv6, 默认:false
disable-ipv6=false
#运行覆盖已存在文件
#@allow-overwrite=true
#自动重命名
#@auto-file-renaming=true
## 进度保存相关 ##
# 从会话文件中读取下载任务
#@input-file=/Users/Shared/aria2.session
# 在Aria2退出时保存`错误/未完成`的下载任务到会话文件
#@save-session=/Users/Shared/aria2.session
# 定时保存会话, 0为退出时才保存, 需1.16.1以上版本, 默认:0
save-session-interval=30
## RPC相关设置 ##
# 启用RPC, 默认:false
enable-rpc=true
# 允许所有来源, 默认:false
rpc-allow-origin-all=true
# 允许非外部访问, 默认:false
rpc-listen-all=true
# 事件轮询方式, 取值:[epoll, kqueue, port, poll, select], 不同系统默认值不同
#event-poll=select
# RPC监听端口, 端口被占用时可以修改, 默认:6800
# 使用本客户端请勿修改此项
# rpc-listen-port=6800
# 设置的RPC授权令牌, v1.18.4新增功能, 取代 --rpc-user 和 --rpc-passwd 选项
#rpc-secret=token
## BT/PT下载相关 ##
# 当下载的是一个种子(以.torrent结尾)时, 自动开始BT任务, 默认:true
#follow-torrent=true
# BT监听端口, 当端口被屏蔽时使用, 默认:6881-6999
listen-port=50101-50109
# 单个种子最大连接数, 默认:55
#bt-max-peers=55
# 打开DHT功能, PT需要禁用, 默认:true
enable-dht=true
# 打开IPv6 DHT功能, PT需要禁用
enable-dht6=true
# DHT网络监听端口, 默认:6881-6999
dht-listen-port=50101-50109
# Set host and port as an entry point to IPv4 DHT network.
dht-entry-point=dht.transmissionbt.com:6881
# Set host and port as an entry point to IPv6 DHT network.
dht-entry-point6=dht.transmissionbt.com:6881
# 本地节点查找, PT需要禁用, 默认:false
bt-enable-lpd=true
# 种子交换, PT需要禁用, 默认:true
enable-peer-exchange=true
# 每个种子限速, 对少种的PT很有用, 默认:50K
#bt-request-peer-speed-limit=50K
# 客户端伪装, PT需要
peer-id-prefix=-TR2770-
user-agent=Transmission/2.94
# 当种子的分享率达到这个数时, 自动停止做种, 0为一直做种, 默认:1.0
seed-ratio=1.0
# 强制保存会话, 即使任务已经完成, 默认:false
# 较新的版本开启后会在任务完成后依然保留.aria2文件
#force-save=false
# BT校验相关, 默认:true
#bt-hash-check-seed=true
# 继续之前的BT任务时, 无需再次校验, 默认:false
bt-seed-unverified=true
# 保存磁力链接元数据为种子文件(.torrent文件), 默认:false
bt-save-metadata=false
# Removes the unselected files when download is completed in BitTorrent.
# To select files, use --select-file option. If it is not used,
# all files are assumed to be selected. Please use this option with care
# because it will actually remove files from your disk. Default: false
bt-remove-unselected-file=true
# Verify the peer using certificates specified
# in --ca-certificate option. Default: true
check-certificate=false
# Exclude seed only downloads when counting concurrent active downloads (See -j option).
# This means that if -j3 is given and this option is turned on and 3 downloads are active and one of those enters seed mode,
# then it is excluded from active download count (thus it becomes 2),
# and the next download waiting in queue gets started.
# But be aware that seeding item is still recognized as active download in RPC method. Default: false
bt-detach-seed-only=true
Binary file not shown.
+91
View File
@@ -0,0 +1,91 @@
###############################
# Motrix Windows Aria2 config file
#
# @see https://aria2.github.io/manual/en/html/aria2c.html
#
###############################
################ RPC ################
# Enable JSON-RPC/XML-RPC server.
enable-rpc=true
# Add Access-Control-Allow-Origin header field with value * to the RPC response.
rpc-allow-origin-all=true
# Listen incoming JSON-RPC/XML-RPC requests on all network interfaces.
rpc-listen-all=true
################ File system ################
# Save a control file(*.aria2) every SEC seconds.
auto-save-interval=10
# Enable disk cache.
disk-cache=64M
# Specify file allocation method.
file-allocation=none
# No file allocation is made for files whose size is smaller than SIZE
no-file-allocation-limit=64M
# Save error/unfinished downloads to a file specified by --save-session option every SEC seconds.
save-session-interval=10
################ Task ################
# Exclude seed only downloads when counting concurrent active downloads
bt-detach-seed-only=true
# Verify the peer using certificates specified in --ca-certificate option.
check-certificate=false
# If aria2 receives "file not found" status from the remote HTTP/FTP servers NUM times
# without getting a single byte, then force the download to fail.
max-file-not-found=10
# Set number of tries.
max-tries=0
# Set the seconds to wait between retries. When SEC > 0, aria2 will retry downloads when the HTTP server returns a 503 response.
retry-wait=10
# Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server. After the connection is established, this option makes no effect and --timeout option is used instead.
connect-timeout=10
# Set timeout in seconds.
timeout=10
# aria2 does not split less than 2*SIZE byte range.
min-split-size=1M
# Send Accept: deflate, gzip request header.
http-accept-gzip=true
# Retrieve timestamp of the remote file from the remote HTTP/FTP server and if it is available, apply it to the local file.
remote-time=true
# Set interval in seconds to output download progress summary. Setting 0 suppresses the output.
summary-interval=0
# Handle quoted string in Content-Disposition header as UTF-8 instead of ISO-8859-1, for example, the filename parameter, but not the extended version filename*.
content-disposition-default-utf8=true
################ BT Task ################
# Enable Local Peer Discovery.
bt-enable-lpd=true
# Requires BitTorrent message payload encryption with arc4.
# bt-force-encryption=true
# If true is given, after hash check using --check-integrity option and file is complete, continue to seed file.
bt-hash-check-seed=true
# Specify the maximum number of peers per torrent.
bt-max-peers=128
# Try to download first and last pieces of each file first. This is useful for previewing files.
bt-prioritize-piece=head
# Removes the unselected files when download is completed in BitTorrent.
bt-remove-unselected-file=true
# Seed previously downloaded files without verifying piece hashes.
bt-seed-unverified=false
# Set the connect timeout in seconds to establish connection to tracker. After the connection is established, this option makes no effect and --bt-tracker-timeout option is used instead.
bt-tracker-connect-timeout=10
# Set timeout in seconds.
bt-tracker-timeout=10
# Set host and port as an entry point to IPv4 DHT network.
dht-entry-point=dht.transmissionbt.com:6881
# Set host and port as an entry point to IPv6 DHT network.
dht-entry-point6=dht.transmissionbt.com:6881
# Enable IPv4 DHT functionality. It also enables UDP tracker support.
enable-dht=true
# Enable IPv6 DHT functionality.
enable-dht6=true
# Enable Peer Exchange extension.
enable-peer-exchange=true
# Specify the string used during the bitorrent extended handshake for the peer's client version.
peer-agent=Transmission/3.00
# Specify the prefix of peer ID.
peer-id-prefix=-TR3000-
BIN
View File
Binary file not shown.
+91
View File
@@ -0,0 +1,91 @@
###############################
# Motrix Windows Aria2 config file
#
# @see https://aria2.github.io/manual/en/html/aria2c.html
#
###############################
################ RPC ################
# Enable JSON-RPC/XML-RPC server.
enable-rpc=true
# Add Access-Control-Allow-Origin header field with value * to the RPC response.
rpc-allow-origin-all=true
# Listen incoming JSON-RPC/XML-RPC requests on all network interfaces.
rpc-listen-all=true
################ File system ################
# Save a control file(*.aria2) every SEC seconds.
auto-save-interval=10
# Enable disk cache.
disk-cache=64M
# Specify file allocation method.
file-allocation=falloc
# No file allocation is made for files whose size is smaller than SIZE
no-file-allocation-limit=64M
# Save error/unfinished downloads to a file specified by --save-session option every SEC seconds.
save-session-interval=10
################ Task ################
# Exclude seed only downloads when counting concurrent active downloads
bt-detach-seed-only=true
# Verify the peer using certificates specified in --ca-certificate option.
check-certificate=false
# If aria2 receives "file not found" status from the remote HTTP/FTP servers NUM times
# without getting a single byte, then force the download to fail.
max-file-not-found=10
# Set number of tries.
max-tries=0
# Set the seconds to wait between retries. When SEC > 0, aria2 will retry downloads when the HTTP server returns a 503 response.
retry-wait=10
# Set the connect timeout in seconds to establish connection to HTTP/FTP/proxy server. After the connection is established, this option makes no effect and --timeout option is used instead.
connect-timeout=10
# Set timeout in seconds.
timeout=10
# aria2 does not split less than 2*SIZE byte range.
min-split-size=1M
# Send Accept: deflate, gzip request header.
http-accept-gzip=true
# Retrieve timestamp of the remote file from the remote HTTP/FTP server and if it is available, apply it to the local file.
remote-time=true
# Set interval in seconds to output download progress summary. Setting 0 suppresses the output.
summary-interval=0
# Handle quoted string in Content-Disposition header as UTF-8 instead of ISO-8859-1, for example, the filename parameter, but not the extended version filename*.
content-disposition-default-utf8=true
################ BT Task ################
# Enable Local Peer Discovery.
bt-enable-lpd=true
# Requires BitTorrent message payload encryption with arc4.
# bt-force-encryption=true
# If true is given, after hash check using --check-integrity option and file is complete, continue to seed file.
bt-hash-check-seed=true
# Specify the maximum number of peers per torrent.
bt-max-peers=128
# Try to download first and last pieces of each file first. This is useful for previewing files.
bt-prioritize-piece=head
# Removes the unselected files when download is completed in BitTorrent.
bt-remove-unselected-file=true
# Seed previously downloaded files without verifying piece hashes.
bt-seed-unverified=false
# Set the connect timeout in seconds to establish connection to tracker. After the connection is established, this option makes no effect and --bt-tracker-timeout option is used instead.
bt-tracker-connect-timeout=10
# Set timeout in seconds.
bt-tracker-timeout=10
# Set host and port as an entry point to IPv4 DHT network.
dht-entry-point=dht.transmissionbt.com:6881
# Set host and port as an entry point to IPv6 DHT network.
dht-entry-point6=dht.transmissionbt.com:6881
# Enable IPv4 DHT functionality. It also enables UDP tracker support.
enable-dht=true
# Enable IPv6 DHT functionality.
enable-dht6=true
# Enable Peer Exchange extension.
enable-peer-exchange=true
# Specify the string used during the bitorrent extended handshake for the peer's client version.
peer-agent=Transmission/3.00
# Specify the prefix of peer ID.
peer-id-prefix=-TR3000-
+14
View File
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": [
"./src/renderer/*"
],
"@shared/*": [
"./src/shared/*"
]
}
},
"exclude": ["node_modules", "dist"]
}
-20867
View File
File diff suppressed because it is too large Load Diff
+81 -219
View File
@@ -1,13 +1,13 @@
{
"name": "Motrix",
"version": "1.4.1",
"version": "1.8.19",
"description": "A full-featured download manager",
"homepage": "https://motrix.app",
"author": {
"name": "AGALWOOD",
"name": "Dr_rOot",
"email": "agalwood.net@gmail.com"
},
"copyright": "Copyright© AGALWOOD",
"copyright": "Copyright© Dr_rOot",
"license": "MIT",
"main": "./dist/electron/main.js",
"repository": {
@@ -17,236 +17,98 @@
"scripts": {
"release": "npm run build --publish onTagOrDraft",
"build": "node .electron-vue/build.js && electron-builder",
"build:applesilicon": "node .electron-vue/build.js && electron-builder --arm64 --mac",
"build:github": "node .electron-vue/build.js",
"build:dir": "node .electron-vue/build.js && electron-builder --dir",
"build:clean": "cross-env BUILD_TARGET=clean node .electron-vue/build.js",
"build:web": "cross-env BUILD_TARGET=web node .electron-vue/build.js",
"dev": "node .electron-vue/dev-runner.js",
"dev:renderer": "webpack-dev-server --hot --colors --config .electron-vue/webpack.renderer.config.js --port 9080 --content-base app/dist",
"dev:renderer": "webpack serve --node-env development --hot --color --config .electron-vue/webpack.renderer.config.js --port 9080 --content-base app/dist",
"lint": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter src",
"lint:fix": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter --fix src",
"pack": "npm run pack:main && npm run pack:renderer",
"pack:main": "cross-env NODE_ENV=production webpack --mode production --progress --colors --config .electron-vue/webpack.main.config.js",
"pack:renderer": "cross-env NODE_ENV=production webpack --mode production --progress --colors --config .electron-vue/webpack.renderer.config.js",
"pack:main": "webpack --node-env production --progress --color --config .electron-vue/webpack.main.config.js",
"pack:renderer": "webpack --node-env production --progress --color --config .electron-vue/webpack.renderer.config.js",
"postinstall": "electron-builder install-app-deps && npm run lint:fix"
},
"build": {
"productName": "Motrix",
"appId": "net.agalwood.Motrix",
"fileAssociations": [
{
"ext": "torrent",
"mimeType": "application/x-bittorrent",
"name": "Torrent",
"role": "Viewer"
}
],
"asar": true,
"directories": {
"output": "release"
},
"files": [
"dist/electron/**/*"
],
"protocols": [
{
"name": "Motrix Protocol",
"schemes": [
"mo",
"motrix"
]
},
{
"name": "Magnet Protocol",
"schemes": [
"magnet"
]
},
{
"name": "Thunder Protocol",
"schemes": [
"thunder"
]
}
],
"dmg": {
"window": {
"width": 540,
"height": 380
},
"contents": [
{
"x": 410,
"y": 230,
"type": "link",
"path": "/Applications"
},
{
"x": 130,
"y": 230,
"type": "file"
}
]
},
"mac": {
"target": [
"dmg",
"zip"
],
"type": "distribution",
"darkModeSupport": true,
"extraResources": {
"from": "./extra/darwin/",
"to": "./",
"filter": [
"**/*"
]
},
"binaries": [
"./release/mac/Motrix.app/Contents/Resources/engine/aria2c"
],
"category": "public.app-category.utilities"
},
"win": {
"target": [
{
"target": "nsis",
"arch": [
"x64",
"ia32"
]
},
{
"target": "zip",
"arch": [
"x64",
"ia32"
]
},
{
"target": "portable",
"arch": [
"x64",
"ia32"
]
}
],
"extraResources": {
"from": "./extra/win32/",
"to": "./",
"filter": [
"**/*"
]
}
},
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true
},
"linux": {
"category": "Network",
"target": [
"deb",
"snap",
"AppImage"
],
"extraResources": {
"from": "./extra/linux/",
"to": "./",
"filter": [
"**/*"
]
}
},
"publish": [
{
"provider": "generic",
"url": "https://dl.motrix.app/release/"
},
{
"provider": "github"
}
]
"engines": {
"node": ">=16.0.0"
},
"dependencies": {
"@panter/vue-i18next": "^0.15.1",
"aria2": "^4.0.3",
"axios": "^0.19.0",
"blob-util": "^2.0.2",
"clipboard-polyfill": "^2.8.1",
"electron-debug": "^3.0.0",
"electron-is": "^3.0.0",
"electron-log": "^3.0.6",
"electron-updater": "^4.0.12",
"element-ui": "^2.9.1",
"forever-monitor": "^1.7.1",
"i18next": "^17.0.3",
"lodash": "^4.17.11",
"normalize.css": "^8.0.1",
"parse-torrent": "^6.1.2",
"randomatic": "^3.1.1",
"svg-innerhtml": "^1.1.0",
"vue": "^2.6.10",
"vue-electron": "^1.0.6",
"vue-router": "^3.0.6",
"vuex": "^3.1.1",
"vuex-router-sync": "^5.0.0"
"node-fetch": "^2.6.1",
"ws": "^8.13.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.6.0",
"@vue/cli-plugin-eslint": "^3.6.0",
"@vue/cli-service": "^3.6.0",
"@vue/eslint-config-standard": "^4.0.0",
"ajv": "^6.10.0",
"babel-core": "^6.26.3",
"babel-eslint": "^10.0.2",
"babel-loader": "^7.1.5",
"@babel/core": "^7.21.8",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-transform-runtime": "^7.21.4",
"@babel/preset-env": "^7.21.5",
"@babel/register": "^7.21.0",
"@babel/runtime": "^7.21.5",
"@bany/curl-to-json": "^1.2.7",
"@electron/notarize": "^1.2.3",
"@electron/osx-sign": "^1.0.4",
"@electron/remote": "^2.0.9",
"@motrix/multispinner": "^0.2.4",
"@motrix/nat-api": "^0.3.4",
"@panter/vue-i18next": "^0.15.2",
"@vue/eslint-config-standard": "^6.1.0",
"ajv": "^8.12.0",
"axios": "^1.4.0",
"babel-eslint": "^10.1.0",
"babel-loader": "^9.1.2",
"babel-plugin-component": "^1.1.1",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.7.0",
"babel-preset-stage-0": "^6.24.1",
"babel-register": "^6.26.0",
"babili-webpack-plugin": "^0.1.2",
"cfonts": "^2.4.3",
"chalk": "^2.4.2",
"copy-webpack-plugin": "^5.0.3",
"cross-env": "^5.1.6",
"css-loader": "^2.1.1",
"del": "^4.1.1",
"devtron": "^1.4.0",
"electron": "^4.2.4",
"electron-builder": "^20.43.0",
"electron-devtools-installer": "^2.2.4",
"electron-notarize": "^0.1.1",
"electron-osx-sign": "^0.4.11",
"electron-store": "^2.0.0",
"eslint": "^5.16.0",
"eslint-config-standard": "^12.0.0",
"bittorrent-peerid": "^1.3.6",
"blob-util": "^2.0.2",
"cfonts": "^3.2.0",
"chalk": "^4.1.2",
"copy-webpack-plugin": "^11.0.0",
"cross-env": "^7.0.3",
"css-loader": "^6.7.3",
"css-minimizer-webpack-plugin": "^5.0.0",
"del": "^6.1.1",
"electron": "^22.3.9",
"electron-builder": "^24.4.0",
"electron-devtools-installer": "^3.2.0",
"electron-is": "^3.0.0",
"electron-log": "^4.4.8",
"electron-store": "^8.1.0",
"electron-updater": "^6.1.0",
"element-ui": "^2.15.13",
"eslint": "^7.32.0",
"eslint-friendly-formatter": "^4.0.1",
"eslint-loader": "^2.1.2",
"eslint-plugin-html": "^4.0.6",
"eslint-plugin-import": "^2.17.3",
"eslint-plugin-node": "^8.0.1",
"eslint-plugin-promise": "^4.1.1",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^5.2.2",
"file-loader": "^3.0.1",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "0.7.0",
"multispinner": "^0.2.1",
"node-loader": "^0.6.0",
"node-sass": "^4.12.0",
"optimize-css-assets-webpack-plugin": "^5.0.1",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"url-loader": "^1.1.2",
"vue-html-loader": "^1.2.4",
"vue-loader": "^15.7.0",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.33.0",
"webpack-cli": "^3.3.4",
"webpack-dev-server": "^3.7.1",
"webpack-hot-middleware": "^2.25.0",
"webpack-merge": "^4.2.1"
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-vue": "^9.12.0",
"eslint-webpack-plugin": "^4.0.1",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.5.1",
"i18next": "^22.4.15",
"lodash": "^4.17.21",
"mini-css-extract-plugin": "2.7.5",
"node-loader": "^2.0.0",
"normalize.css": "^8.0.1",
"parse-torrent": "^9.1.5",
"randomatic": "^3.1.1",
"sass": "1.62.1",
"sass-loader": "^12.6.0",
"style-loader": "^3.3.2",
"terser-webpack-plugin": "^5.3.8",
"vue": "^2.7.14",
"vue-electron": "^1.0.6",
"vue-loader": "^15.10.1",
"vue-router": "^3.6.5",
"vue-selectable": "^0.5.0",
"vue-style-loader": "^4.1.3",
"vue-template-compiler": "^2.7.14",
"vuex": "^3.6.2",
"vuex-router-sync": "^5.0.0",
"webpack": "^5.82.1",
"webpack-cli": "^5.1.1",
"webpack-dev-server": "^4.15.0",
"webpack-hot-middleware": "^2.25.3",
"webpack-merge": "^5.8.0",
"worker-loader": "^3.0.8"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

+32 -5
View File
@@ -10,22 +10,49 @@
</script>
<% } %>
</head>
<style>
.skeleton-aside {
background-color: rgba(0, 0, 0, 0.8);
width: 78px;
}
.skeleton-subnav {
background-color: #f4f5f7;
width: 200px;
}
.skeleton-main {
background-color: #fff;
}
@media (prefers-color-scheme: dark) {
.skeleton-aside {
background-color: rgba(0, 0, 0, 0.9);
}
.skeleton-subnav {
background-color: #2D2D2D;
}
.skeleton-main {
background-color: #343434;
}
}
</style>
<body>
<div id="app">
<div class="title-bar"></div>
<section class="el-container" id="container">
<aside class="el-aside aside" style="width: 78px;">
<aside class="el-aside skeleton-aside hidden-sm-and-down">
</aside>
<aside class="el-aside subnav" style="width: 200px;">
<aside class="el-aside skeleton-subnav hidden-xs-only">
</aside>
<section class="el-container main">
<section class="el-container skeleton-main">
</section>
</section>
</div>
<!-- Set `__static` path to static files in production -->
<% if (!process.browser) { %>
<% if (!htmlWebpackPlugin.options.isBrowser && !htmlWebpackPlugin.options.isDev) { %>
<script>
if (process.env.NODE_ENV !== 'development') window.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
window.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
</script>
<% } %>
+647 -105
View File
@@ -1,13 +1,29 @@
import { EventEmitter } from 'events'
import { EventEmitter } from 'node:events'
import { readFile, unlink } from 'node:fs'
import { extname, basename } from 'node:path'
import { app, shell, dialog, ipcMain } from 'electron'
import is from 'electron-is'
import { readFile } from 'fs'
import { extname, basename } from 'path'
import { isEmpty, isEqual } from 'lodash'
import {
APP_RUN_MODE,
AUTO_SYNC_TRACKER_INTERVAL,
AUTO_CHECK_UPDATE_INTERVAL
} from '@shared/constants'
import { checkIsNeedRun } from '@shared/utils'
import {
convertTrackerDataToComma,
fetchBtTrackerFromSource,
reduceTrackerString
} from '@shared/utils/tracker'
import { showItemInFolder } from './utils'
import logger from './core/Logger'
import Context from './core/Context'
import ConfigManager from './core/ConfigManager'
import { setupLocaleManager } from '@/ui/Locale'
import { setupLocaleManager } from './ui/Locale'
import Engine from './core/Engine'
import EngineClient from './core/EngineClient'
import UPnPManager from './core/UPnPManager'
import AutoLaunchManager from './core/AutoLaunchManager'
import UpdateManager from './core/UpdateManager'
import EnergyManager from './core/EnergyManager'
@@ -16,8 +32,8 @@ import WindowManager from './ui/WindowManager'
import MenuManager from './ui/MenuManager'
import TouchBarManager from './ui/TouchBarManager'
import TrayManager from './ui/TrayManager'
import DockManager from './ui/DockManager'
import ThemeManager from './ui/ThemeManager'
import { AUTO_CHECK_UPDATE_INTERVAL } from '@shared/constants'
export default class Application extends EventEmitter {
constructor () {
@@ -27,32 +43,35 @@ export default class Application extends EventEmitter {
}
init () {
this.configManager = new ConfigManager()
this.initContext()
this.locale = this.configManager.getLocale()
this.localeManager = setupLocaleManager(this.locale)
this.i18n = this.localeManager.getI18n()
this.initConfigManager()
this.menuManager = new MenuManager()
this.menuManager.setup(this.locale)
this.setupLogger()
this.initTouchBarManager()
this.initLocaleManager()
this.setupApplicationMenu()
this.initWindowManager()
this.engine = new Engine({
systemConfig: this.configManager.getSystemConfig(),
userConfig: this.configManager.getUserConfig()
})
this.initUPnPManager()
this.startEngine()
this.trayManager = new TrayManager()
this.initEngineClient()
this.autoLaunchManager = new AutoLaunchManager()
this.initTouchBarManager()
this.initThemeManager()
this.energyManager = new EnergyManager()
this.initTrayManager()
this.initDockManager()
this.initAutoLaunchManager()
this.initEnergyManager()
this.initUpdaterManager()
@@ -60,11 +79,77 @@ export default class Application extends EventEmitter {
this.handleCommands()
this.handleEvents()
this.handleIpcMessages()
this.handleIpcInvokes()
this.emit('application:initialized')
}
initContext () {
this.context = new Context()
}
initConfigManager () {
this.configListeners = {}
this.configManager = new ConfigManager()
}
offConfigListeners () {
try {
Object.keys(this.configListeners).forEach((key) => {
this.configListeners[key]()
})
} catch (e) {
logger.warn('[Motrix] offConfigListeners===>', e)
}
this.configListeners = {}
}
setupLogger () {
const { userConfig } = this.configManager
const key = 'log-level'
const logLevel = userConfig.get(key)
logger.transports.file.level = logLevel
this.configListeners[key] = userConfig.onDidChange(key, async (newValue, oldValue) => {
logger.info(`[Motrix] detected ${key} value change event:`, newValue, oldValue)
logger.transports.file.level = newValue
})
}
initLocaleManager () {
this.locale = this.configManager.getLocale()
this.localeManager = setupLocaleManager(this.locale)
this.i18n = this.localeManager.getI18n()
}
setupApplicationMenu () {
this.menuManager = new MenuManager()
this.menuManager.setup(this.locale)
}
adjustMenu () {
if (is.mas()) {
const visibleStates = {
'app.check-for-updates': false,
'task.new-bt-task': false
}
this.menuManager.updateMenuStates(visibleStates, null, null)
this.trayManager.updateMenuStates(visibleStates, null, null)
}
}
startEngine () {
const self = this
try {
this.engine = new Engine({
systemConfig: this.configManager.getSystemConfig(),
userConfig: this.configManager.getUserConfig()
})
this.engine.start()
} catch (err) {
const { message } = err
@@ -72,14 +157,290 @@ export default class Application extends EventEmitter {
type: 'error',
title: this.i18n.t('app.system-error-title'),
message: this.i18n.t('app.system-error-message', { message })
}, () => {
}).then(_ => {
setTimeout(() => {
app.quit()
self.quit()
}, 100)
})
}
}
async stopEngine () {
logger.info('[Motrix] stopEngine===>')
try {
await this.engineClient.shutdown({ force: true })
logger.info('[Motrix] stopEngine.setImmediate===>')
setImmediate(() => {
this.engine.stop()
})
} catch (err) {
logger.warn('[Motrix] shutdown engine fail: ', err.message)
} finally {
// no finally
}
}
initEngineClient () {
const port = this.configManager.getSystemConfig('rpc-listen-port')
const secret = this.configManager.getSystemConfig('rpc-secret')
this.engineClient = new EngineClient({
port,
secret
})
}
initAutoLaunchManager () {
this.autoLaunchManager = new AutoLaunchManager()
}
initEnergyManager () {
this.energyManager = new EnergyManager()
}
initTrayManager () {
this.trayManager = new TrayManager({
theme: this.configManager.getUserConfig('tray-theme'),
systemTheme: this.themeManager.getSystemTheme(),
speedometer: this.configManager.getUserConfig('tray-speedometer'),
runMode: this.configManager.getUserConfig('run-mode')
})
this.watchTraySpeedometerEnabledChange()
this.trayManager.on('mouse-down', ({ focused }) => {
this.sendCommandToAll('application:update-tray-focused', { focused })
})
this.trayManager.on('mouse-up', ({ focused }) => {
this.sendCommandToAll('application:update-tray-focused', { focused })
})
this.trayManager.on('drop-files', (files = []) => {
this.handleFile(files[0])
})
this.trayManager.on('drop-text', (text) => {
this.handleProtocol(text)
})
}
watchTraySpeedometerEnabledChange () {
const { userConfig } = this.configManager
const key = 'tray-speedometer'
this.configListeners[key] = userConfig.onDidChange(key, async (newValue, oldValue) => {
logger.info(`[Motrix] detected ${key} value change event:`, newValue, oldValue)
this.trayManager.handleSpeedometerEnableChange(newValue)
})
}
initDockManager () {
this.dockManager = new DockManager({
runMode: this.configManager.getUserConfig('run-mode')
})
}
watchOpenAtLoginChange () {
const { userConfig } = this.configManager
const key = 'open-at-login'
this.configListeners[key] = userConfig.onDidChange(key, async (newValue, oldValue) => {
logger.info(`[Motrix] detected ${key} value change event:`, newValue, oldValue)
if (is.linux()) {
return
}
if (newValue) {
this.autoLaunchManager.enable()
} else {
this.autoLaunchManager.disable()
}
})
}
watchProtocolsChange () {
const { userConfig } = this.configManager
const key = 'protocols'
this.configListeners[key] = userConfig.onDidChange(key, async (newValue, oldValue) => {
logger.info(`[Motrix] detected ${key} value change event:`, newValue, oldValue)
if (!newValue || isEqual(newValue, oldValue)) {
return
}
logger.info('[Motrix] setup protocols client:', newValue)
this.protocolManager.setup(newValue)
})
}
watchRunModeChange () {
const { userConfig } = this.configManager
const key = 'run-mode'
this.configListeners[key] = userConfig.onDidChange(key, async (newValue, oldValue) => {
logger.info(`[Motrix] detected ${key} value change event:`, newValue, oldValue)
this.trayManager.handleRunModeChange(newValue)
if (newValue !== APP_RUN_MODE.TRAY) {
this.dockManager.show()
} else {
this.dockManager.hide()
// Hiding the dock icon will trigger the entire app to hide.
this.show()
}
})
}
watchShowProgressBarChange () {
const { userConfig } = this.configManager
const key = 'show-progress-bar'
this.configListeners[key] = userConfig.onDidChange(key, async (newValue, oldValue) => {
logger.info(`[Motrix] detected ${key} value change event:`, newValue, oldValue)
if (newValue) {
this.bindProgressChange()
} else {
this.unbindProgressChange()
}
})
}
initUPnPManager () {
this.upnp = new UPnPManager()
this.watchUPnPEnabledChange()
this.watchUPnPPortsChange()
const enabled = this.configManager.getUserConfig('enable-upnp')
if (!enabled) {
return
}
this.startUPnPMapping()
}
async startUPnPMapping () {
const btPort = this.configManager.getSystemConfig('listen-port')
const dhtPort = this.configManager.getSystemConfig('dht-listen-port')
const promises = [
this.upnp.map(btPort),
this.upnp.map(dhtPort)
]
try {
await Promise.allSettled(promises)
} catch (e) {
logger.warn('[Motrix] start UPnP mapping fail', e.message)
}
}
async stopUPnPMapping () {
const btPort = this.configManager.getSystemConfig('listen-port')
const dhtPort = this.configManager.getSystemConfig('dht-listen-port')
const promises = [
this.upnp.unmap(btPort),
this.upnp.unmap(dhtPort)
]
try {
await Promise.allSettled(promises)
} catch (e) {
logger.warn('[Motrix] stop UPnP mapping fail', e)
}
}
watchUPnPPortsChange () {
const { systemConfig } = this.configManager
const watchKeys = ['listen-port', 'dht-listen-port']
watchKeys.forEach((key) => {
this.configListeners[key] = systemConfig.onDidChange(key, async (newValue, oldValue) => {
logger.info('[Motrix] detected port change event:', key, newValue, oldValue)
const enable = this.configManager.getUserConfig('enable-upnp')
if (!enable) {
return
}
const promises = [
this.upnp.unmap(oldValue),
this.upnp.map(newValue)
]
try {
await Promise.allSettled(promises)
} catch (e) {
logger.info('[Motrix] change UPnP port mapping failed:', e)
}
})
})
}
watchUPnPEnabledChange () {
const { userConfig } = this.configManager
const key = 'enable-upnp'
this.configListeners[key] = userConfig.onDidChange(key, async (newValue, oldValue) => {
logger.info('[Motrix] detected enable-upnp value change event:', newValue, oldValue)
if (newValue) {
this.startUPnPMapping()
} else {
await this.stopUPnPMapping()
this.upnp.closeClient()
}
})
}
async shutdownUPnPManager () {
const enable = this.configManager.getUserConfig('enable-upnp')
if (enable) {
await this.stopUPnPMapping()
}
this.upnp.closeClient()
}
autoSyncTracker () {
const enable = this.configManager.getUserConfig('auto-sync-tracker')
const lastTime = this.configManager.getUserConfig('last-sync-tracker-time')
const result = checkIsNeedRun(enable, lastTime, AUTO_SYNC_TRACKER_INTERVAL)
logger.info('[Motrix] auto sync tracker checkIsNeedRun:', result)
if (!result) {
return
}
const source = this.configManager.getUserConfig('tracker-source')
if (isEmpty(source)) {
return
}
setTimeout(() => {
fetchBtTrackerFromSource(source).then((data) => {
logger.warn('[Motrix] auto sync tracker data:', data)
if (!data || data.length === 0) {
return
}
let tracker = convertTrackerDataToComma(data)
tracker = reduceTrackerString(tracker)
this.savePreference({
system: {
'bt-tracker': tracker
},
user: {
'last-sync-tracker-time': Date.now()
}
})
}).catch((err) => {
logger.warn('[Motrix] auto sync tracker failed:', err.message)
})
}, 500)
}
autoResumeTask () {
const enabled = this.configManager.getUserConfig('resume-all-when-app-launched')
if (!enabled) {
return
}
this.engineClient.call('unpauseAll')
}
initWindowManager () {
this.windowManager = new WindowManager({
userConfig: this.configManager.getUserConfig()
@@ -88,12 +449,25 @@ export default class Application extends EventEmitter {
this.windowManager.on('window-resized', (data) => {
this.storeWindowState(data)
})
this.windowManager.on('window-moved', (data) => {
this.storeWindowState(data)
})
this.windowManager.on('window-closed', (data) => {
this.storeWindowState(data)
})
this.windowManager.on('enter-full-screen', (window) => {
this.dockManager.show()
})
this.windowManager.on('leave-full-screen', (window) => {
const mode = this.configManager.getUserConfig('run-mode')
if (mode === APP_RUN_MODE.TRAY) {
this.dockManager.hide()
}
})
}
storeWindowState (data = {}) {
@@ -112,23 +486,26 @@ export default class Application extends EventEmitter {
}
start (page, options = {}) {
this.showPage(page, options)
}
const win = this.showPage(page, options)
showPage (page, options = {}) {
const { openedAtLogin } = options
const win = this.windowManager.openWindow(page, {
hidden: openedAtLogin
})
win.once('ready-to-show', () => {
this.isReady = true
this.emit('ready')
})
if (is.macOS()) {
this.touchBarManager.setup(page, win)
}
}
showPage (page, options = {}) {
const { openedAtLogin } = options
const autoHideWindow = this.configManager.getUserConfig('auto-hide-window')
return this.windowManager.openWindow(page, {
hidden: openedAtLogin || autoHideWindow
})
}
show (page = 'index') {
this.windowManager.showWindow(page)
}
@@ -150,9 +527,27 @@ export default class Application extends EventEmitter {
}
stop () {
this.engine.stop()
this.energyManager.stopPowerSaveBlocker()
this.trayManager.destroy()
try {
const promises = [
this.stopEngine(),
this.shutdownUPnPManager(),
this.energyManager.stopPowerSaveBlocker(),
this.trayManager.destroy()
]
return promises
} catch (err) {
logger.warn('[Motrix] stop error: ', err.message)
}
}
async stopAllSettled () {
await Promise.allSettled(this.stop())
}
async quit () {
await this.stopAllSettled()
app.exit()
}
sendCommand (command, ...args) {
@@ -180,9 +575,9 @@ export default class Application extends EventEmitter {
initThemeManager () {
this.themeManager = new ThemeManager()
this.themeManager.on('system-theme-changed', (theme) => {
this.trayManager.changeIconTheme(theme)
this.sendCommandToAll('application:system-theme', theme)
this.themeManager.on('system-theme-change', (theme) => {
this.trayManager.handleSystemThemeChange(theme)
this.sendCommandToAll('application:update-system-theme', { theme })
})
}
@@ -190,13 +585,11 @@ export default class Application extends EventEmitter {
if (!is.macOS()) {
return
}
this.touchBarManager = new TouchBarManager()
}
initProtocolManager () {
if (is.dev() || is.mas()) {
return
}
const protocols = this.configManager.getUserConfig('protocols', {})
this.protocolManager = new ProtocolManager({
protocols
@@ -204,10 +597,6 @@ export default class Application extends EventEmitter {
}
handleProtocol (url) {
if (is.dev() || is.mas()) {
return
}
this.show()
this.protocolManager.handle(url)
@@ -224,15 +613,17 @@ export default class Application extends EventEmitter {
this.show()
const fileName = basename(filePath)
const name = 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)
const dataURL = Buffer.from(data).toString('base64')
this.sendCommandToAll('application:new-bt-task-with-file', {
name,
dataURL
})
})
}
@@ -240,27 +631,20 @@ export default class Application extends EventEmitter {
if (is.mas()) {
return
}
const enabled = this.configManager.getUserConfig('auto-check-update')
const lastTime = this.configManager.getUserConfig('last-check-update-time')
this.updateManager = new UpdateManager({
autoCheck: this.isNeedAutoCheck(),
setCheckTime: this.configManager
autoCheck: checkIsNeedRun(enabled, lastTime, AUTO_CHECK_UPDATE_INTERVAL)
})
this.handleUpdaterEvents()
}
isNeedAutoCheck () {
const enable = this.configManager.getUserConfig('auto-check-update')
if (!enable) {
return false
}
const lastCheck = this.configManager.getUserConfig('last-check-update-time')
return (Date.now() - lastCheck > AUTO_CHECK_UPDATE_INTERVAL)
}
handleUpdaterEvents () {
this.updateManager.on('checking', (event) => {
this.menuManager.updateMenuItemEnabledState('app.check-for-updates', false)
this.trayManager.updateMenuItemEnabledState('app.check-for-updates', false)
this.configManager.setUserConfig('last-check-update-time', Date.now())
})
this.updateManager.on('download-progress', (event) => {
@@ -277,11 +661,19 @@ export default class Application extends EventEmitter {
this.menuManager.updateMenuItemEnabledState('app.check-for-updates', true)
this.trayManager.updateMenuItemEnabledState('app.check-for-updates', true)
const win = this.windowManager.getWindow('index')
win.setProgressBar(0)
win.setProgressBar(1)
})
this.updateManager.on('will-updated', (event) => {
this.updateManager.on('update-cancelled', (event) => {
this.menuManager.updateMenuItemEnabledState('app.check-for-updates', true)
this.trayManager.updateMenuItemEnabledState('app.check-for-updates', true)
const win = this.windowManager.getWindow('index')
win.setProgressBar(-1)
})
this.updateManager.on('will-updated', async (event) => {
this.windowManager.setWillQuit(true)
await this.stopAllSettled()
})
this.updateManager.on('update-error', (event) => {
@@ -290,51 +682,69 @@ export default class Application extends EventEmitter {
})
}
relaunch (page = 'index') {
this.stop()
async relaunch () {
await this.stopAllSettled()
app.relaunch()
app.exit()
// this.closePage(page)
// if (page === 'index') {
// this.engine.restart()
// }
// setTimeout(() => {
// this.showPage(page)
// }, 500)
}
async resetSession () {
await this.stopEngine()
app.clearRecentDocuments()
const sessionPath = this.context.get('session-path')
setTimeout(() => {
unlink(sessionPath, (err) => {
logger.info('[Motrix] Removed the download seesion file:', err)
})
this.engine.start()
}, 3000)
}
savePreference (config = {}) {
logger.info('[Motrix] save preference:', config)
const { system, user } = config
if (!isEmpty(system)) {
console.info('[Motrix] main save system config: ', system)
this.configManager.setSystemConfig(system)
this.engineClient.changeGlobalOption(system)
}
if (!isEmpty(user)) {
console.info('[Motrix] main save user config: ', user)
this.configManager.setUserConfig(user)
}
}
handleCommands () {
this.on('application:save-preference', this.savePreference)
this.on('application:update-tray', (tray) => {
this.trayManager.updateTrayByImage(tray)
})
this.on('application:relaunch', () => {
this.relaunch()
})
this.on('application:exit', () => {
this.stop()
app.exit()
this.on('application:quit', () => {
this.quit()
})
this.on('application:open-at-login', (openAtLogin) => {
console.log('application:open-at-login===>', openAtLogin)
if (is.linux()) {
return
}
if (openAtLogin) {
this.autoLaunchManager.enable()
} else {
this.autoLaunchManager.disable()
}
})
this.on('application:show', (page) => {
this.on('application:show', ({ page }) => {
this.show(page)
})
this.on('application:hide', (page) => {
this.on('application:hide', ({ page }) => {
this.hide(page)
})
this.on('application:reset-session', () => this.resetSession())
this.on('application:reset', () => {
this.offConfigListeners()
this.configManager.reset()
this.relaunch()
})
@@ -344,19 +754,41 @@ export default class Application extends EventEmitter {
})
this.on('application:change-theme', (theme) => {
this.themeManager.updateAppAppearance(theme)
this.sendCommandToAll('application:theme', theme)
this.themeManager.updateSystemTheme(theme)
this.sendCommandToAll('application:update-theme', { theme })
})
this.on('application:change-locale', (locale) => {
logger.info('[Motrix] application:change-locale===>', locale)
this.localeManager.changeLanguageByLocale(locale)
.then(() => {
this.menuManager.setup(locale)
this.trayManager.setup(locale)
this.menuManager.handleLocaleChange(locale)
this.trayManager.handleLocaleChange(locale)
})
})
this.on('application:toggle-dock', (visible) => {
if (visible) {
this.dockManager.show()
} else {
this.dockManager.hide()
// Hiding the dock icon will trigger the entire app to hide.
this.show()
}
})
this.on('application:auto-hide-window', (hide) => {
if (hide) {
this.windowManager.handleWindowBlur()
} else {
this.windowManager.unbindWindowBlur()
}
})
this.on('application:change-menu-states', (visibleStates, enabledStates, checkedStates) => {
this.menuManager.updateMenuStates(visibleStates, enabledStates, checkedStates)
this.trayManager.updateMenuStates(visibleStates, enabledStates, checkedStates)
})
this.on('application:open-file', (event) => {
dialog.showOpenDialog({
properties: ['openFile'],
@@ -366,8 +798,8 @@ export default class Application extends EventEmitter {
extensions: ['torrent']
}
]
}, (filePaths) => {
if (!filePaths || filePaths.length === 0) {
}).then(({ canceled, filePaths }) => {
if (canceled || filePaths.length === 0) {
return
}
@@ -381,47 +813,157 @@ export default class Application extends EventEmitter {
})
this.on('application:setup-protocols-client', (protocols) => {
if (is.dev() || is.mas()) {
if (is.dev() || is.mas() || !protocols) {
return
}
console.log('this.protocolManager', protocols)
logger.info('[Motrix] setup protocols client:', protocols)
this.protocolManager.setup(protocols)
})
this.on('application:open-external', (url) => {
this.openExternal(url)
})
this.on('application:reveal-in-folder', (data) => {
const { gid, path } = data
logger.info('[Motrix] application:reveal-in-folder===>', path)
if (path) {
showItemInFolder(path)
}
if (gid) {
this.sendCommandToAll('application:show-task-detail', { gid })
}
})
this.on('help:official-website', () => {
const url = 'https://motrix.app/'
shell.openExternal(url)
this.openExternal(url)
})
this.on('help:manual', () => {
const url = 'https://motrix.app/manual'
shell.openExternal(url)
this.openExternal(url)
})
this.on('help:release-notes', () => {
const url = 'https://motrix.app/release'
shell.openExternal(url)
this.openExternal(url)
})
this.on('help:report-problem', () => {
const url = 'https://motrix.app/report'
shell.openExternal(url)
this.openExternal(url)
})
}
openExternal (url) {
if (!url) {
return
}
shell.openExternal(url)
}
handleConfigChange (configName) {
this.sendCommandToAll('application:update-preference-config', { configName })
}
handleEvents () {
this.once('application:initialized', () => {
this.autoSyncTracker()
this.autoResumeTask()
this.adjustMenu()
})
this.configManager.userConfig.onDidAnyChange(() => this.handleConfigChange('user'))
this.configManager.systemConfig.onDidAnyChange(() => this.handleConfigChange('system'))
this.watchOpenAtLoginChange()
this.watchProtocolsChange()
this.watchRunModeChange()
this.watchShowProgressBarChange()
this.on('download-status-change', (downloading) => {
this.trayManager.handleDownloadStatusChange(downloading)
if (downloading) {
this.energyManager.startPowerSaveBlocker()
} else {
this.energyManager.stopPowerSaveBlocker()
}
})
this.on('speed-change', (speed) => {
this.dockManager.handleSpeedChange(speed)
this.trayManager.handleSpeedChange(speed)
})
this.on('task-download-complete', (task, path) => {
this.dockManager.openDock(path)
if (is.linux()) {
return
}
app.addRecentDocument(path)
})
if (this.configManager.userConfig.get('show-progress-bar')) {
this.bindProgressChange()
}
}
handleProgressChange (progress) {
if (this.updateManager.isChecking) {
return
}
if (!is.windows() && progress === 2) {
progress = 0
}
this.windowManager.getWindow('index').setProgressBar(progress)
}
bindProgressChange () {
if (this.listeners('progress-change').length > 0) {
return
}
this.on('progress-change', this.handleProgressChange)
}
unbindProgressChange () {
if (this.listeners('progress-change').length === 0) {
return
}
this.off('progress-change', this.handleProgressChange)
this.windowManager.getWindow('index').setProgressBar(-1)
}
handleIpcMessages () {
ipcMain.on('command', (event, command, ...args) => {
logger.log('receive command', command, ...args)
logger.log('[Motrix] ipc receive command', command, ...args)
this.emit(command, ...args)
})
ipcMain.on('update-menu-states', (event, visibleStates, enabledStates, checkedStates) => {
this.menuManager.updateMenuStates(visibleStates, enabledStates, checkedStates)
this.trayManager.updateMenuStates(visibleStates, enabledStates, checkedStates)
ipcMain.on('event', (event, eventName, ...args) => {
logger.log('[Motrix] ipc receive event', eventName, ...args)
this.emit(eventName, ...args)
})
}
ipcMain.on('download-status-change', (event, status) => {
this.trayManager.updateStatus(status)
handleIpcInvokes () {
ipcMain.handle('get-app-config', async () => {
const systemConfig = this.configManager.getSystemConfig()
const userConfig = this.configManager.getUserConfig()
const context = this.context.get()
const result = {
...systemConfig,
...userConfig,
...context
}
return result
})
}
}
+16 -10
View File
@@ -1,4 +1,4 @@
import { EventEmitter } from 'events'
import { EventEmitter } from 'node:events'
import { app } from 'electron'
import is from 'electron-is'
@@ -10,8 +10,7 @@ import {
parseArgvAsUrl,
parseArgvAsFile
} from './utils'
const EMPTY_STRING = ''
import { EMPTY_STRING } from '@shared/constants'
export default class Launcher extends EventEmitter {
constructor () {
@@ -27,7 +26,7 @@ export default class Launcher extends EventEmitter {
makeSingleInstance (callback) {
// Mac App Store Sandboxed App not support requestSingleInstanceLock
if (is.mas()) {
callback()
callback && callback()
return
}
@@ -37,14 +36,13 @@ export default class Launcher extends EventEmitter {
app.quit()
} else {
app.on('second-instance', (event, argv, workingDirectory) => {
logger.warn('second-instance====>', argv, workingDirectory)
global.application.showPage('index')
if (!is.macOS() && argv.length > 1) {
this.handleAppLaunchArgv(argv)
}
})
callback()
callback && callback()
}
}
@@ -59,12 +57,13 @@ export default class Launcher extends EventEmitter {
this.handleAppLaunchArgv(process.argv)
}
logger.warn('openedAtLogin===>', this.openedAtLogin)
logger.info('[Motrix] openedAtLogin:', this.openedAtLogin)
this.handleAppEvents()
}
handleAppEvents () {
this.handleRendererRemote()
this.handleOpenUrl()
this.handleOpenFile()
@@ -72,6 +71,12 @@ export default class Launcher extends EventEmitter {
this.handleAppWillQuit()
}
handleRendererRemote () {
app.on('browser-window-created', (_, window) => {
require('@electron/remote/main').enable(window.webContents)
})
}
/**
* handleOpenUrl
* Event 'open-url' macOS only
@@ -113,12 +118,12 @@ export default class Launcher extends EventEmitter {
* @param {array} argv
*/
handleAppLaunchArgv (argv) {
logger.info('handleAppLaunchArgv===>', argv)
logger.info('[Motrix] handleAppLaunchArgv:', argv)
// args: array, extra: map
const { args, extra } = splitArgv(argv)
logger.info('splitArgv.args===>', args)
logger.info('splitArgv.extra===>', extra)
logger.info('[Motrix] split argv args:', args)
logger.info('[Motrix] split argv extra:', extra)
if (extra['--opened-at-login'] === '1') {
this.openedAtLogin = true
}
@@ -178,6 +183,7 @@ export default class Launcher extends EventEmitter {
app.on('will-quit', () => {
logger.info('[Motrix] will-quit')
if (global.application) {
logger.info('[Motrix] will-quit.application.stop')
global.application.stop()
}
})
+21 -4
View File
@@ -1,5 +1,22 @@
export default {
'darwin': 'aria2c',
'win32': 'aria2c.exe',
'linux': 'aria2c'
export const engineBinMap = {
darwin: 'aria2c',
win32: 'aria2c.exe',
linux: 'aria2c'
}
export const engineArchMap = {
darwin: {
x64: 'x64',
arm64: 'arm64'
},
win32: {
ia32: 'ia32',
x64: 'x64',
arm64: 'x64'
},
linux: {
x64: 'x64',
arm: 'armv7l',
arm64: 'arm64'
}
}
+4 -4
View File
@@ -6,12 +6,12 @@ export default {
title: 'Motrix',
width: 1024,
height: 768,
minWidth: 840,
minWidth: 478,
minHeight: 420,
// backgroundColor: '#FFFFFF',
transparent: !is.windows()
transparent: is.macOS()
},
bindCloseToHide: true,
url: is.dev() ? `http://localhost:9080` : `file://${__dirname}/index.html`
openDevTools: is.dev(),
url: is.dev() ? 'http://localhost:9080' : require('path').join('file://', __dirname, '/index.html')
}
}
+2
View File
@@ -1,9 +1,11 @@
/* eslint quote-props: ["error", "always"] */
export default {
'task-list': 'application:task-list',
'new-task': 'application:new-task',
'new-bt-task': 'application:new-bt-task',
'pause-all-task': 'application:pause-all-task',
'resume-all-task': 'application:resume-all-task',
'reveal-in-folder': 'application:reveal-in-folder',
'preferences': 'application:preferences',
'about': 'application:about'
}
-42
View File
@@ -1,42 +0,0 @@
export default [
'udp://62.138.0.158:6969/announce',
'udp://93.158.213.92:1337/announce',
'udp://185.225.17.100:1337/announce',
'udp://151.80.120.112:2710/announce',
'udp://151.80.120.114:2710/announce',
'udp://185.19.107.254:80/announce',
'udp://208.83.20.20:6969/announce',
'udp://5.206.27.172:6969/announce',
'udp://176.31.241.153:80/announce',
'udp://37.235.174.46:2710/announce',
'udp://95.211.168.204:2710/announce',
'udp://159.100.245.181:6969/announce',
'http://51.68.122.172:80/announce',
'udp://89.234.156.205:451/announce',
'udp://184.105.151.164:6969/announce',
'udp://51.15.40.114:80/announce',
'http://82.209.230.66:80/announce',
'udp://185.83.215.123:6969/announce',
'udp://195.154.52.99:80/announce',
'http://51.38.230.101:80/announce',
'udp://tracker.coppersurfer.tk:6969/announce',
'udp://tracker.opentrackr.org:1337/announce',
'udp://tracker.internetwarriors.net:1337/announce',
'udp://9.rarbg.to:2710/announce',
'udp://9.rarbg.me:2710/announce',
'udp://tracker.openbittorrent.com:80/announce',
'udp://exodus.desync.com:6969/announce',
'udp://tracker.tiny-vps.com:6969/announce',
'udp://thetracker.org:80/announce',
'udp://retracker.lanta-net.ru:2710/announce',
'udp://bt.xxx-tracker.com:2710/announce',
'udp://tracker.cyberia.is:6969/announce',
'http://open.acgnxtracker.com:80/announce',
'udp://tracker.torrent.eu.org:451/announce',
'udp://explodie.org:6969/announce',
'udp://ipv4.tracker.harry.lu:80/announce',
'http://retracker.mgts.by:80/announce',
'udp://tracker.uw0.xyz:6969/announce',
'udp://open.stealth.si:80/announce',
'http://t.nyaatracker.com:80/announce'
]
+6 -7
View File
@@ -1,19 +1,18 @@
import { app } from 'electron'
import { LOGIN_SETTING_OPTIONS } from '@shared/constants'
export default class AutoLaunchManager {
enable () {
return new Promise((resolve, reject) => {
const enabled = app.getLoginItemSettings().openAtLogin
const enabled = app.getLoginItemSettings(LOGIN_SETTING_OPTIONS).openAtLogin
if (enabled) {
resolve()
}
app.setLoginItemSettings({
openAtLogin: true,
// For Windows
args: [
'--opened-at-login=1'
]
...LOGIN_SETTING_OPTIONS,
openAtLogin: true
})
resolve()
})
@@ -28,7 +27,7 @@ export default class AutoLaunchManager {
isEnabled () {
return new Promise((resolve, reject) => {
const enabled = app.getLoginItemSettings().openAtLogin
const enabled = app.getLoginItemSettings(LOGIN_SETTING_OPTIONS).openAtLogin
resolve(enabled)
})
}
+93 -24
View File
@@ -1,13 +1,26 @@
import { app } from 'electron'
import is from 'electron-is'
import Store from 'electron-store'
import tracker from '../configs/tracker'
import {
getConfigBasePath,
getDhtPath,
getLogPath,
getSessionPath,
getMaxConnectionPerServer,
getUserDownloadsPath
} from '../utils/index'
import {
APP_RUN_MODE,
APP_THEME,
EMPTY_STRING,
ENGINE_RPC_PORT,
IP_VERSION,
LOGIN_SETTING_OPTIONS,
NGOSANG_TRACKERS_BEST_IP_URL_CDN,
NGOSANG_TRACKERS_BEST_URL_CDN
} from '@shared/constants'
import { CHROME_UA } from '@shared/ua'
import { separateConfig } from '@shared/utils'
import { reduceTrackerString } from '@shared/utils/tracker'
export default class ConfigManager {
constructor () {
@@ -23,43 +36,58 @@ export default class ConfigManager {
}
/**
* Some aria2 conf
* Aria2 Configuration Priority
* system.json > built-in aria2.conf
* https://aria2.github.io/manual/en/html/aria2c.html
*
* Best bt trackers
* https://github.com/ngosang/trackerslist
*/
initSystemConfig () {
this.systemConfig = new Store({
name: 'system',
cwd: getConfigBasePath(),
/* eslint-disable quote-props */
defaults: {
'all-proxy': '',
'allow-overwrite': true,
'all-proxy': EMPTY_STRING,
'allow-overwrite': false,
'auto-file-renaming': true,
'bt-tracker': tracker.join(','),
'bt-exclude-tracker': EMPTY_STRING,
'bt-force-encryption': false,
'bt-load-saved-metadata': true,
'bt-save-metadata': true,
'bt-tracker': EMPTY_STRING,
'continue': true,
'dht-file-path': getDhtPath(4),
'dht-file-path6': getDhtPath(6),
'dht-file-path': getDhtPath(IP_VERSION.V4),
'dht-file-path6': getDhtPath(IP_VERSION.V6),
'dht-listen-port': 26701,
'dir': getUserDownloadsPath(),
'enable-dht6': true,
'follow-metalink': true,
'follow-torrent': true,
'listen-port': 21301,
'max-concurrent-downloads': 5,
'max-connection-per-server': is.macOS() ? 64 : 16,
'max-connection-per-server': getMaxConnectionPerServer(),
'max-download-limit': 0,
'max-overall-download-limit': 0,
'max-overall-upload-limit': '128K',
'min-split-size': '1M',
'max-overall-upload-limit': 0,
'no-proxy': EMPTY_STRING,
'pause-metadata': false,
'pause': true,
'rpc-listen-port': 16800,
'rpc-secret': '',
'rpc-listen-port': ENGINE_RPC_PORT,
'rpc-secret': EMPTY_STRING,
'seed-ratio': 1,
'seed-time': 60,
'split': 16,
'user-agent': 'Transmission/2.94'
'split': getMaxConnectionPerServer(),
'user-agent': CHROME_UA
}
/* eslint-enable quote-props */
})
this.fixSystemConfig()
}
initUserConfig () {
this.userConfig = new Store({
name: 'user',
cwd: getConfigBasePath(),
// Schema need electron-store upgrade to 3.x.x,
// but it will cause the application build to fail.
// schema: {
@@ -68,36 +96,77 @@ export default class ConfigManager {
// enum: ['auto', 'light', 'dark']
// }
// },
/* eslint-disable quote-props */
defaults: {
'all-proxy-backup': '',
'all-proxy-backup': EMPTY_STRING,
'auto-check-update': is.macOS(),
'auto-hide-window': false,
'auto-sync-tracker': true,
'enable-upnp': true,
'engine-max-connection-per-server': getMaxConnectionPerServer(),
'favorite-directories': [],
'hide-app-menu': is.windows() || is.linux(),
'history-directories': [],
'keep-seeding': false,
'keep-window-state': false,
'last-check-update-time': 0,
'last-sync-tracker-time': 0,
'locale': app.getLocale(),
'log-path': getLogPath(),
'log-level': 'warn',
'new-task-show-downloading': true,
'no-confirm-before-delete-task': false,
'open-at-login': false,
'protocols': { 'magnet': true, 'thunder': false },
'resume-all-when-app-launched': false,
'keep-window-state': false,
'session-path': getSessionPath(),
'run-mode': APP_RUN_MODE.STANDARD,
'show-progress-bar': true,
'task-notification': true,
'theme': 'auto',
'theme': APP_THEME.AUTO,
'tracker-source': [
NGOSANG_TRACKERS_BEST_IP_URL_CDN,
NGOSANG_TRACKERS_BEST_URL_CDN
],
'tray-theme': APP_THEME.AUTO,
'tray-speedometer': is.macOS(),
'update-channel': 'latest',
'use-proxy': false,
'window-state': {}
}
/* eslint-enable quote-props */
})
this.fixUserConfig()
}
fixSystemConfig () {
// Remove aria2c unrecognized options
const { others } = separateConfig(this.systemConfig.store)
if (!others) {
return
}
Object.keys(others).forEach(key => {
this.systemConfig.delete(key)
})
// Fix spawn ENAMETOOLONG on Windows
const tracker = reduceTrackerString(this.systemConfig.get('bt-tracker'))
this.setSystemConfig('bt-tracker', tracker)
}
fixUserConfig () {
// Fix the value of open-at-login when the user delete
// the Motrix self-starting item through startup management.
const openAtLogin = app.getLoginItemSettings().openAtLogin
const openAtLogin = app.getLoginItemSettings(LOGIN_SETTING_OPTIONS).openAtLogin
if (this.getUserConfig('open-at-login') !== openAtLogin) {
this.setUserConfig('open-at-login', openAtLogin)
}
if (this.getUserConfig('tracker-source').length === 0) {
this.setUserConfig('tracker-source', [
NGOSANG_TRACKERS_BEST_IP_URL_CDN,
NGOSANG_TRACKERS_BEST_URL_CDN
])
}
}
getSystemConfig (key, defaultValue) {
+41 -1
View File
@@ -1,3 +1,43 @@
export default class Context {
import logger from './Logger'
import {
getEnginePath,
getAria2BinPath,
getAria2ConfPath,
getSessionPath
} from '../utils'
const { platform, arch } = process
export default class Context {
constructor () {
this.init()
}
getLogPath () {
const { path } = logger.transports.file.getFile()
return path
}
init () {
// The key of Context cannot be the same as that of userConfig and systemConfig.
this.context = {
platform: platform,
arch: arch,
'log-path': this.getLogPath(),
'session-path': getSessionPath(),
'engine-path': getEnginePath(platform, arch),
'aria2-bin-path': getAria2BinPath(platform, arch),
'aria2-conf-path': getAria2ConfPath(platform, arch)
}
logger.info('[Motrix] Context.init===>', this.context)
}
get (key) {
if (typeof key === 'undefined') {
return this.context
}
return this.context[key]
}
}
+9 -5
View File
@@ -1,23 +1,27 @@
import { powerSaveBlocker } from 'electron'
let psbId = null
import logger from './Logger'
let psbId
export default class EnergyManager {
startPowerSaveBlocker () {
logger.info('[Motrix] EnergyManager.startPowerSaveBlocker', psbId)
if (psbId && powerSaveBlocker.isStarted(psbId)) {
return
}
psbId = powerSaveBlocker.start('prevent-app-suspension')
console.log('startPowerSaveBlocker===>', psbId)
logger.info('[Motrix] start power save blocker:', psbId)
}
stopPowerSaveBlocker () {
if (!psbId || !powerSaveBlocker.isStarted(psbId)) {
logger.info('[Motrix] EnergyManager.stopPowerSaveBlocker', psbId)
if (typeof psbId === 'undefined' || !powerSaveBlocker.isStarted(psbId)) {
return
}
powerSaveBlocker.stop(psbId)
console.log('stopPowerSaveBlocker===>', psbId)
psbId = null
logger.info('[Motrix] stop power save blocker:', psbId)
psbId = undefined
}
}
+86 -89
View File
@@ -1,19 +1,21 @@
'use strict'
import { app } from 'electron'
import { spawn } from 'node:child_process'
import { existsSync, writeFile, unlink } from 'node:fs'
import is from 'electron-is'
import { existsSync } from 'fs'
import { resolve, join } from 'path'
import forever from 'forever-monitor'
import logger from './Logger'
import { getI18n } from '@/ui/Locale'
import { getI18n } from '../ui/Locale'
import {
getEngineBin,
getEnginePidPath,
getAria2BinPath,
getAria2ConfPath,
getSessionPath,
transformConfig
} from '../utils/index'
const { platform, arch } = process
export default class Engine {
// ChildProcess | null
static instance = null
constructor (options = {}) {
@@ -24,82 +26,99 @@ export default class Engine {
this.userConfig = options.userConfig
}
getStartSh () {
const { platform } = process
let basePath = resolve(app.getAppPath(), '..')
start () {
const pidPath = getEnginePidPath()
logger.info('[Motrix] Engie pid path:', pidPath)
if (this.instance) {
return
}
const binPath = this.getEngineBinPath()
const args = this.getStartArgs()
this.instance = spawn(binPath, args, {
windowsHide: false,
stdio: is.dev() ? 'pipe' : 'ignore'
})
const pid = this.instance.pid.toString()
this.writePidFile(pidPath, pid)
this.instance.once('close', () => {
try {
unlink(pidPath, (err) => {
if (err) {
logger.warn(`[Motrix] Unlink engine process pid file failed: ${err}`)
}
})
} catch (err) {
logger.warn(`[Motrix] Unlink engine process pid file failed: ${err}`)
}
})
if (is.dev()) {
basePath = resolve(__dirname, `../../../extra/${platform}`)
}
this.instance.stdout.on('data', (data) => {
logger.log('[Motrix] engine stdout===>', data.toString())
})
const binName = getEngineBin(platform)
if (!binName) {
throw new Error(this.i18n.t('app.engine-damaged-message'))
this.instance.stderr.on('data', (data) => {
logger.log('[Motrix] engine stderr===>', data.toString())
})
}
}
let binPath = join(basePath, `/engine/${binName}`)
const binIsExist = existsSync(binPath)
stop () {
logger.info('[Motrix] engine.stop.instance')
if (this.instance) {
this.instance.kill()
this.instance = null
}
}
writePidFile (pidPath, pid) {
writeFile(pidPath, pid, (err) => {
if (err) {
logger.error(`[Motrix] Write engine process pid failed: ${err}`)
}
})
}
getEngineBinPath () {
const result = getAria2BinPath(platform, arch)
const binIsExist = existsSync(result)
if (!binIsExist) {
logger.error('[Motrix] engine bin is not exist===>', binPath)
logger.error('[Motrix] engine bin is not exist:', result)
throw new Error(this.i18n.t('app.engine-missing-message'))
}
let confPath = join(basePath, '/engine/aria2.conf')
let sessionPath = this.userConfig['session-path'] || getSessionPath()
const sessionIsExist = existsSync(sessionPath)
let result = [`${binPath}`, `--conf-path=${confPath}`, `--save-session=${sessionPath}`]
if (sessionIsExist) {
result = [...result, `--input-file=${sessionPath}`]
}
const extraConfig = transformConfig(this.systemConfig)
result = [...result, ...extraConfig]
return result
}
start () {
const sh = this.getStartSh()
logger.info('[Motrix] Engine start sh===>', sh)
this.instance = forever.start(sh, {
max: 100,
parser: function (command, args) {
return {
command: command,
args: args
}
},
silent: !is.dev()
})
getStartArgs () {
const confPath = getAria2ConfPath(platform, arch)
const { child } = this.instance
logger.info('[Motrix] Engine pid===>', child.pid)
const sessionPath = getSessionPath()
const sessionIsExist = existsSync(sessionPath)
this.instance.on('error', (err) => {
logger.info(`[Motrix] Engine error===> ${err}`)
})
let result = [`--conf-path=${confPath}`, `--save-session=${sessionPath}`]
if (sessionIsExist) {
result = [...result, `--input-file=${sessionPath}`]
}
this.instance.on('start', function (process, data) {
logger.info(`[Motrix] Engine started===>`)
})
const extraConfig = {
...this.systemConfig
}
const keepSeeding = this.userConfig['keep-seeding']
const seedRatio = this.systemConfig['seed-ratio']
if (keepSeeding || seedRatio === 0) {
extraConfig['seed-ratio'] = 0
delete extraConfig['seed-time']
}
console.log('extraConfig===>', extraConfig)
this.instance.on('stop', function (process) {
logger.info(`[Motrix] Engine stopped===>`)
})
const extra = transformConfig(extraConfig)
result = [...result, ...extra]
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}`)
// })
return result
}
isRunning (pid) {
@@ -110,28 +129,6 @@ export default class Engine {
}
}
stop () {
const { pid } = this.instance.child
try {
logger.info('[Motrix] Engine stopping===>')
this.instance.stop()
} catch (err) {
logger.error('[Motrix] Engine stop fail===>', err.message)
this.forceStop(pid)
} finally {
}
}
forceStop (pid) {
try {
if (pid && this.isRunning(pid)) {
process.kill(pid)
}
} catch (err) {
logger.warn('[Motrix] Engine forceStop fail===>', err)
}
}
restart () {
this.stop()
this.start()
+70
View File
@@ -0,0 +1,70 @@
'use strict'
import { Aria2 } from '@shared/aria2'
import logger from './Logger'
import {
compactUndefined,
formatOptionsForEngine
} from '@shared/utils'
import {
ENGINE_RPC_HOST,
ENGINE_RPC_PORT,
EMPTY_STRING
} from '@shared/constants'
const defaults = {
host: ENGINE_RPC_HOST,
port: ENGINE_RPC_PORT,
secret: EMPTY_STRING
}
export default class EngineClient {
static instance = null
static client = null
constructor (options = {}) {
this.options = {
...defaults,
...options
}
this.init()
}
init () {
this.connect()
}
connect () {
logger.info('[Motrix] main engine client connect', this.options)
const { host, port, secret } = this.options
this.client = new Aria2({
host,
port,
secret
})
}
async call (method, ...args) {
return this.client.call(method, ...args).catch((err) => {
logger.warn('[Motrix] call client fail:', err.message)
})
}
async changeGlobalOption (options) {
logger.info('[Motrix] change engine global option:', options)
const args = formatOptionsForEngine(options)
return this.call('changeGlobalOption', args)
}
async shutdown (options = {}) {
const { force = false } = options
const { secret } = this.options
const method = force ? 'forceShutdown' : 'shutdown'
const args = compactUndefined([secret])
return this.call(method, ...args)
}
}
+1
View File
@@ -1,5 +1,6 @@
import { app, dialog } from 'electron'
import is from 'electron-is'
import logger from './Logger'
const defaults = {
+11 -2
View File
@@ -1,8 +1,17 @@
import { join } from 'node:path'
import is from 'electron-is'
import logger from 'electron-log'
logger.transports.file.level = is.production() ? 'warn' : 'silly'
logger.info('Logger init')
import { IS_PORTABLE, PORTABLE_EXECUTABLE_DIR } from '@shared/constants'
const level = is.production() ? 'info' : 'silly'
logger.transports.file.level = level
if (IS_PORTABLE) {
logger.transports.file.resolvePath = () => join(PORTABLE_EXECUTABLE_DIR, 'main.log')
}
logger.info('[Motrix] Logger init')
logger.warn('[Motrix] Logger init')
export default logger
+28 -23
View File
@@ -1,8 +1,11 @@
import { EventEmitter } from 'events'
import { EventEmitter } from 'node:events'
import { app } from 'electron'
import is from 'electron-is'
import { parse } from 'querystring'
import logger from './Logger'
import protocolMap from '../configs/protocol'
import { ADD_TASK_TYPE } from '@shared/constants'
export default class ProtocolManager extends EventEmitter {
constructor (options = {}) {
@@ -25,7 +28,11 @@ export default class ProtocolManager extends EventEmitter {
this.setup(protocols)
}
setup (protocols) {
setup (protocols = {}) {
if (is.dev() || is.mas()) {
return
}
Object.keys(protocols).forEach((protocol) => {
const enabled = protocols[protocol]
if (enabled) {
@@ -41,7 +48,15 @@ export default class ProtocolManager extends EventEmitter {
handle (url) {
logger.info(`[Motrix] protocol url: ${url}`)
this.handleMagnetAndThunderProtocol(url)
if (
url.toLowerCase().startsWith('ftp:') ||
url.toLowerCase().startsWith('http:') ||
url.toLowerCase().startsWith('https:') ||
url.toLowerCase().startsWith('magnet:') ||
url.toLowerCase().startsWith('thunder:')
) {
return this.handleResourceProtocol(url)
}
if (
url.toLowerCase().startsWith('mo:') ||
@@ -51,28 +66,20 @@ export default class ProtocolManager extends EventEmitter {
}
}
handleMagnetAndThunderProtocol (url) {
handleResourceProtocol (url) {
if (!url) {
return
}
let protocolTag = ''
if (url.toLowerCase().startsWith('magnet:')) {
protocolTag = 'handleMagnetProtocol'
}
if (url.toLowerCase().startsWith('thunder:')) {
protocolTag = 'handleThunderProtocol'
}
logger.error(`[Motrix] ${protocolTag} url: ${url}`)
global.application.sendCommandToAll('application:new-task', 'uri', url)
global.application.sendCommandToAll('application:new-task', {
type: ADD_TASK_TYPE.URI,
uri: url
})
}
handleMoProtocol (url) {
const parsed = new URL(url)
const { host } = parsed
const { host, search } = parsed
logger.info('[Motrix] protocol parsed:', parsed, host)
const command = protocolMap[host]
@@ -80,10 +87,8 @@ export default class ProtocolManager extends EventEmitter {
return
}
// @TODO 没想明白怎么传参数好
// 如果按顺序传递,那 url 的 query string 就要求有序的了
// const query = queryString.parse(parsed.query)
const args = []
global.application.sendCommandToAll(command, ...args)
const query = search.startsWith('?') ? search.replace('?', '') : search
const args = parse(query)
global.application.sendCommandToAll(command, args)
}
}
+99
View File
@@ -0,0 +1,99 @@
import NatAPI from '@motrix/nat-api'
import logger from './Logger'
let client = null
const mappingStatus = {}
export default class UPnPManager {
constructor (options = {}) {
this.options = {
...options
}
}
init () {
if (client) {
return
}
client = new NatAPI({
autoUpdate: true
})
}
map (port) {
this.init()
return new Promise((resolve, reject) => {
logger.info('[Motrix] UPnPManager port mapping: ', port)
if (!port) {
reject(new Error('[Motrix] port was not specified'))
return
}
try {
client.map(port, (err) => {
if (err) {
logger.warn(`[Motrix] UPnPManager map ${port} failed, error: `, err.message)
reject(err.message)
return
}
mappingStatus[port] = true
logger.info(`[Motrix] UPnPManager port ${port} mapping succeeded`)
resolve()
})
} catch (err) {
reject(err.message)
}
})
}
unmap (port) {
this.init()
return new Promise((resolve, reject) => {
logger.info('[Motrix] UPnPManager port unmapping: ', port)
if (!port) {
reject(new Error('[Motrix] port was not specified'))
return
}
if (!mappingStatus[port]) {
resolve()
return
}
try {
client.unmap(port, (err) => {
if (err) {
logger.warn(`[Motrix] UPnPManager unmap ${port} failed, error: `, err)
reject(err.message)
return
}
logger.info(`[Motrix] UPnPManager port ${port} unmapping succeeded`)
mappingStatus[port] = false
resolve()
})
} catch (err) {
reject(err.message)
}
})
}
closeClient () {
if (!client) {
return
}
try {
client.destroy(() => {
client = null
})
} catch (err) {
logger.warn('[Motrix] close UPnP client fail', err)
}
}
}
+25 -13
View File
@@ -1,10 +1,11 @@
import { EventEmitter } from 'events'
import { EventEmitter } from 'node:events'
import { resolve } from 'node:path'
import { dialog } from 'electron'
import is from 'electron-is'
import { autoUpdater } from 'electron-updater'
import { resolve } from 'path'
import logger from './Logger'
import { getI18n } from '@/ui/Locale'
import { getI18n } from '../ui/Locale'
if (is.dev()) {
autoUpdater.updateConfigPath = resolve(__dirname, '../../../app-update.yml')
@@ -16,8 +17,10 @@ export default class UpdateManager extends EventEmitter {
this.options = options
this.i18n = getI18n()
this.isChecking = false
this.updater = autoUpdater
this.updater.autoDownload = false
this.updater.autoInstallOnAppQuit = false
this.updater.logger = logger
this.autoCheckData = {
checkEnable: this.options.autoCheck,
@@ -39,22 +42,22 @@ export default class UpdateManager extends EventEmitter {
this.updater.on('update-not-available', this.updateNotAvailable.bind(this))
this.updater.on('download-progress', this.updateDownloadProgress.bind(this))
this.updater.on('update-downloaded', this.updateDownloaded.bind(this))
this.updater.on('update-cancelled', this.updateCancelled.bind(this))
this.updater.on('error', this.updateError.bind(this))
if (this.autoCheckData.checkEnable) {
if (this.autoCheckData.checkEnable && !this.isChecking) {
this.autoCheckData.userCheck = false
this.options.setCheckTime.setUserConfig('last-check-update-time', Date.now())
this.updater.checkForUpdates()
}
}
check () {
this.options.setCheckTime.setUserConfig('last-check-update-time', Date.now())
this.autoCheckData.userCheck = true
this.updater.checkForUpdates()
}
checkingForUpdate () {
this.isChecking = true
this.emit('checking')
}
@@ -66,14 +69,17 @@ export default class UpdateManager extends EventEmitter {
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) {
}).then(({ response }) => {
if (response === 0) {
this.updater.downloadUpdate()
} else {
this.emit('update-cancelled', info)
}
})
}
updateNotAvailable (event, info) {
this.isChecking = false
this.emit('update-not-available', info)
if (this.autoCheckData.userCheck) {
dialog.showMessageBox({
@@ -102,21 +108,27 @@ export default class UpdateManager extends EventEmitter {
dialog.showMessageBox({
title: this.i18n.t('app.check-for-updates-title'),
message: this.i18n.t('app.update-downloaded-message')
}, () => {
}).then(_ => {
this.isChecking = false
this.emit('will-updated')
setImmediate(() => {
setTimeout(() => {
this.updater.quitAndInstall()
})
}, 200)
})
}
updateCancelled () {
this.isChecking = false
}
updateError (event, error) {
this.isChecking = false
this.emit('update-error', error)
const msg = (error == null)
? this.i18n.t('update-error-message')
? this.i18n.t('app.update-error-message')
: (error.stack || error).toString()
this.updater.logger.warn(`[Motrix] update-error: ${msg}`)
dialog.showErrorBox(msg)
dialog.showErrorBox('Error', msg)
}
}
+1 -7
View File
@@ -7,14 +7,8 @@
/* eslint-disable */
// Install `electron-debug` with `devtron`
require('electron-debug')({
// devToolsMode: 'right',
showDevTools: true
})
// Install `vue-devtools`
require('electron').app.on('ready', () => {
require('electron').app.whenReady().then(() => {
let installExtension = require('electron-devtools-installer')
installExtension.default(installExtension.VUEJS_DEVTOOLS)
.then(() => {})
+8
View File
@@ -1,8 +1,16 @@
import { app } from 'electron'
import is from 'electron-is'
import { initialize } from '@electron/remote/main'
import Launcher from './Launcher'
/**
* initialize the main-process side of the remote module
*/
initialize()
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true'
if (process.env.NODE_ENV !== 'development') {
global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
}
+6 -4
View File
@@ -3,7 +3,7 @@
{
"id": "menu.app",
"submenu": [
{ "id": "app.about", "command": "application:about", "command-before": "application:show,index" },
{ "id": "app.about", "command": "application:about", "command-before": "application:show?page=index" },
{ "type": "separator" },
{ "id": "app.preferences", "command": "application:preferences" },
{ "id": "app.check-for-updates", "command": "application:check-for-updates" },
@@ -17,10 +17,11 @@
{
"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" },
{ "id": "task.new-task", "command": "application:new-task", "command-after": "application:show?page=index" },
{ "id": "task.new-bt-task", "command": "application:new-bt-task", "command-after": "application:show?page=index" },
{ "id": "task.open-file", "command": "application:open-file", "command-before": "application:show?page=index" },
{ "type": "separator" },
{ "id": "app.task-list", "command": "application:task-list" },
{ "id": "task.pause-task", "command": "application:pause-task" },
{ "id": "task.resume-task", "command": "application:resume-task" },
{ "id": "task.delete-task", "command": "application:delete-task" },
@@ -29,6 +30,7 @@
{ "type": "separator" },
{ "id": "task.pause-all-task", "command": "application:pause-all-task" },
{ "id": "task.resume-all-task", "command": "application:resume-all-task" },
{ "id": "task.select-all-task", "command": "application:select-all-task" },
{ "type": "separator" },
{ "id": "task.clear-recent-tasks", "command": "application:clear-recent-tasks" }
]
+8 -6
View File
@@ -3,11 +3,11 @@
{
"id": "menu.file",
"submenu": [
{ "id": "app.about", "command": "application:about", "command-before": "application:show,index" },
{ "id": "app.about", "command": "application:about", "command-before": "application:show?page=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" },
{ "id": "app.show", "command": "application:show", "command-arg": { "page": "index" } },
{ "type": "separator" },
{ "id": "app.quit", "role": "quit" }
]
@@ -15,10 +15,11 @@
{
"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" },
{ "id": "task.new-task", "command": "application:new-task", "command-after": "application:show?page=index" },
{ "id": "task.new-bt-task", "command": "application:new-bt-task", "command-after": "application:show?page=index" },
{ "id": "task.open-file", "command": "application:open-file", "command-before": "application:show?page=index" },
{ "type": "separator" },
{ "id": "app.task-list", "command": "application:task-list" },
{ "id": "task.pause-task", "command": "application:pause-task" },
{ "id": "task.resume-task", "command": "application:resume-task" },
{ "id": "task.delete-task", "command": "application:delete-task" },
@@ -26,7 +27,8 @@
{ "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": "task.resume-all-task", "command": "application:resume-all-task" },
{ "id": "task.select-all-task", "command": "application:select-all-task" }
]
},
{
+5 -5
View File
@@ -1,6 +1,6 @@
[
{
"type": "button", "icon": "new-task", "id": "task.new-task", "command": "application:new-task", "command-arg": "uri", "command-after": "application:show,index"
"type": "button", "icon": "new-task", "id": "task.new-task", "command": "application:new-task", "command-after": "application:show?page=index"
},
{
"type": "spacer", "size": "small"
@@ -10,13 +10,13 @@
"id": "task.task-list",
"items": [
{
"type": "button", "icon": "task-active", "command": "application:task-list", "command-arg": "active"
"type": "button", "icon": "task-active", "command": "application:task-list", "command-arg": { "status": "active" }
},
{
"type": "button", "icon": "task-waiting", "command": "application:task-list", "command-arg": "waiting"
"type": "button", "icon": "task-waiting", "command": "application:task-list", "command-arg": { "status": "waiting" }
},
{
"type": "button", "icon": "task-stopped", "command": "application:task-list", "command-arg": "stopped"
"type": "button", "icon": "task-stopped", "command": "application:task-list", "command-arg": { "status": "stopped" }
}
]
},
@@ -30,6 +30,6 @@
"type": "spacer", "size": "small"
},
{
"type": "button", "icon": "about", "id": "app.about", "command": "application:about", "command-before": "application:show,index"
"type": "button", "icon": "about", "id": "app.about", "command": "application:about", "command-before": "application:show?page=index"
}
]
+7 -6
View File
@@ -1,12 +1,13 @@
[
{ "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" },
{ "id": "task.new-task", "command": "application:new-task", "command-after": "application:show?page=index" },
{ "id": "task.new-bt-task", "command": "application:new-bt-task", "command-arg": { "type": "torrent" }, "command-after": "application:show?page=index" },
{ "id": "task.open-file", "command": "application:open-file", "command-before": "application:show?page=index" },
{ "type": "separator" },
{ "id": "app.show", "command": "application:show", "command-arg": "index" },
{ "id": "app.show", "command": "application:show", "command-arg": { "page": "index" } },
{ "id": "help.manual", "command": "help:manual" },
{ "id": "app.check-for-updates", "command": "application:check-for-updates" },
{ "type": "separator" },
{ "id": "app.preferences", "command": "application:preferences", "command-before": "application:show,index" },
{ "id": "app.quit", "role": "quit" }
{ "id": "app.task-list", "command": "application:task-list", "command-before": "application:show?page=index" },
{ "id": "app.preferences", "command": "application:preferences", "command-before": "application:show?page=index" },
{ "id": "app.quit", "command": "application:quit" }
]
+7 -5
View File
@@ -3,11 +3,11 @@
{
"id": "menu.file",
"submenu": [
{ "id": "app.about", "command": "application:about", "command-before": "application:show,index" },
{ "id": "app.about", "command": "application:about", "command-before": "application:show?page=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" },
{ "id": "app.show", "command": "application:show", "command-arg": { "page": "index" } },
{ "type": "separator" },
{ "id": "app.quit", "role": "quit" }
]
@@ -15,10 +15,11 @@
{
"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" },
{ "id": "task.new-task", "command": "application:new-task", "command-after": "application:show?page=index" },
{ "id": "task.new-bt-task", "command": "application:new-bt-task", "command-after": "application:show?page=index" },
{ "id": "task.open-file", "command": "application:open-file", "command-before": "application:show?page=index" },
{ "type": "separator" },
{ "id": "app.task-list", "command": "application:task-list" },
{ "id": "task.pause-task", "command": "application:pause-task" },
{ "id": "task.resume-task", "command": "application:resume-task" },
{ "id": "task.delete-task", "command": "application:delete-task" },
@@ -27,6 +28,7 @@
{ "type": "separator" },
{ "id": "task.pause-all-task", "command": "application:pause-all-task" },
{ "id": "task.resume-all-task", "command": "application:resume-all-task" },
{ "id": "task.select-all-task", "command": "application:select-all-task" },
{ "type": "separator" },
{ "id": "task.clear-recent-tasks", "command": "application:clear-recent-tasks" }
]
+64
View File
@@ -0,0 +1,64 @@
import is from 'electron-is'
import { EventEmitter } from 'node:events'
import { app } from 'electron'
import { bytesToSize } from '@shared/utils'
import {
APP_RUN_MODE
} from '@shared/constants'
const enabled = is.macOS()
export default class DockManager extends EventEmitter {
constructor (options) {
super()
this.options = options
const { runMode } = this.options
if (runMode === APP_RUN_MODE.TRAY) {
this.hide()
}
}
show = enabled
? () => {
if (app.dock.isVisible()) {
return
}
return app.dock.show()
}
: () => {}
hide = enabled
? () => {
if (!app.dock.isVisible()) {
return
}
app.dock.hide()
}
: () => {}
// macOS setBadge not working
// @see https://github.com/electron/electron/issues/25745#issuecomment-702826143
setBadge = enabled
? (text) => {
app.dock.setBadge(text)
}
: (text) => {}
handleSpeedChange = enabled
? (speed) => {
const { downloadSpeed } = speed
const text = downloadSpeed > 0 ? `${bytesToSize(downloadSpeed)}/s` : ''
this.setBadge(text)
}
: (text) => {}
openDock = enabled
? (path) => {
app.dock.downloadFinished(path)
}
: (path) => {}
}
+4 -4
View File
@@ -5,20 +5,20 @@ const localeManager = new LocaleManager({
resources
})
export function getLocaleManager () {
export const getLocaleManager = () => {
return localeManager
}
export function setupLocaleManager (locale) {
export const setupLocaleManager = (locale) => {
localeManager.changeLanguageByLocale(locale)
return localeManager
}
export function getI18n () {
export const getI18n = () => {
return localeManager.getI18n()
}
export function getI18nTranslator () {
export const getI18nTranslator = () => {
return localeManager.getI18n().t
}
+8 -7
View File
@@ -1,12 +1,13 @@
import { EventEmitter } from 'events'
import { EventEmitter } from 'node:events'
import { Menu } from 'electron'
import keymap from '@shared/keymap'
import {
translateTemplate,
flattenMenuItems,
updateStates
} from '../utils/menu'
import keymap from '@shared/keymap'
import { getI18n } from '@/ui/Locale'
import { getI18n } from '../ui/Locale'
export default class MenuManager extends EventEmitter {
constructor (options) {
@@ -23,13 +24,13 @@ export default class MenuManager extends EventEmitter {
}
load () {
let template = require(`../menus/${process.platform}.json`)
this.template = template['menu']
const template = require(`../menus/${process.platform}.json`)
this.template = template.menu
}
build () {
const keystrokesByCommand = {}
for (let item in this.keymap) {
for (const item in this.keymap) {
keystrokesByCommand[this.keymap[item]] = item
}
@@ -46,7 +47,7 @@ export default class MenuManager extends EventEmitter {
this.items = flattenMenuItems(menu)
}
rebuild () {
handleLocaleChange (locale) {
this.setup()
}
+19 -26
View File
@@ -1,46 +1,39 @@
import { EventEmitter } from 'events'
import { systemPreferences } from 'electron'
import is from 'electron-is'
import { LIGHT_THEME, DARK_THEME } from '@shared/constants'
import { EventEmitter } from 'node:events'
import { nativeTheme } from 'electron'
import { APP_THEME } from '@shared/constants'
import logger from '../core/Logger'
import { getSystemTheme } from '../utils'
export default class ThemeManager extends EventEmitter {
constructor (options = {}) {
super()
this.options = options
this.init()
}
init () {
this.systemTheme = getSystemTheme()
this.handleEvents()
}
getSystemTheme () {
let result = LIGHT_THEME
if (!is.macOS()) {
return result
}
result = systemPreferences.isDarkMode() ? DARK_THEME : LIGHT_THEME
return result
return this.systemTheme
}
handleEvents () {
if (!is.macOS()) {
return
}
systemPreferences.subscribeNotification(
'AppleInterfaceThemeChangedNotification',
() => {
const theme = this.getSystemTheme()
this.updateAppAppearance(theme)
this.emit('system-theme-changed', theme)
}
)
nativeTheme.on('updated', () => {
const theme = getSystemTheme()
this.systemTheme = theme
logger.info('[Motrix] nativeTheme updated===>', theme)
this.emit('system-theme-change', theme)
})
}
updateAppAppearance (theme) {
if (!is.macOS() || theme !== LIGHT_THEME || theme !== DARK_THEME) {
return
}
systemPreferences.setAppLevelAppearance(theme)
updateSystemTheme (theme) {
theme = theme === APP_THEME.AUTO ? 'system' : theme
nativeTheme.themeSource = theme
}
}
+30 -27
View File
@@ -1,6 +1,7 @@
import { EventEmitter } from 'events'
import { join } from 'path'
import { EventEmitter } from 'node:events'
import { join } from 'node:path'
import { TouchBar, nativeImage } from 'electron'
import { handleCommand } from '../utils/menu'
import logger from '../core/Logger'
@@ -15,7 +16,7 @@ export default class TouchBarManager extends EventEmitter {
}
load () {
this.template = require(`../menus/touchBar.json`)
this.template = require('../menus/touchBar.json')
}
getClickFn (item) {
@@ -41,30 +42,32 @@ export default class TouchBarManager extends EventEmitter {
const { label, backgroundColor, textColor, size } = options
switch (type) {
case 'button':
const icon = this.getIconImage(options.icon)
const click = this.getClickFn(options)
result = new TouchBarButton({
label,
backgroundColor,
icon,
click
case 'button':
result = new TouchBarButton({
label,
backgroundColor,
icon: this.getIconImage(options.icon),
click: this.getClickFn(options)
})
break
case 'label':
result = new TouchBarLabel({
label,
textColor
})
break
case 'spacer':
result = new TouchBarSpacer({ size })
break
case 'group':
result = new TouchBarGroup({
items: new TouchBar({
items: options.items
})
break
case 'label':
result = new TouchBarLabel({
label,
textColor
})
break
case 'spacer':
result = new TouchBarSpacer({ size })
break
case 'group':
result = new TouchBarGroup({ items: options.items })
break
default:
result = null
})
break
default:
result = null
}
return result
@@ -90,7 +93,7 @@ export default class TouchBarManager extends EventEmitter {
if (!bar) {
try {
const items = this.build(this.template)
bar = new TouchBar(items)
bar = new TouchBar({ items })
this.bars[page] = bar
} catch (e) {
logger.info('getTouchBarByPage fail', e)
+280 -53
View File
@@ -1,47 +1,133 @@
import { EventEmitter } from 'events'
import { join } from 'path'
import { Tray, Menu, systemPreferences } from 'electron'
import { EventEmitter } from 'node:events'
import { join } from 'node:path'
import { Tray, Menu, nativeImage } from 'electron'
import is from 'electron-is'
import { APP_RUN_MODE, APP_THEME } from '@shared/constants'
import { getInverseTheme } from '@shared/utils'
import logger from '../core/Logger'
import { getI18n } from './Locale'
import {
translateTemplate,
flattenMenuItems,
updateStates
} from '../utils/menu'
import { getI18n } from '@/ui/Locale'
import { LIGHT_THEME, DARK_THEME } from '@shared/constants'
import { convertArrayBufferToBuffer } from '../utils/index'
let tray = null
const { platform } = process
export default class TrayManager extends EventEmitter {
constructor (options = {}) {
super()
this.options = options
this.theme = options.theme || APP_THEME.AUTO
this.systemTheme = options.systemTheme
this.inverseSystemTheme = getInverseTheme(this.systemTheme)
this.macOS = platform === 'darwin'
this.speedometer = options.speedometer
this.runMode = options.runMode
this.i18n = getI18n()
this.menu = null
this.cache = {}
this.uploadSpeed = 0
this.downloadSpeed = 0
this.status = false
this.focused = false
this.initialized = false
this.load()
this.init()
this.setup()
this.handleEvents()
}
load () {
this.template = require(`../menus/tray.json`)
const theme = systemPreferences.isDarkMode() ? DARK_THEME : LIGHT_THEME
init () {
if (tray || this.initialized || this.runMode === APP_RUN_MODE.HIDE_TRAY) {
return
}
if (is.macOS()) {
this.normalIcon = join(__static, `./mo-tray-${theme}-normal.png`)
this.activeIcon = join(__static, `./mo-tray-${theme}-active.png`)
} else {
this.normalIcon = join(__static, './mo-tray-colorful-normal.png')
this.activeIcon = join(__static, './mo-tray-colorful-active.png')
this.loadTemplate()
this.loadImages()
this.initTray()
this.setupMenu()
this.bindEvents()
this.initialized = true
}
loadTemplate () {
this.template = require('../menus/tray.json')
}
loadImages () {
switch (platform) {
case 'darwin':
this.loadImagesForMacOS()
break
case 'win32':
this.loadImagesForWindows()
break
case 'linux':
this.loadImagesForLinux()
break
default:
this.loadImagesForDefault()
break
}
}
build () {
loadImagesForMacOS () {
this.normalIcon = this.getFromCacheOrCreateImage('mo-tray-light-normal.png')
}
loadImagesForWindows () {
this.normalIcon = this.getFromCacheOrCreateImage('mo-tray-colorful-normal.png')
this.activeIcon = this.getFromCacheOrCreateImage('mo-tray-colorful-active.png')
}
loadImagesForLinux () {
const { theme } = this
if (theme === APP_THEME.AUTO) {
this.normalIcon = this.getFromCacheOrCreateImage('mo-tray-dark-normal.png')
this.activeIcon = this.getFromCacheOrCreateImage('mo-tray-dark-active.png')
} else {
this.normalIcon = this.getFromCacheOrCreateImage(`mo-tray-${theme}-normal.png`)
this.activeIcon = this.getFromCacheOrCreateImage(`mo-tray-${theme}-active.png`)
}
}
loadImagesForDefault () {
this.normalIcon = this.getFromCacheOrCreateImage('mo-tray-light-normal.png')
this.activeIcon = this.getFromCacheOrCreateImage('mo-tray-light-active.png')
}
getFromCacheOrCreateImage (key) {
let file = this.getCache(key)
if (file) {
return file
}
file = nativeImage.createFromPath(join(__static, `./${key}`))
file.setTemplateImage(this.macOS)
this.setCache(key, file)
return file
}
getCache (key) {
return this.cache[key]
}
setCache (key, value) {
this.cache[key] = value
}
buildMenu () {
const keystrokesByCommand = {}
for (let item in this.keymap) {
for (const item in this.keymap) {
keystrokesByCommand[this.keymap[item]] = item
}
@@ -52,74 +138,145 @@ export default class TrayManager extends EventEmitter {
this.items = flattenMenuItems(this.menu)
}
setup () {
this.build()
setupMenu () {
this.buildMenu()
/**
* Linux requires setContextMenu to be called
* in order for the context menu to populate correctly
*/
if (process.platform === 'linux') {
tray.setContextMenu(this.menu)
this.updateContextMenu()
}
initTray () {
const { icon } = this.getIcons()
tray = new Tray(icon)
// tray.setPressedImage(inverseIcon)
if (!this.macOS) {
tray.setToolTip('Motrix')
}
}
init () {
tray = new Tray(this.normalIcon)
tray.setToolTip('Motrix')
bindEvents () {
// All OS
tray.on('click', this.handleTrayClick)
// macOS, Windows
// tray.on('double-click', this.handleTrayDbClick)
tray.on('right-click', this.handleTrayRightClick)
tray.on('mouse-down', this.handleTrayMouseDown)
tray.on('mouse-up', this.handleTrayMouseUp)
// macOS only
tray.setIgnoreDoubleClickEvents(true)
tray.on('drop-files', this.handleTrayDropFiles)
tray.on('drop-text', this.handleTrayDropText)
}
handleEvents () {
tray.on('click', this.handleTrayClick)
tray.on('double-click', this.handleTrayDbClick)
tray.on('right-click', this.handleTrayRightClick)
unbindEvents () {
// All OS
tray.removeListener('click', this.handleTrayClick)
tray.on('drop-files', this.handleTrayDropFile)
// macOS, Windows
tray.removeListener('right-click', this.handleTrayRightClick)
tray.removeListener('mouse-down', this.handleTrayMouseDown)
tray.removeListener('mouse-up', this.handleTrayMouseUp)
// macOS only
tray.removeListener('drop-files', this.handleTrayDropFiles)
tray.removeListener('drop-text', this.handleTrayDropText)
}
handleTrayClick = (event) => {
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])
handleTrayMouseDown = (event) => {
this.focused = true
this.emit('mouse-down', {
focused: true,
theme: this.inverseSystemTheme
})
this.renderTray()
}
updateStatus (status) {
this.status = status
this.updateIcon()
handleTrayMouseUp = (event) => {
this.focused = false
this.emit('mouse-up', {
focused: false,
theme: this.theme
})
this.renderTray()
}
updateIcon () {
const icon = this.status ? this.activeIcon : this.normalIcon
tray.setImage(icon)
handleTrayDropFiles = (event, files) => {
this.emit('drop-files', files)
}
changeIconTheme (theme = LIGHT_THEME) {
if (!is.macOS()) {
handleTrayDropText = (event, text) => {
this.emit('drop-text', text)
}
toggleSpeedometer (enabled) {
this.speedometer = enabled
}
async renderTray () {
if (!tray || this.speedometer) {
return
}
this.normalIcon = join(__static, `./mo-tray-${theme}-normal.png`)
this.activeIcon = join(__static, `./mo-tray-${theme}-active.png`)
const { icon } = this.getIcons()
this.updateIcon()
tray.setImage(icon)
// tray.setPressedImage(inverseIcon)
this.updateContextMenu()
}
getIcons () {
if (this.macOS) {
return { icon: this.normalIcon }
}
const { focused, status, systemTheme } = this
const icon = status ? this.activeIcon : this.normalIcon
if (systemTheme === APP_THEME.DARK) {
return {
icon
}
}
const inverseIcon = status ? this.inverseActiveIcon : this.inverseNormalIcon
return {
icon: focused ? inverseIcon : icon
// inverseIcon: focused ? icon : inverseIcon
}
}
updateContextMenu () {
/**
* Linux requires setContextMenu to be called
* in order for the context menu to populate correctly
*/
if (!tray || process.platform !== 'linux') {
return
}
tray.setContextMenu(this.menu)
}
updateMenuStates (visibleStates, enabledStates, checkedStates) {
updateStates(this.items, visibleStates, enabledStates, checkedStates)
this.updateContextMenu()
}
updateMenuItemVisibleState (id, flag) {
@@ -136,7 +293,77 @@ export default class TrayManager extends EventEmitter {
this.updateMenuStates(null, enabledStates, null)
}
handleLocaleChange (locale) {
this.setupMenu()
}
handleRunModeChange (mode) {
this.runMode = mode
if (mode === APP_RUN_MODE.HIDE_TRAY) {
this.destroy()
} else {
this.init()
}
}
handleSpeedometerEnableChange (enabled) {
this.toggleSpeedometer(enabled)
this.renderTray()
}
handleSystemThemeChange (systemTheme = APP_THEME.LIGHT) {
if (!is.macOS()) {
return
}
this.systemTheme = systemTheme
this.inverseSystemTheme = getInverseTheme(systemTheme)
this.loadImages()
this.renderTray()
}
handleDownloadStatusChange (status) {
this.status = status
this.renderTray()
}
async handleSpeedChange ({ uploadSpeed, downloadSpeed }) {
if (!this.speedometer) {
return
}
this.uploadSpeed = uploadSpeed
this.downloadSpeed = downloadSpeed
await this.renderTray()
}
async updateTrayByImage (ab) {
if (!tray) {
return
}
const buffer = convertArrayBufferToBuffer(ab)
const image = nativeImage.createFromBuffer(buffer, {
scaleFactor: 2
})
image.setTemplateImage(this.macOS)
tray.setImage(image)
}
destroy () {
logger.info('[Motrix] TrayManager.destroy')
if (tray) {
this.unbindEvents()
}
tray.destroy()
tray = null
this.initialized = false
}
}
+77 -16
View File
@@ -1,21 +1,35 @@
import { join } from 'path'
import { EventEmitter } from 'events'
import { join } from 'node:path'
import { EventEmitter } from 'node:events'
import { debounce } from 'lodash'
import { app, shell, screen, BrowserWindow } from 'electron'
import is from 'electron-is'
import pageConfig from '../configs/page'
import logger from '../core/Logger'
import { debounce } from 'lodash'
const defaultBrowserOptions = {
const baseBrowserOptions = {
titleBarStyle: 'hiddenInset',
show: false,
width: 1024,
height: 768,
backgroundColor: '#fff',
webPreferences: {
nodeIntegration: true
}
}
// fix: BrowserWindow rendering bug under linux
const defaultBrowserOptions = is.macOS()
? {
...baseBrowserOptions,
vibrancy: 'ultra-dark',
visualEffectState: 'active',
backgroundColor: '#00000000'
}
: {
...baseBrowserOptions
}
export default class WindowManager extends EventEmitter {
constructor (options = {}) {
super()
@@ -71,7 +85,7 @@ export default class WindowManager extends EventEmitter {
openWindow (page, options = {}) {
const pageOptions = this.getPageOptions(page)
const { hidden } = options
const autoHideWindow = this.userConfig['auto-hide-window']
let window = this.windows[page] || null
if (window) {
window.show()
@@ -81,18 +95,27 @@ export default class WindowManager extends EventEmitter {
window = new BrowserWindow({
...defaultBrowserOptions,
...pageOptions.attrs
...pageOptions.attrs,
webPreferences: {
enableRemoteModule: true,
contextIsolation: false,
nodeIntegration: true,
nodeIntegrationInWorker: true
}
})
const bounds = this.getPageBounds(page)
console.log('bounds ====>', bounds)
if (bounds) {
window.setBounds(bounds)
}
window.webContents.on('new-window', (e, url) => {
e.preventDefault()
if (is.dev() && pageOptions.openDevTools) {
window.webContents.openDevTools()
}
window.webContents.setWindowOpenHandler(({ url }) => {
shell.openExternal(url)
return { action: 'deny' }
})
if (pageOptions.url) {
@@ -105,6 +128,14 @@ export default class WindowManager extends EventEmitter {
}
})
window.on('enter-full-screen', () => {
this.emit('enter-full-screen', window)
})
window.on('leave-full-screen', () => {
this.emit('leave-full-screen', window)
})
this.handleWindowState(page, window)
this.handleWindowClose(pageOptions, page, window)
@@ -112,6 +143,10 @@ export default class WindowManager extends EventEmitter {
this.bindAfterClosed(page, window)
this.addWindow(page, window)
if (autoHideWindow) {
this.handleWindowBlur()
}
return window
}
@@ -133,6 +168,10 @@ export default class WindowManager extends EventEmitter {
destroyWindow (page) {
const win = this.getWindow(page)
if (!win) {
return
}
this.removeWindow(page)
win.removeListener('closed')
win.removeListener('move')
@@ -166,7 +205,15 @@ export default class WindowManager extends EventEmitter {
window.on('close', (event) => {
if (pageOptions.bindCloseToHide && !this.willQuit) {
event.preventDefault()
window.hide()
// @see https://github.com/electron/electron/issues/20263
if (window.isFullScreen()) {
window.once('leave-full-screen', () => window.hide())
window.setFullScreen(false)
} else {
window.hide()
}
}
const bounds = window.getBounds()
this.emit('window-closed', { page, bounds })
@@ -175,15 +222,16 @@ export default class WindowManager extends EventEmitter {
showWindow (page) {
const window = this.getWindow(page)
if (!window) {
if (!window || (window.isVisible() && !window.isMinimized())) {
return
}
window.show()
}
hideWindow (page) {
const window = this.getWindow(page)
if (!window) {
if (!window || !window.isVisible()) {
return
}
window.hide()
@@ -200,10 +248,11 @@ export default class WindowManager extends EventEmitter {
if (!window) {
return
}
if (window.isVisible()) {
window.hide()
} else {
if (!window.isVisible() || window.isFullScreen()) {
window.show()
} else {
window.hide()
}
}
@@ -217,6 +266,18 @@ export default class WindowManager extends EventEmitter {
})
}
onWindowBlur (event, window) {
window.hide()
}
handleWindowBlur () {
app.on('browser-window-blur', this.onWindowBlur)
}
unbindWindowBlur () {
app.removeListener('browser-window-blur', this.onWindowBlur)
}
handleAllWindowClosed () {
app.on('window-all-closed', (event) => {
event.preventDefault()
@@ -227,7 +288,7 @@ export default class WindowManager extends EventEmitter {
if (!window) {
return
}
logger.info('[Motrix] sendCommandTo===>', command, ...args)
logger.info('[Motrix] send command to:', command, ...args)
window.webContents.send('command', command, ...args)
}
+122 -34
View File
@@ -1,38 +1,91 @@
import { app } from 'electron'
import { resolve } from 'node:path'
import { access, constants, existsSync, lstatSync } from 'node:fs'
import { app, nativeTheme, shell } from 'electron'
import is from 'electron-is'
import { resolve } from 'path'
import { existsSync, lstatSync } from 'fs'
import {
APP_THEME,
ENGINE_MAX_CONNECTION_PER_SERVER,
IP_VERSION,
IS_PORTABLE,
PORTABLE_EXECUTABLE_DIR
} from '@shared/constants'
import { engineBinMap, engineArchMap } from '../configs/engine'
import logger from '../core/Logger'
import engineBinMap from '../configs/engine'
export function getLogPath () {
return logger.transports.file.file
export const getUserDataPath = () => {
return IS_PORTABLE ? PORTABLE_EXECUTABLE_DIR : app.getPath('userData')
}
export function getDhtPath (protocol) {
const name = protocol === 6 ? 'dht6.dat' : 'dht.dat'
return resolve(app.getPath('userData'), `./${name}`)
export const getSystemLogPath = () => {
return app.getPath('logs')
}
export function getSessionPath () {
return resolve(app.getPath('userData'), './download.session')
}
export function getUserDataPath () {
return app.getPath('userData')
}
export function getUserDownloadsPath () {
export const getUserDownloadsPath = () => {
return app.getPath('downloads')
}
export function getEngineBin (platform) {
let result = engineBinMap.hasOwnProperty(platform) ? engineBinMap[platform] : ''
export const getConfigBasePath = () => {
const path = getUserDataPath()
return path
}
export const getSessionPath = () => {
return resolve(getUserDataPath(), './download.session')
}
export const getEnginePidPath = () => {
return resolve(getUserDataPath(), './engine.pid')
}
export const getDhtPath = (protocol) => {
const name = protocol === IP_VERSION.V6 ? 'dht6.dat' : 'dht.dat'
return resolve(getUserDataPath(), `./${name}`)
}
export const getEngineBin = (platform) => {
const result = engineBinMap[platform] || ''
return result
}
export function transformConfig (config) {
let result = []
export const getEngineArch = (platform, arch) => {
if (!['darwin', 'win32', 'linux'].includes(platform)) {
return ''
}
const result = engineArchMap[platform][arch]
return result
}
export const getDevEnginePath = (platform, arch) => {
const ah = getEngineArch(platform, arch)
const base = `../../../extra/${platform}/${ah}/engine`
const result = resolve(__dirname, base)
return result
}
export const getProdEnginePath = () => {
return resolve(app.getAppPath(), '../engine')
}
export const getEnginePath = (platform, arch) => {
return is.dev() ? getDevEnginePath(platform, arch) : getProdEnginePath()
}
export const getAria2BinPath = (platform, arch) => {
const base = getEnginePath(platform, arch)
const binName = getEngineBin(platform)
const result = resolve(base, `./${binName}`)
return result
}
export const getAria2ConfPath = (platform, arch) => {
const base = getEnginePath(platform, arch)
return resolve(base, './aria2.conf')
}
export const transformConfig = (config) => {
const result = []
for (const [k, v] of Object.entries(config)) {
if (v !== '') {
result.push(`--${k}=${v}`)
@@ -41,7 +94,7 @@ export function transformConfig (config) {
return result
}
export function isRunningInDmg () {
export const isRunningInDmg = () => {
if (!is.macOS() || is.dev()) {
return false
}
@@ -50,7 +103,7 @@ export function isRunningInDmg () {
return result
}
export function moveAppToApplicationsFolder (errorMsg = '') {
export const moveAppToApplicationsFolder = (errorMsg = '') => {
return new Promise((resolve, reject) => {
try {
const result = app.moveToApplicationsFolder()
@@ -65,7 +118,7 @@ export function moveAppToApplicationsFolder (errorMsg = '') {
})
}
export function splitArgv (argv) {
export const splitArgv = (argv) => {
const args = []
const extra = {}
for (const arg of argv) {
@@ -81,8 +134,8 @@ export function splitArgv (argv) {
return { args, extra }
}
export function parseArgvAsUrl (argv) {
let arg = argv[1]
export const parseArgvAsUrl = (argv) => {
const arg = argv[1]
if (!arg) {
return
}
@@ -92,16 +145,16 @@ export function parseArgvAsUrl (argv) {
}
}
export function checkIsSupportedSchema (url = '') {
export const checkIsSupportedSchema = (url = '') => {
const str = url.toLowerCase()
if (
str.startsWith('mo:') ||
str.startsWith('motrix:') ||
str.startsWith('ftp:') ||
str.startsWith('http:') ||
str.startsWith('https:') ||
str.startsWith('ftp:') ||
str.startsWith('magnet:') ||
str.startsWith('thunder:')
str.startsWith('thunder:') ||
str.startsWith('mo:') ||
str.startsWith('motrix:')
) {
return true
} else {
@@ -109,11 +162,11 @@ export function checkIsSupportedSchema (url = '') {
}
}
export function isDirectory (path) {
export const isDirectory = (path) => {
return existsSync(path) && lstatSync(path).isDirectory()
}
export function parseArgvAsFile (argv) {
export const parseArgvAsFile = (argv) => {
let arg = argv[1]
if (!arg || isDirectory(arg)) {
return
@@ -124,3 +177,38 @@ export function parseArgvAsFile (argv) {
}
return arg
}
export const getMaxConnectionPerServer = () => {
return ENGINE_MAX_CONNECTION_PER_SERVER
}
export const getSystemTheme = () => {
let result = APP_THEME.LIGHT
result = nativeTheme.shouldUseDarkColors ? APP_THEME.DARK : APP_THEME.LIGHT
return result
}
export const convertArrayBufferToBuffer = (arrayBuffer) => {
const buffer = Buffer.alloc(arrayBuffer.byteLength)
const view = new Uint8Array(arrayBuffer)
for (let i = 0; i < buffer.length; ++i) {
buffer[i] = view[i]
}
return buffer
}
export const showItemInFolder = (fullPath) => {
if (!fullPath) {
return
}
fullPath = resolve(fullPath)
access(fullPath, constants.F_OK, (err) => {
if (err) {
logger.warn(`[Motrix] ${fullPath} ${err ? 'does not exist' : 'exists'}`)
return
}
shell.showItemInFolder(fullPath)
})
}
+54 -54
View File
@@ -1,33 +1,35 @@
export function concat (template, submenu, submenuToAdd) {
import { parse } from 'querystring'
export const concat = (template, submenu, submenuToAdd) => {
submenuToAdd.forEach(sub => {
let relativeItem = null
if (sub.position) {
switch (sub.position) {
case 'first':
submenu.unshift(sub)
break
case 'last':
submenu.push(sub)
break
case 'before':
relativeItem = findById(template, sub['relative-id'])
if (relativeItem) {
let array = relativeItem.__parent
let index = array.indexOf(relativeItem)
array.splice(index, 0, sub)
}
break
case 'after':
relativeItem = findById(template, sub['relative-id'])
if (relativeItem) {
let array = relativeItem.__parent
let index = array.indexOf(relativeItem)
array.splice(index + 1, 0, sub)
}
break
default:
submenu.push(sub)
break
case 'first':
submenu.unshift(sub)
break
case 'last':
submenu.push(sub)
break
case 'before':
relativeItem = findById(template, sub['relative-id'])
if (relativeItem) {
const array = relativeItem.__parent
const index = array.indexOf(relativeItem)
array.splice(index, 0, sub)
}
break
case 'after':
relativeItem = findById(template, sub['relative-id'])
if (relativeItem) {
const array = relativeItem.__parent
const index = array.indexOf(relativeItem)
array.splice(index + 1, 0, sub)
}
break
default:
submenu.push(sub)
break
}
} else {
submenu.push(sub)
@@ -35,9 +37,9 @@ export function concat (template, submenu, submenuToAdd) {
})
}
export function merge (template, item) {
export const merge = (template, item) => {
if (item.id) {
let matched = findById(template, item.id)
const matched = findById(template, item.id)
if (matched) {
if (item.submenu && Array.isArray(item.submenu)) {
if (!Array.isArray(matched.submenu)) {
@@ -54,15 +56,15 @@ export function merge (template, item) {
}
function findById (template, id) {
for (let i in template) {
let item = template[i]
for (const i in template) {
const item = template[i]
if (item.id === id) {
// Returned item need to have a reference to parent Array (.__parent).
// This is required to handle `position` and `relative-id`
item.__parent = template
return item
} else if (Array.isArray(item.submenu)) {
let result = findById(item.submenu, id)
const result = findById(item.submenu, id)
if (result) {
return result
}
@@ -71,9 +73,9 @@ function findById (template, id) {
return null
}
export function translateTemplate (template, keystrokesByCommand, i18n) {
for (let i in template) {
let item = template[i]
export const translateTemplate = (template, keystrokesByCommand, i18n) => {
for (const i in template) {
const item = template[i]
if (item.command) {
item.accelerator = acceleratorForCommand(item.command, keystrokesByCommand)
}
@@ -99,7 +101,7 @@ export function translateTemplate (template, keystrokesByCommand, i18n) {
return template
}
export function handleCommand (item) {
export const handleCommand = (item) => {
handleCommandBefore(item)
const args = item['command-arg']
@@ -112,30 +114,28 @@ export function handleCommand (item) {
}
function handleCommandBefore (item) {
console.log('handleCommandBefore==1=>', item)
if (!item['command-before']) {
return
}
const [ command, ...args ] = item['command-before'].split(',')
console.log('handleCommandBefore==2=>', command, ...args)
global.application.sendCommandToAll(command, ...args)
const [command, params] = item['command-before'].split('?')
const args = parse(params)
global.application.sendCommandToAll(command, args)
}
function handleCommandAfter (item) {
console.log('handleCommandAfter==1=>', item)
if (!item['command-after']) {
return
}
const [ command, ...args ] = item['command-after'].split(',')
console.log('handleCommandAfter==2=>', command, ...args)
global.application.sendCommandToAll(command, ...args)
const [command, params] = item['command-after'].split('?')
const args = parse(params)
global.application.sendCommandToAll(command, args)
}
function acceleratorForCommand (command, keystrokesByCommand) {
const keystroke = keystrokesByCommand[command]
if (keystroke) {
let modifiers = keystroke.split(/-(?=.)/)
let key = modifiers.pop().toUpperCase()
const key = modifiers.pop().toUpperCase()
.replace('+', 'Plus')
.replace('MINUS', '-')
modifiers = modifiers.map((modifier) => {
@@ -152,14 +152,14 @@ function acceleratorForCommand (command, keystrokesByCommand) {
.replace(/alt/ig, 'Alt')
}
})
let keys = modifiers.concat([key])
const keys = modifiers.concat([key])
return keys.join('+')
}
return null
}
export function flattenMenuItems (menu) {
let flattenItems = {}
export const flattenMenuItems = (menu) => {
const flattenItems = {}
menu.items.forEach(item => {
if (item.id) {
flattenItems[item.id] = item
@@ -171,26 +171,26 @@ export function flattenMenuItems (menu) {
return flattenItems
}
export function updateStates (itemsById, visibleStates, enabledStates, checkedStates) {
export const updateStates = (itemsById, visibleStates, enabledStates, checkedStates) => {
if (visibleStates) {
for (let command in visibleStates) {
let item = itemsById[command]
for (const command in visibleStates) {
const item = itemsById[command]
if (item) {
item.visible = visibleStates[command]
}
}
}
if (enabledStates) {
for (let command in enabledStates) {
let item = itemsById[command]
for (const command in enabledStates) {
const item = itemsById[command]
if (item) {
item.enabled = enabledStates[command]
}
}
}
if (checkedStates) {
for (let id in checkedStates) {
let item = itemsById[id]
for (const id in checkedStates) {
const item = itemsById[id]
if (item) {
item.checked = checkedStates[id]
}
+132 -74
View File
@@ -1,7 +1,7 @@
import { remote } from 'electron'
import { ipcRenderer } from 'electron'
import is from 'electron-is'
import { isEmpty } from 'lodash'
import Aria2 from 'aria2'
import { isEmpty, clone } from 'lodash'
import { Aria2 } from '@shared/aria2'
import {
separateConfig,
compactUndefined,
@@ -10,24 +10,20 @@ import {
changeKeysToCamelCase,
changeKeysToKebabCase
} from '@shared/utils'
import {
BEST_TRACKERS_URL,
BEST_TRACKERS_IP_URL
} from '@shared/constants'
const application = remote.getGlobal('application')
import { ENGINE_RPC_HOST } from '@shared/constants'
export default class Api {
constructor (options = {}) {
this.options = options
this.client = null
this.init()
}
init () {
this.loadConfig()
this.initClient()
async init () {
this.config = await this.loadConfig()
this.client = this.initClient()
this.client.open()
}
loadConfigFromLocalStorage () {
@@ -36,21 +32,18 @@ export default class Api {
return result
}
loadConfigFromNativeStore () {
const systemConfig = application.configManager.getSystemConfig()
const userConfig = application.configManager.getUserConfig()
const result = { ...systemConfig, ...userConfig }
async loadConfigFromNativeStore () {
const result = await ipcRenderer.invoke('get-app-config')
return result
}
loadConfig () {
async loadConfig () {
let result = is.renderer()
? this.loadConfigFromNativeStore()
? await this.loadConfigFromNativeStore()
: this.loadConfigFromLocalStorage()
result = changeKeysToCamelCase(result)
this.config = result
return result
}
initClient () {
@@ -58,13 +51,12 @@ export default class Api {
rpcListenPort: port,
rpcSecret: secret
} = this.config
const host = '127.0.0.1'
this.client = new Aria2({
const host = ENGINE_RPC_HOST
return new Aria2({
host,
port,
secret
})
this.client.open()
}
closeClient () {
@@ -79,7 +71,7 @@ export default class Api {
fetchPreference () {
return new Promise((resolve) => {
this.loadConfig()
this.config = this.loadConfig()
resolve(this.config)
})
}
@@ -99,20 +91,24 @@ export default class Api {
savePreferenceToNativeStore (params = {}) {
const { user, system, others } = separateConfig(params)
if (!isEmpty(system)) {
console.info('[Motrix] save system config: ', system)
application.configManager.setSystemConfig(system)
this.changeGlobalOption(system)
}
const config = {}
if (!isEmpty(user)) {
console.info('[Motrix] save user config: ', user)
application.configManager.setUserConfig(user)
config.user = user
}
if (!isEmpty(system)) {
console.info('[Motrix] save system config: ', system)
config.system = system
this.updateActiveTaskOption(system)
}
if (!isEmpty(others)) {
console.info('[Motrix] save config found iillegal key: ', others)
console.info('[Motrix] save config found illegal key: ', others)
}
ipcRenderer.send('command', 'application:save-preference', config)
}
getVersion () {
@@ -146,12 +142,23 @@ export default class Api {
})
}
changeOption (params = {}) {
let { gid, options = {} } = params
options = formatOptionsForEngine(options)
updateActiveTaskOption (options) {
this.fetchTaskList({ type: 'active' })
.then((data) => {
if (isEmpty(data)) {
return
}
const kebabOptions = changeKeysToKebabCase(options)
const args = compactUndefined([gid, kebabOptions])
const gids = data.map((task) => task.gid)
this.batchChangeOption({ gids, options })
})
}
changeOption (params = {}) {
const { gid, options = {} } = params
const engineOptions = formatOptionsForEngine(options)
const args = compactUndefined([gid, engineOptions])
return this.client.call('changeOption', ...args)
}
@@ -163,12 +170,16 @@ export default class Api {
addUri (params) {
const {
uris,
outs,
options
} = params
const kebabOptions = changeKeysToKebabCase(options)
const tasks = uris.map((uri) => {
const args = compactUndefined([[uri], kebabOptions])
return [ 'aria2.addUri', ...args ]
const tasks = uris.map((uri, index) => {
const engineOptions = formatOptionsForEngine(options)
if (outs && outs[index]) {
engineOptions.out = outs[index]
}
const args = compactUndefined([[uri], engineOptions])
return ['aria2.addUri', ...args]
})
return this.client.multicall(tasks)
}
@@ -178,8 +189,8 @@ export default class Api {
torrent,
options
} = params
const kebabOptions = changeKeysToKebabCase(options)
const args = compactUndefined([torrent, [], kebabOptions])
const engineOptions = formatOptionsForEngine(options)
const args = compactUndefined([torrent, [], engineOptions])
return this.client.call('addTorrent', ...args)
}
@@ -188,8 +199,8 @@ export default class Api {
metalink,
options
} = params
const kebabOptions = changeKeysToKebabCase(options)
const args = compactUndefined([metalink, kebabOptions])
const engineOptions = formatOptionsForEngine(options)
const args = compactUndefined([metalink, engineOptions])
return this.client.call('addMetalink', ...args)
}
@@ -199,14 +210,14 @@ export default class Api {
const waitingArgs = compactUndefined([offset, num, keys])
return new Promise((resolve, reject) => {
this.client.multicall([
[ 'aria2.tellActive', ...activeArgs ],
[ 'aria2.tellWaiting', ...waitingArgs ]
['aria2.tellActive', ...activeArgs],
['aria2.tellWaiting', ...waitingArgs]
]).then((data) => {
console.log('fetchDownloadingTaskList data', data)
console.log('[Motrix] fetch downloading task list data:', data)
const result = mergeTaskResult(data)
resolve(result)
}).catch((err) => {
console.log('fetchDownloadingTaskList fail===>', err)
console.log('[Motrix] fetch downloading task list fail:', err)
reject(err)
})
})
@@ -224,17 +235,23 @@ export default class Api {
return this.client.call('tellStopped', ...args)
}
fetchActiveTaskList (params = {}) {
const { keys } = params
const args = compactUndefined([keys])
return this.client.call('tellActive', ...args)
}
fetchTaskList (params = {}) {
const { type } = params
switch (type) {
case 'active':
return this.fetchDownloadingTaskList(params)
case 'waiting':
return this.fetchWaitingTaskList(params)
case 'stopped':
return this.fetchStoppedTaskList(params)
default:
return this.fetchDownloadingTaskList(params)
case 'active':
return this.fetchDownloadingTaskList(params)
case 'waiting':
return this.fetchWaitingTaskList(params)
case 'stopped':
return this.fetchStoppedTaskList(params)
default:
return this.fetchDownloadingTaskList(params)
}
}
@@ -244,6 +261,36 @@ export default class Api {
return this.client.call('tellStatus', ...args)
}
fetchTaskItemWithPeers (params = {}) {
const { gid, keys } = params
const statusArgs = compactUndefined([gid, keys])
const peersArgs = compactUndefined([gid])
return new Promise((resolve, reject) => {
this.client.multicall([
['aria2.tellStatus', ...statusArgs],
['aria2.getPeers', ...peersArgs]
]).then((data) => {
console.log('[Motrix] fetchTaskItemWithPeers:', data)
const result = data[0] && data[0][0]
const peers = data[1] && data[1][0]
result.peers = peers || []
console.log('[Motrix] fetchTaskItemWithPeers.result:', result)
console.log('[Motrix] fetchTaskItemWithPeers.peers:', peers)
resolve(result)
}).catch((err) => {
console.log('[Motrix] fetch downloading task list fail:', err)
reject(err)
})
})
}
fetchTaskItemPeers (params = {}) {
const { gid, keys } = params
const args = compactUndefined([gid, keys])
return this.client.call('getPeers', ...args)
}
pauseTask (params = {}) {
const { gid } = params
const args = compactUndefined([gid])
@@ -300,24 +347,35 @@ export default class Api {
return this.client.call('removeDownloadResult', ...args)
}
startPowerSaveBlocker () {
application.energyManager.startPowerSaveBlocker()
}
multicall (method, params = {}) {
let { gids, options = {} } = params
options = formatOptionsForEngine(options)
stopPowerSaveBlocker () {
application.energyManager.stopPowerSaveBlocker()
}
fetchBtTrackerFromGitHub () {
const now = Date.now()
const promises = [
fetch(`${BEST_TRACKERS_IP_URL}?t=${now}`).then((res) => res.text()),
fetch(`${BEST_TRACKERS_URL}?t=${now}`).then((res) => res.text())
]
return Promise.all(promises).then((values) => {
let result = values.join('\r\n').replace(/^\s*[\r\n]/gm, '')
return result
const data = gids.map((gid, index) => {
const _options = clone(options)
const args = compactUndefined([gid, _options])
return [method, ...args]
})
return this.client.multicall(data)
}
batchChangeOption (params = {}) {
return this.multicall('aria2.changeOption', params)
}
batchRemoveTask (params = {}) {
return this.multicall('aria2.remove', params)
}
batchResumeTask (params = {}) {
return this.multicall('aria2.unpause', params)
}
batchPauseTask (params = {}) {
return this.multicall('aria2.pause', params)
}
batchForcePauseTask (params = {}) {
return this.multicall('aria2.forcePause', params)
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 10 KiB

+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<g class="nc-icon-wrapper" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" stroke="currentColor">
<line data-cap="butt" data-color="color-2" fill="none" stroke-miterlimit="10" x1="12" y1="2" x2="12" y2="22"/>
<polyline fill="none" stroke="currentColor" stroke-miterlimit="10" points="19,15 12,22 5,15 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 429 B

+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<g class="nc-icon-wrapper" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" stroke="currentColor">
<line data-cap="butt" data-color="color-2" fill="none" stroke-miterlimit="10" x1="12" y1="22" x2="12" y2="2"/>
<polyline fill="none" stroke="currentColor" stroke-miterlimit="10" points="5,9 12,2 19,9 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 426 B

+9
View File
@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g stroke-linecap="square" stroke-linejoin="miter" stroke-width="2" fill="#000000" stroke="#000000">
<line fill="none" stroke-miterlimit="10" x1="8.2" y1="4.5" x2="11.1" y2="7.3"></line>
<line fill="none" stroke-miterlimit="10" x1="16.7" y1="12.9" x2="19.5" y2="15.8"></line>
<path fill="none" stroke="#000000" stroke-miterlimit="10"
d="M12.5,17.2 c-1.6,1.6-4.1,1.6-5.7,0c-1.6-1.6-1.6-4.1,0-5.7l7.1-7.1l-2.8-2.8L4,8.7C0.9,11.8,0.9,16.9,4,20s8.2,3.1,11.3,0l7.1-7.1l-2.8-2.8 L12.5,17.2z">
</path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 617 B

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