Compare commits

...

206 Commits

Author SHA1 Message Date
Yaronzz f4854f4b74 Fix formatting issues in README.md
Build exe / build (macos-latest) (push) Has been cancelled
Build exe / build (ubuntu-latest) (push) Has been cancelled
Build exe / build (windows-latest) (push) Has been cancelled
2025-10-17 11:41:40 +08:00
Yaronzz 8352f0f6e2 UPDATE 2023-11-01 13:41:16 +08:00
Yaronzz a8da5c0ff3 Merge pull request #1106 from exislow/gui-playlists
[GUI] Show user's playlists and allow to download them.
2023-10-31 13:34:49 +08:00
Robert Honz df7c444487 Added playlist -> right click to download the whole playlist in "playlist style". 2023-10-31 06:08:40 +01:00
Robert Honz d88dca4da6 Style fix. 2023-10-23 21:55:57 +02:00
Robert Honz 88b5b61328 KeyPressEvent select all items. 2023-10-23 21:55:26 +02:00
Robert Honz 56c9cf5695 Refactoring: Mainly removed unused imports. 2023-10-23 15:00:06 +02:00
Robert Honz 379eca8458 Multiple title can be downloaded sequentially. 2023-10-23 14:34:14 +02:00
Robert Honz 7d6f9fc6e1 * Playlist content will be displayed in table.
* Can select multiple items to download.
2023-10-23 13:41:17 +02:00
Robert Honz 87eabab36f * Added tidalapi as dependency.
* Added TreeView to display user's playlists.
2023-10-22 21:16:20 +02:00
Robert Honz 288c75bcc7 Removed tidal. import. 2023-10-22 10:51:47 +02:00
Yaronzz 62d83b5975 update readme 2023-09-06 10:25:38 +08:00
Yaronzz 251af9e745 Merge branch 'master' of https://github.com/yaronzz/Tidal-Media-Downloader into master 2023-09-06 09:34:13 +08:00
Yaronzz 0751c37b35 update 2023-09-06 09:34:01 +08:00
Yaronzz 4f32b14441 1. Add quality 'MAX'
2. Try to parse 'dash+xml'
2023-09-06 09:31:50 +08:00
Yaronzz 97928ef207 Merge pull request #1075 from yaronzz/dependabot/pip/TIDALDL-PY/requests-2.31.0
Bump requests from 2.27.1 to 2.31.0 in /TIDALDL-PY
2023-07-13 08:41:48 +08:00
Yaronzz 9edd5967f0 Merge pull request #1078 from adibue/doc-link-fix
Fix links to documentation
2023-07-13 08:41:23 +08:00
Adrian Bühler 8449b85d81 Fix links to documentation 2023-06-14 15:57:28 +02:00
dependabot[bot] 2f4ad82421 Bump requests from 2.27.1 to 2.31.0 in /TIDALDL-PY
Bumps [requests](https://github.com/psf/requests) from 2.27.1 to 2.31.0.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.27.1...v2.31.0)

---
updated-dependencies:
- dependency-name: requests
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-23 03:22:30 +00:00
Yaronzz 513be57c3d fix getTrackPath bug 2022-12-21 09:16:22 +08:00
Yaronzz 3eb11252c2 Merge pull request #1006 from roberts91/made-video-download-optional
Made video download optional
2022-12-21 08:54:51 +08:00
Yaronzz b972f7cda8 Merge branch 'master' into made-video-download-optional 2022-12-21 08:51:23 +08:00
Yaronzz b1b643109c Merge pull request #1019 from DJSweder/patch-1
Update czech.py
2022-11-14 09:28:34 +08:00
Yaronzz c15ad63542 Merge pull request #1017 from Click1701/master
Update german.py
2022-11-14 09:27:29 +08:00
DJSweder 09321db35e Update czech.py
Some minor changes
2022-11-13 16:52:45 +01:00
Click1701 132e516250 Update german.py
Translated yet untranslated parts and other slight changes
2022-11-08 17:20:17 +01:00
Yaronzz a771c598ae upload new version 2022-10-31 14:08:07 +08:00
Yaronzz db76e84123 Merge pull request #1003 from Zibbp/master
fix(cover): return if no cover found
2022-10-31 13:37:45 +08:00
Yaronzz 7eb4419177 Merge pull request #1002 from bladeoner/stale
Update stale.yml
2022-10-31 13:36:28 +08:00
Yaronzz df3c405667 Merge pull request #1001 from grzekru/delay_setting
Add delay setting
2022-10-31 13:36:10 +08:00
Yaronzz 951fd102ad Merge pull request #999 from bladeoner/workflow
Update Github Workflow
2022-10-31 13:33:55 +08:00
Robert Sæther 252076f6dd Added missing translations 2022-10-31 04:27:30 +01:00
Robert Sæther 11828a0e8e Made video download optional when downloading playlists, albums or mixes 2022-10-31 02:30:57 +01:00
Isaac 93f363f405 fix(cover): return if no cover found 2022-10-28 10:02:27 -05:00
bladeoner 12a96d8a46 Update stale.yml 2022-10-26 08:21:25 +02:00
Grzegorz Krukar 238b2da4b3 Add delay setting 2022-10-25 23:51:16 +02:00
bladeoner 76313d68c9 Update Github Workflow 2022-10-21 13:36:42 +02:00
Yaronzz 4e8751ceb1 upload new version 2022-10-12 10:28:26 +08:00
Yaronzz 2dfcbad8f0 Merge pull request #995 from roberts91/added-playlist-format-option
Added option to control playlist folder format, added norwegian translations, translation file cleanup (all files now have same structure)
2022-10-12 10:17:57 +08:00
Robert Sæther 07d18ce2d6 Language file clean-up (all files has same structure), added norwegian translations 2022-10-10 15:36:29 +02:00
Robert Sæther 7fdd307176 Minor translation cleanup 2022-10-10 14:53:07 +02:00
Robert Sæther 11805382cc Removed duplicate translation 2022-10-10 14:18:07 +02:00
Robert Sæther 044a847e78 Added option to control playlist folder format 2022-10-10 01:22:47 +02:00
Yaronzz 6e49253e99 Merge pull request #992 from dansleboby/fix-issue-970-986
Fix issue #970 and #986
2022-09-27 10:44:18 +08:00
Gilbert Paquin 0c83717469 Only take streamReady track
This is when a track is still in the playlist and no longer on tidal, you can't play the song anymore through tidal

Fix Issue #970
2022-09-23 16:37:04 -04:00
Gilbert Paquin 7f1afb27f1 Random delay and long wait if for any reason the random delay too short
Fix issue #986
2022-09-23 16:35:55 -04:00
Yaronzz 18efb49213 Merge pull request #983 from omensight/master
Fix error when cover is not present
2022-09-13 09:42:46 +08:00
Mijael Viricochea Parra a275275cb6 Revert "Build file added for Windows"
This reverts commit 7e5b6d22c4.
2022-09-12 21:32:48 -04:00
Mijael Viricochea Parra 7e5b6d22c4 Build file added for Windows 2022-09-09 21:31:01 -04:00
Mijael Viricochea 96742046ba Fix error when cover is not present 2022-09-08 16:30:41 -04:00
Yaronzz 3199dcedc6 upload new version 2022-08-29 10:30:03 +08:00
Yaronzz 2cf59b3195 Fix #931 2022-08-29 10:25:50 +08:00
Yaronzz be84a3631a Merge pull request #974 from yohann69/patch-1
Update french.py
2022-08-23 09:16:24 +08:00
Yaronzz 9ce35af72f Merge pull request #967 from bladeoner/language
Update Hungarian language
2022-08-23 09:16:00 +08:00
Yohann 9d904a0fea Update french.py 2022-08-11 18:40:28 +02:00
bladeoner 5e05afd775 Update Hungarian language 2022-08-01 23:29:18 +02:00
Yaronzz dece506d58 Merge pull request #962 from DJSweder/patch-2
Update czech.py
2022-07-28 23:24:38 +08:00
DJSweder c2cc170988 Update czech.py
Correction of author's information.
2022-07-26 14:11:33 +02:00
DJSweder 3cab9ea295 Update czech.py
Corrections and completion translation into Czech language.
2022-07-26 10:18:10 +02:00
Yaronzz 5cf094d227 Merge pull request #946 from acherifi/add_artists_search_and_favorites
Add capability to perform an artist search and download all albums
2022-07-26 10:05:10 +08:00
Yaronzz 2e1e15ed3f Merge pull request #959 from KitDaCatsun/patch-2
Made errors in __post__ throw after 3 attempts
2022-07-26 10:02:57 +08:00
KitDaCatsun 7434470216 Made errors in __post__ throw after 3 attempts
`range(3)` gives `0, 1, 2` so `index >= 3` would never be reached. Assuming intended behavior was to throw if an error occurs on the third try and ignore errors on the first and second
2022-07-25 10:17:04 +01:00
Yaronzz 2ce2a310ae Merge pull request #958 from KitDaCatsun/patch-1
Removed unused assignment
2022-07-25 17:14:31 +08:00
KitDaCatsun dfc7af7796 Removed unused assignment
header set to {} then immediately given new value
2022-07-25 09:06:17 +01:00
Ali CHERIFI 63bf063dd3 Fix except block 2022-07-14 22:51:38 +02:00
Ali CHERIFI 3e8a3436b4 Add capability to perform an artist search and download all albums 2022-07-14 22:43:12 +02:00
Yaronzz e08e5efc88 upload new version 2022-07-14 09:54:54 +08:00
Yaronzz 7f3758e18c Fix bug of #945 2022-07-14 09:52:45 +08:00
Yaronzz 3e2d74a37f update readme 2022-07-08 11:15:13 +08:00
Yaronzz 69ccd65025 update readme 2022-07-08 11:11:49 +08:00
Yaronzz 81b82e6c29 update gui 2022-07-08 10:54:05 +08:00
Yaronzz 346befda6d update gui 2022-07-08 09:59:48 +08:00
Yaronzz 450102bfea Merge pull request #940 from Frikilinux/lang-es
Translate new options and fix typos
2022-07-08 08:34:11 +08:00
Frikilinux a966b3d93d Translate new options and fix typos 2022-07-07 19:01:27 -03:00
Yaronzz 55df515256 upload new version #936 2022-07-06 14:57:30 +08:00
Yaronzz 242747719a Mulithread download 2022-07-06 14:43:59 +08:00
Yaronzz e3c5886a02 upload v2022.6.30.1 2022-06-30 09:06:27 +08:00
Yaronzz 33c49b83db fix #934 2022-06-30 08:57:04 +08:00
Yaronzz ed13b9b92d check qt_material #933 2022-06-30 08:45:13 +08:00
Yaronzz e45f649e46 update readme 2022-06-27 17:38:10 +08:00
Yaronzz 0172301769 check api key 2022-06-27 11:16:00 +08:00
Yaronzz a7aa38e563 fix bug of #930 2022-06-24 18:30:53 +08:00
Yaronzz fd97a2b966 upload new version 2022-06-24 10:19:41 +08:00
Yaronzz e1ee47b93c update 2022-06-23 14:07:26 +08:00
Yaronzz 61b9dd3af8 update 2022-06-23 13:43:47 +08:00
Yaronzz 628a42b058 add require module 2022-06-23 13:38:40 +08:00
Yaronzz 2c392f0e22 upload new version 2022-06-23 11:55:19 +08:00
Yaronzz dc57d4d01d Merge pull request #927 from yaronzz/refactor
Refactor
2022-06-23 11:42:21 +08:00
Yaronzz 8ed83b1672 Merge remote-tracking branch 'remotes/origin/master' into refactor
# Conflicts:
#	README.md
#	TIDALDL-PY/tidal_dl/tidal.py
2022-06-23 11:38:42 +08:00
Yaronzz 3099820956 1. update setup.py 2022-06-23 11:26:33 +08:00
Yaronzz d643de43e9 1. add simple-gui 2022-06-23 10:03:17 +08:00
Yaronzz 39db4730c5 update README.md 2022-06-22 11:44:08 +08:00
Yaronzz 937aa7ca8f Merge pull request #924 from RandomNinjaAtk/patch-1
Bugfix for unable [ERR] {TITLE} parse ts urls failed
2022-06-21 15:22:42 +08:00
RandomNinjaAtk 84b9f6f6bc Bugfix for unable [ERR] {TITLE} parse ts urls failed
See issue: #872 

Tested and verified this change works locally.
2022-06-20 18:05:28 -04:00
Yaronzz b1ebd6f0b2 remove settings: onlyM4a 2022-06-20 17:34:41 +08:00
Yaronzz e1562ba30e 1. rebuild tidal-dl 2022-06-20 15:15:52 +08:00
Yaronzz 8876be13b6 fix bug of #916 2022-06-17 17:06:36 +08:00
Yaronzz 30a6c8c55a Merge pull request #896 from artiescie/master
for playlist dl, perform deletes as well as adds in the target dir
2022-06-09 11:47:09 +08:00
Yaronzz eb01de7f3a Merge pull request #912 from Blackjack200/master
improve chinese translation
2022-06-09 11:43:08 +08:00
Yaronzz e652556de2 skip 2022-06-07 08:41:21 +08:00
AZ1IDJC 00ef2f906f improve chinese translation 2022-06-05 23:28:09 +08:00
Yaronzz aba9493201 Merge pull request #903 from bladeoner/stale
Update stale job increase number of operations
2022-05-18 20:35:59 +08:00
bladeoner c78a56fff0 Update stale job increase number of operations 2022-04-26 10:59:06 +02:00
Richard Curzon 56bf0f9510 if there are .lrc lyric files, and corresponding music is deleted, then delete also the .lrc 2022-04-17 05:53:49 -04:00
Richard Curzon 2ebf80869c For playlist, remove TIDAL songs and redownload PL, the songs will be removed in the mirror image dl folder 2022-04-16 09:09:12 -04:00
Yaronzz bb5be5e5fb Merge pull request #895 from bladeoner/stale 2022-04-16 18:18:31 +08:00
bladeoner 5c2a13d4d1 Update stale messages 2022-04-16 12:02:36 +02:00
Yaronzz c61be4bbf3 update readme 2022-04-02 10:44:26 +08:00
Yaronzz a969583d79 update readme 2022-04-01 17:23:27 +08:00
Yaronzz 9f9a4f9aef update readme 2022-04-01 16:43:59 +08:00
Yaronzz 3b3af6a174 update workflow 2022-04-01 16:27:22 +08:00
Yaronzz 166961297e update workflow 2022-04-01 16:20:37 +08:00
Yaronzz 1f5343569f update workflow 2022-04-01 15:56:17 +08:00
Yaronzz 9e9d47f470 update workflow 2022-04-01 15:40:55 +08:00
Yaronzz 6870a8c37f update workflow 2022-04-01 15:11:27 +08:00
Yaronzz 4d368dd04d update workflow 2022-04-01 15:04:26 +08:00
Yaronzz 64b98ee117 update workflow 2022-04-01 12:34:05 +08:00
Yaronzz 5ec77efb19 update workflow 2022-04-01 12:27:41 +08:00
Yaronzz 65da2f7272 Create stale.yml 2022-04-01 11:52:32 +08:00
Yaronzz a5fb92db92 update workflow 2022-04-01 11:50:36 +08:00
Yaronzz 81e244f230 update workflow 2022-04-01 11:42:03 +08:00
Yaronzz 6a1b931340 update workflow 2022-04-01 11:38:02 +08:00
Yaronzz 8a21b01c1d update workflow 2022-04-01 11:25:21 +08:00
Yaronzz 96f46c2b59 update workflow 2022-04-01 10:32:42 +08:00
Yaronzz ffe335c17e update workflow 2022-04-01 10:18:21 +08:00
Yaronzz 79b537c186 update workflow 2022-04-01 09:56:59 +08:00
Yaronzz a806785609 update workflow 2022-04-01 09:50:11 +08:00
Yaronzz 06ff60ca74 update workflow 2022-04-01 09:47:00 +08:00
Yaronzz b34013129e update workflow 2022-04-01 09:30:38 +08:00
Yaronzz f1a5b1d764 update workflow 2022-04-01 09:27:40 +08:00
Yaronzz d52980506c Merge branch 'master' of https://github.com/yaronzz/Tidal-Media-Downloader into master 2022-04-01 09:27:06 +08:00
Yaronzz 34bab40d3d update 2022-04-01 09:26:55 +08:00
Yaronzz 747d06c7b4 Update util.py 2022-03-31 18:00:42 +08:00
Yaronzz 41573b7b39 Merge pull request #878 from bladeoner/language
Update Dutch language
2022-03-24 08:44:16 +08:00
bladeoner112@gmail.com d7e078db2e Update Dutch Language 2022-03-18 17:35:54 +01:00
392309221 363a854428 add m3u8dl.py 2022-03-14 15:55:22 +08:00
392309221 ad00099c9d Add video-path-format 2022-03-08 09:23:25 +08:00
392309221 6676a380e1 Add track-path-format 'TrackID' 2022-03-08 08:53:24 +08:00
Yaronzz bab13ff718 Merge pull request #877 from Kyo-70/patch-1
Update the Portuguese Translation
2022-03-07 15:14:40 +08:00
Yaronzz 9707c5c276 Merge branch 'master' into patch-1 2022-03-07 15:14:23 +08:00
Yaronzz 48206d675a Merge pull request #875 from PatrykMis/lng-polish
Add Polish translation, global typo fixes
2022-03-07 15:12:14 +08:00
Kyo-70 f877c184bb Update the Portuguese Translation
here is my contribution
2022-03-05 18:40:01 -04:00
Patryk Mis 59b360b285 Fix global typos 2022-03-04 19:59:44 +01:00
Patryk Mis 1a09571788 Add Polish translation 2022-03-04 19:49:47 +01:00
Yaronzz 2484a8d4d8 fix #874 2022-03-04 18:03:38 +08:00
Yaronzz 5e73ad35fa upload new version 2022-03-04 17:12:09 +08:00
Yaronzz 8503a622b0 1. fix #844 2022-03-04 17:02:30 +08:00
Yaronzz ab479300ea Merge pull request #871 from bladeoner/language
Add Dutch language
2022-03-02 10:12:49 +08:00
Yaronzz 96fb847479 Merge pull request #870 from bladeoner/workflow
Update Github Workflow
2022-03-02 10:12:40 +08:00
bladeoner 5484669333 Add Dutch language 2022-03-01 16:20:38 +01:00
bladeoner e366edbbea Update Github Workflow 2022-03-01 10:40:54 +01:00
Yaronzz e8ef25183d Merge pull request #864 from bladeoner/workflow
Add nightly build for tidal-dl and update README.md
2022-02-28 14:52:42 +08:00
Yaronzz c94c5283a7 Merge pull request #868 from bladeoner/requirements
Update requirements, add pydub and fix aigp warning
2022-02-28 09:12:53 +08:00
Yaronzz 77803c0b41 Merge pull request #869 from bladeoner/url
Update link to HTTPS
2022-02-28 09:12:18 +08:00
bladeoner b5bd4af56d Add nightly build for tidal-dl and update README.md 2022-02-27 17:36:09 +01:00
bladeoner 0a28baad64 Update link to HTTPS 2022-02-27 15:29:25 +01:00
bladeoner 6a1cd1d1d1 Update requirements, add pydub and fix aigp warning 2022-02-27 15:24:26 +01:00
392309221 25e72aa45e fix bug of setting path 2022-02-25 09:34:30 +08:00
Yaronzz 90f869fcdb Merge pull request #860 from bladeoner/reports
Replace bug, feature request and question reports
2022-02-23 10:00:47 +08:00
Yaronzz 72a2cb804a Merge pull request #858 from 9uyone/master
Update Ukrainian
2022-02-23 10:00:13 +08:00
bladeoner 752fb9e719 Replace bug, feature request and question reports 2022-02-22 11:14:15 +01:00
9uyone ac745e1434 correction of date in ukrainian.py 2022-02-20 23:02:08 +02:00
9uyone cbb4480d1e Update Ukrainian 2022-02-20 22:36:55 +02:00
Yaronzz a410370f45 update Hungarian #847 2022-02-11 08:40:00 +08:00
Yaronzz b8c4333d4e Merge pull request #846 from CDzungx/master
Update vietnamese.py
2022-02-11 08:37:09 +08:00
CDzungx 7e165f6c17 Update vietnamese.py
Update translations
2022-02-09 11:51:54 +07:00
Yaronzz c9ae7bfebd upload new version 2022-02-07 11:31:25 +08:00
Yaronzz 1d5b8cd8f6 Merge pull request #840 from 1nikolas/patch-1
New Api key
2022-02-07 08:42:16 +08:00
Yaronzz d41c8ddcae Merge pull request #836 from 9uyone/master
Update Ukrainian language
2022-02-07 08:40:08 +08:00
Nikolas Spiridakis 3d4b143c74 fix api key 2022-02-05 23:20:15 +02:00
Nikolas Spiridakis 5892525593 New Api key 2022-02-05 22:35:36 +02:00
9uyone ff0e794b8c Update ukrainian.py 2022-02-03 20:52:42 +02:00
Yaronzz 5f42afa31a Merge pull request #812 from Towe1ie/fix/set-access-token
Fix set access token typo and countryCode
2022-01-21 23:53:30 +08:00
Nemanja Lučić 2a56bee611 Format 2022-01-21 15:53:41 +01:00
Nemanja Lučić 685b7cb1f8 Format 2022-01-21 15:52:22 +01:00
Nemanja Lucic b0df00c0a3 Fix set access token typo and countryCode 2022-01-21 12:57:49 +01:00
Yaronzz 30917d1b0f Fix bug of "ReleaseDate" 2022-01-21 10:56:08 +08:00
Yaronzz 3848c4cf89 update 2022-01-21 09:40:51 +08:00
Yaronzz 753b6f6f76 Merge branch 'master' of https://github.com/yaronzz/Tidal-Media-Downloader into master 2022-01-21 09:17:05 +08:00
Yaronzz d6739dc63e upload new version 2022-01-21 09:16:45 +08:00
Yaronzz 4e14fb0501 Merge pull request #805 from Frikilinux/lang-es
Update Spanish language
2022-01-20 11:33:36 +08:00
Frikilinux 397ad9f823 Update Spanish language 2022-01-19 18:19:49 -03:00
Yaronzz d2218c58c1 Update FUNDING.yml 2022-01-18 17:34:02 +08:00
Yaronzz 7627c2a0f7 upload new version 2022-01-18 16:54:19 +08:00
Yaronzz 69a7ff6813 update gui 2022-01-18 11:59:37 +08:00
Yaronzz 133def9722 optimize code 2022-01-17 16:53:50 +08:00
Yaronzz 1b3afaabd0 upload new version 2022-01-11 17:40:38 +08:00
Yaronzz 9cb690378b upload new version 2022-01-11 17:37:51 +08:00
Yaronzz dd4b7254d9 Reset directory 2021-12-30 11:47:36 +08:00
yaronzz 394506e40d Optimize login 2021-12-28 17:42:14 +08:00
Yaronzz 6399cab7c4 Album folder format support: {None} 2021-12-27 17:37:28 +08:00
Yaronzz ba1a559a4b Settings: add type-folder(eg Album/Video/Playlist) 2021-12-27 17:00:45 +08:00
Yaronzz 41d7e30df5 upload new version 2021-11-30 11:08:32 +08:00
Yaronzz 94139c9f79 Merge pull request #750 from jee019/master
create Japanese translation file
2021-11-30 11:04:10 +08:00
jee019 5d4f8fb314 create Japanese translation 2021-11-30 11:43:31 +09:00
Yaronzz beae239007 Merge pull request #739 from jee019/master
update english.py & korean.py
2021-11-30 09:38:38 +08:00
jee019 f20c84eb6e Update english.py 2021-11-24 16:04:09 +09:00
jee019 588482707a Update korean.py 2021-11-24 16:03:25 +09:00
jee019 2ebb283119 Update english.py 2021-11-24 15:28:59 +09:00
jee019 3bfa300fad Update english.py 2021-11-24 15:24:31 +09:00
jee019 8ca30f65f3 Update korean.py 2021-11-24 15:23:17 +09:00
Yaronzz fa6a9fbbf8 upload new version 2021-11-21 01:46:13 +08:00
Yaronzz 8af25e0600 upload new version 2021-11-17 21:58:04 +08:00
Yaronzz 944b98c4b4 update 2021-11-15 23:20:15 +08:00
Yaronzz 8254a61389 Merge pull request #719 from hozzaq/patch-1
Update util.py
2021-11-15 23:08:49 +08:00
Haadiy Rozzaq d016c433ff Update util.py 2021-11-15 19:20:14 +07:00
120 changed files with 4224 additions and 5501 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
ko_fi: yaronzz
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
+64
View File
@@ -0,0 +1,64 @@
name: Bug Report
description: Create a bug report to help us improve.
title: "[BUG]: "
labels: bug
body:
- type: markdown
attributes:
value: |
Please search for this issue in issues-page first. Avoid duplication.
Please read Wiki first.
https://github.com/yaronzz/Tidal-Media-Downloader/wiki
- type: textarea
id: which-tool
attributes:
label: Which tool
description: Describe which tool has been used.
placeholder: |
tidal-gui or tidal-dl
validations:
required: true
- type: textarea
id: version
attributes:
label: Version
description: Describe the version of the tool.
placeholder: |
eg 2019.12.1.0
validations:
required: true
- type: textarea
id: platform
attributes:
label: Platform
description: Describe the platform on which the tool has been used.
placeholder: |
Windows\Linux\Macos\Android
validations:
required: true
- type: textarea
id: describe-bug
attributes:
label: Describe the bug
description: Describe the bug as accurately as possible.
placeholder: |
How to reappear this bug?
Which albumID\trackID\artistID?
Please describe in detail.
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell
validations:
required: false
- type: textarea
id: screenshots
attributes:
label: Add screenshots
description: Please add screenshots if available.
validations:
required: false
-25
View File
@@ -1,25 +0,0 @@
---
name: Bug report
about: Create a bug report to help us improve
title: "[BUG] xxxxxxxxxxxxx"
labels: bug
---
<!-- Please search for this issue in issues-page first. Avoid duplication. -->
<!-- Please read Wiki first. -->
<!-- https://github.com/yaronzz/Tidal-Media-Downloader/wiki -->
**Which tool**
<!-- tidal-gui or tidal-dl -->
**Version**
<!-- eg 2019.12.1.0 -->
**Platform**
<!-- Windows\Linux\Macos\Android -->
**Bug description**
<!-- How to reappear this bug?
Which albumID\trackID\artistID?
Please describe in detail. -->
**Screenshot**
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
+34
View File
@@ -0,0 +1,34 @@
name: Feature Request
description: Open a feature request to Tidal-Media-Downloader.
title: "[FEATURE]: "
labels: feature request
body:
- type: markdown
attributes:
value: |
Please search for this issue in issues-page first. Avoid duplication.
Please read Wiki first.
https://github.com/yaronzz/Tidal-Media-Downloader/wiki
- type: textarea
id: which-tool
attributes:
label: Which tool
description: Describe for which tool you want a feature to be added.
placeholder: |
tidal-gui or tidal-dl
validations:
required: true
- type: textarea
id: feature
attributes:
label: Describe the feature
description: Describe the feature as accurately as possible.
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Add screenshots
description: Please add screenshots if available.
validations:
required: false
-18
View File
@@ -1,18 +0,0 @@
---
name: Feature request
about: Open a feature request to Tidal-Media-Downloader
title: "[FEATURE] xxxxxxxxxxxxx"
labels: feature request
---
<!-- Please search for this issue in issues-page first. Avoid duplication. -->
<!-- Please read Wiki first. -->
<!-- https://github.com/yaronzz/Tidal-Media-Downloader/wiki -->
**Which tool**
<!-- tidal-gui or tidal-dl -->
**Which feature**
<!-- eg. Support IOS -->
**Description**
<!-- Please describe in detail. Screenshot-->
@@ -0,0 +1,34 @@
name: Questions
description: Question for the tool.
title: "[QUESTION]: "
labels: question
body:
- type: markdown
attributes:
value: |
Please search for this issue in issues-page first. Avoid duplication.
Please read Wiki first.
https://github.com/yaronzz/Tidal-Media-Downloader/wiki
- type: textarea
id: which-tool
attributes:
label: Which tool
description: Describe which tool the question is about.
placeholder: |
tidal-gui or tidal-dl
validations:
required: true
- type: textarea
id: question
attributes:
label: Describe your question
description: Describe your question as accurately as possible.
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Add screenshots
description: Please add screenshots if available.
validations:
required: false
-17
View File
@@ -1,17 +0,0 @@
---
name: Question
about: Question for the tool
title: "[QUESTION] xxxxxxxxxxxxx"
labels: question
---
<!-- Please search for this issue in issues-page first. Avoid duplication. -->
<!-- Please read Wiki first. -->
<!--
https://github.com/yaronzz/Tidal-Media-Downloader/wiki
https://yaronzz.top/post/tidal_dl_installation/
-->
**Which tool**
<!-- tidal-gui or tidal-dl -->
**Question**
+28
View File
@@ -0,0 +1,28 @@
# # This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
# #
# # You can adjust the behavior by modifying this file.
# # For more information, see:
# # https://github.com/actions/stale
# name: Mark stale issues and pull requests
# on:
# schedule:
# - cron: '45 15 * * *'
# jobs:
# stale:
# runs-on: ubuntu-latest
# permissions:
# issues: write
# pull-requests: write
# steps:
# - uses: actions/stale@v6
# with:
# repo-token: ${{ secrets.GITHUB_TOKEN }}
# stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity.'
# stale-pr-message: 'This pull request has been automatically marked as stale because it has not had recent activity.'
# stale-issue-label: 'no-issue-activity'
# stale-pr-label: 'no-pr-activity'
# operations-per-run: 60
+77
View File
@@ -0,0 +1,77 @@
name: Build exe
on: [push, pull_request]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install dependencies
shell: bash
run: |
pip3 install wheel
pip3 install pyinstaller
pip3 install PyQt5
pip3 install -r requirements.txt --upgrade
working-directory: TIDALDL-PY
- name: Clean directory
shell: bash
run: |
rm -rf dist
rm -rf build
rm -rf tidal_dl.egg-info
rm -rf tidal_gui.egg-info
rm -rf MANIFEST.in
working-directory: TIDALDL-PY
- name: Build tidal-dl
run: |
pyinstaller -F tidal_dl/__init__.py -n tidal-dl
working-directory: TIDALDL-PY
# - name: Build tidal-gui-macOs
# shell: bash
# if: ${{ matrix.os == 'macos-latest' }}
# run: |
# cp -rf guiStatic.in MANIFEST.in
# pyinstaller -F tidal_gui/__init__.py -w -n tidal-gui
# cp -rf tidal_gui/resource dist/
# working-directory: TIDALDL-PY
# - name: Build tidal-gui
# shell: bash
# if: ${{ matrix.os != 'macos-latest' }}
# run: |
# cp -rf guiStatic.in MANIFEST.in
# pyinstaller -D tidal_gui/__init__.py -w -n tidal-gui
# working-directory: TIDALDL-PY
# - name: Gzip tidal-gui
# shell: bash
# if: ${{ matrix.os != 'macos-latest' }}
# run: |
# cp -rf ../tidal_gui/resource ./tidal-gui/
# tar -zcvf tidal-gui.tar.gz tidal-gui
# rm -rf tidal-gui
# working-directory: TIDALDL-PY/dist
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: tidal-dl-${{ runner.os }}
path: |
TIDALDL-PY/dist/*
+15
View File
@@ -163,3 +163,18 @@ download/Playlist/Boy Bands- K-Pop Kings/Tmp0/22.part
.idea
tidal_dl-BAK
/TIDALDL-PY2/tidal_dl
/TIDALDL-GUI-CROSS/tidal_gui/view/__pycache__
/TIDALDL-GUI-CROSS/tidal_gui/viewModel/__pycache__
/TIDALDL-GUI-CROSS/tidal_gui/control/__pycache__
__pycache__
clean.sh
TIDALDL-PY/MANIFEST.in
TIDALDL-PY/exe/resource
TIDALDL-PY/exe/tidal_dl_win.tar.gz
.github/workflows/continuous-integration-workflow copy.yml
TIDALDL-PY/tidal-gui.spec
.history/
.gitignore
/TIDALDL-PY/tidal_dl_old
/TIDALDL-PY/tidal_gui_old
/TIDALDL-PY/tidal_gui
+8 -6
View File
@@ -14,8 +14,9 @@
"console": "integratedTerminal",
// "python": "python3",
"env": {
"PYTHONPATH": "${workspaceRoot}/TIDALDL-PY/"
"PYTHONPATH": "${workspaceRoot}/TIDALDL-PY/tidal_dl/"
},
"justMyCode": false
},
{
"name": "Python: common line",
@@ -25,7 +26,7 @@
"console": "integratedTerminal",
// "python": "python3",
"env": {
"PYTHONPATH": "${workspaceRoot}/TIDALDL-PY/"
"PYTHONPATH": "${workspaceRoot}/TIDALDL-PY/tidal_dl/"
},
"args": [
"--link",
@@ -33,7 +34,8 @@
"-o",
"e:\\test",
"-q",
"0"
"0",
"-g"
]
},
{
@@ -44,7 +46,7 @@
"console": "integratedTerminal",
// "python": "python3",
"env": {
"PYTHONPATH": "${workspaceRoot}/TIDALDL-PY/"
"PYTHONPATH": "${workspaceRoot}/TIDALDL-PY/tidal_dl/"
},
"justMyCode": false
@@ -53,11 +55,11 @@
"name": "Python: gui",
"type": "python",
"request": "launch",
"program": "${workspaceRoot}/TIDALDL-GUI/tidal_gui/__init__.py",
"program": "${workspaceRoot}/TIDALDL-PY/tidal_gui/__init__.py",
"console": "integratedTerminal",
// "python": "python3",
"env": {
"PYTHONPATH": "${workspaceRoot}/TIDALDL-GUI/"
"PYTHONPATH": "${workspaceRoot}/TIDALDL-PY/tidal_dl/"
},
"justMyCode": false
+46 -11
View File
@@ -1,6 +1,10 @@
<br>
<a href="https://github.com/yaronzz/Tidal-Media-Downloader-PRO">[GUI-REPOSITORY]</a>
<br>
![Tidal-Media-Downloader](https://socialify.git.ci/yaronzz/Tidal-Media-Downloader/image?description=1&font=Rokkitt&forks=1&issues=1&language=1&name=1&owner=1&pattern=Circuit%20Board&stargazers=1&theme=Dark)
<div align="center">
<h1>Tidal-Media-Downloader</h1>
<a href="https://github.com/yaronzz/Tidal-Media-Downloader/blob/master/LICENSE">
@@ -18,27 +22,41 @@
<a href="https://pypi.org/project/tidal-dl/">
<img src="https://img.shields.io/pypi/dm/tidal-dl?label=tidal-dl%20download" alt="">
</a>
<a href="https://github.com/yaronzz/Tidal-Media-Downloader/actions/workflows/build.yml">
<img src="https://github.com/yaronzz/Tidal-Media-Downloader/actions/workflows/build.yml/badge.svg" alt="">
</a>
</div>
<p align="center">
«Tidal-Media-Downloader» is an application that lets you download videos and tracks from Tidal. It supports two version: tidal-dl and tidal-gui. (This repository only contains tidal-dl, and the release isn't the newest gui version.)
<br>
<a href="https://github.com/yaronzz/Tidal-Media-Downloader-PRO/releases">Download</a> |
<a href="https://yaronzz.com/post/tidal_dl_installation/">Documentation</a> |
<a href="https://yaronzz.com/post/tidal_dl_installation_chn/">中文文档</a> |
<a href="https://t.me/Tidal_Media_Downloader">Channel</a>
<a href="https://doc.yaronzz.com/post/tidal_dl_installation/">Documentation</a> |
<a href="https://doc.yaronzz.com/post/tidal_dl_installation_chn/">中文文档</a> |
<br>
</p>
## 📺 Installation
| Name | platform | Install |
| -------------- | --------------------------------- | ------------------------------------------------------------ |
| tidal-gui | Windows | [GUI Repository](https://github.com/yaronzz/Tidal-Media-Downloader-PRO) |
| tidal-dl (cli) | Windows \ Linux \ Macos \ Android | ```pip3 install tidal-dl --upgrade```<br />[Detailed Description](https://yaronzz.com/post/tidal_dl_installation/#Install) |
## 📡 Telegram
```shell
pip3 install tidal-dl --upgrade
```
- [Group](https://t.me/tidal_group) : Feed back
- [Channel](https://t.me/Tidal_Media_Downloader) : Notify the new version
| USE | FUNCTION |
| ----------------------------------------------------- | -------------------------- |
| tidal-dl | Show interactive interface |
| tidal-dl -h | Show help-message |
| tidal-dl -l "https://tidal.com/browse/track/70973230" | Download link |
| tidal-dl -g | Show simple-gui |
If you are using windows system, you can use [tidal-pro](https://github.com/yaronzz/Tidal-Media-Downloader-PRO)
### Nightly Builds
|Download nightly builds from continuous integration: | [![Build Status][Build]][Actions]
|-------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|
[Actions]: https://github.com/yaronzz/Tidal-Media-Downloader/actions
[Build]: https://github.com/yaronzz/Tidal-Media-Downloader/workflows/Tidal%20Media%20Downloader/badge.svg
## 🤖 Features
- Download album \ track \ video \ playlist \ artist-albums
@@ -51,6 +69,8 @@
<img src="https://i.loli.net/2020/08/19/gqW6zHI1SrKlomC.png" alt="image" style="zoom: 50%;" />
![image-20220708105823257](https://s2.loli.net/2022/07/08/vV6HsxugwoDyGr8.png)
![image-20200806013705425](https://i.loli.net/2020/08/06/sPLowIlCGyOdpVN.png)
## Settings - Possible Tags
@@ -73,6 +93,7 @@
| {NumberOfVolumes} | 1 |
| {ReleaseDate} | 1963-03-22 |
| {RecordType} | ALBUM |
| {None} | |
### Track
@@ -80,6 +101,7 @@
| ----------------- | ------------------------------------------ |
| {TrackNumber} | 01 |
| {ArtistName} | The Beatles |
| {ArtistsName} | The Beatles |
| {TrackTitle} | I Saw Her Standing There (Remastered 2009) |
| {ExplicitFlag} | (*Explicit*) |
| {AlbumYear} | 1963 |
@@ -87,6 +109,19 @@
| {AudioQuality} | LOSSLESS |
| {DurationSeconds} | 173 |
| {Duration} | 02:53 |
| {TrackID} | 55163244 |
### Video
| Tag | Example Value |
| ----------------- | ------------------------------------------ |
| {VideoNumber} | 00 |
| {ArtistName} | DMX |
| {ArtistsName} | DMX, Westside Gunn |
| {VideoTitle} | Hood Blues |
| {ExplicitFlag} | (*Explicit*) |
| {VideoYear} | 2021 |
| {TrackID} | 188932980 |
## ☕ Support
@@ -96,6 +131,7 @@ If you really like my projects and want to support me, you can buy me a coffee a
## 🎂 Contributors
This project exists thanks to all the people who contribute.
<a href="https://github.com/yaronzz/Tidal-Media-Downloader/graphs/contributors"><img src="https://contributors-img.web.app/image?repo=yaronzz/Tidal-Media-Downloader" /></a>
## 🎨 Libraries and reference
@@ -118,4 +154,3 @@ pip3 uninstall tidal-dl
pip3 install -r requirements.txt --user
python3 setup.py install
```
-32
View File
@@ -1,32 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : __init__.py
@Date : 2021/05/08
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
import sys
from PyQt5.QtWidgets import QApplication
from tidal_gui import theme
from tidal_gui.viewModel.loginModel import LoginModel
from tidal_gui.viewModel.mainModel import MainModel
def main():
qss = theme.getThemeQssContent()
app = QApplication(sys.argv)
app.setStyleSheet(qss)
mainView = MainModel()
mainView.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
@@ -1,10 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : __init__.py
@Date : 2021/05/08
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
@@ -1,19 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : checkBox.py
@Date : 2021/05/08
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtWidgets import QCheckBox
class CheckBox(QCheckBox):
def __init__(self, text: str = "", checked: bool = False):
super(CheckBox, self).__init__()
self.setChecked(checked)
self.setText(text)
@@ -1,27 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : comboBox.py
@Date : 2021/8/17
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtWidgets import QComboBox, QListView
from PyQt5.QtCore import Qt
class ComboBox(QComboBox):
def __init__(self, items: list):
super(ComboBox, self).__init__()
self.setItems(items)
self.setFixedWidth(200)
self.setView(QListView())
# remove shadow
self.view().window().setWindowFlags(Qt.Popup | Qt.FramelessWindowHint | Qt.NoDropShadowWindowHint)
self.view().window().setAttribute(Qt.WA_TranslucentBackground)
def setItems(self, items):
for item in items:
self.addItem(str(item))
@@ -1,118 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : framelessWidget.py
@Date : 2021/05/08
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtGui import QMouseEvent
from PyQt5.QtWidgets import QWidget, QGridLayout, QHBoxLayout
from tidal_gui.control.pushButton import PushButton
from tidal_gui.style import ButtonStyle
class FramelessWidget(QWidget):
def __init__(self):
super(FramelessWidget, self).__init__()
self.setWindowFlags(Qt.FramelessWindowHint)
self.borderWidget = QWidget()
self.borderWidget.setObjectName("widgetMain")
self.borderWidget.setStyleSheet("QWidget#widgetMain{border: 1px solid #000000;};")
self.contentGrid = QGridLayout()
self.contentGrid.setContentsMargins(1, 1, 1, 1)
self.windowBtnGrid = self.__createWindowsButtonLayout__()
self.enableMove = True
self.validMoveWidget = None
self.clickPos = None
self.grid = QGridLayout()
self.grid.setSpacing(0)
self.grid.setContentsMargins(0, 0, 0, 0)
self.grid.addWidget(self.borderWidget, 0, 0)
self.grid.addLayout(self.contentGrid, 0, 0)
self.setLayout(self.grid)
def __showMaxWindows__(self):
if self.windowState() == Qt.WindowMaximized:
self.showNormal()
else:
self.showMaximized()
def __createWindowsButtonLayout__(self):
self.closeBtn = PushButton('', ButtonStyle.CloseWindow)
self.maxBtn = PushButton('', ButtonStyle.MaxWindow)
self.minBtn = PushButton('', ButtonStyle.MinWindow)
self.closeBtn.clicked.connect(self.close)
self.minBtn.clicked.connect(self.showMinimized)
self.maxBtn.clicked.connect(self.__showMaxWindows__)
layout = QHBoxLayout()
layout.setSpacing(0)
layout.setContentsMargins(1, 1, 1, 1)
layout.addWidget(self.minBtn)
layout.addWidget(self.maxBtn)
layout.addWidget(self.closeBtn)
return layout
def __clickInValidMoveWidget__(self, x=-1, y=-1) -> bool:
if self.validMoveWidget is None:
return True
if x == -1 and y == -1:
x = self.clickPos.x()
y = self.clickPos.y()
pos = self.validMoveWidget.pos()
if x < pos.x() or x > pos.x() + self.validMoveWidget.width():
return False
if y < pos.y() or y > pos.y() + self.validMoveWidget.height():
return False
return True
def mousePressEvent(self, e: QMouseEvent):
if e.button() == Qt.LeftButton:
self.clickPos = e.pos()
def mouseReleaseEvent(self, e: QMouseEvent):
if e.button() == Qt.LeftButton:
self.clickPos = QPoint(-1, -1)
def mouseMoveEvent(self, e: QMouseEvent):
if not self.enableMove:
return
if Qt.LeftButton & e.buttons():
if self.__clickInValidMoveWidget__() and self.clickPos:
self.move(e.pos() + self.pos() - self.clickPos)
def mouseDoubleClickEvent(self, e: QMouseEvent):
if self.maxBtn.isHidden():
return
if Qt.LeftButton & e.buttons():
if self.__clickInValidMoveWidget__(e.x(), e.y()):
self.__showMaxWindows__()
def getGrid(self):
return self.contentGrid
def disableMove(self):
self.enableMove = False
def setValidMoveWidget(self, widget):
self.validMoveWidget = widget
def setWindowButton(self, showClose=True, showMin=True, showMax=True):
if not showMax:
self.maxBtn.hide()
if not showMin:
self.minBtn.hide()
if not showClose:
self.closeBtn.hide()
self.grid.addLayout(self.windowBtnGrid, 0, 0, Qt.AlignTop | Qt.AlignRight)
@@ -1,20 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : label.py
@Date : 2021/05/08
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtWidgets import QLabel
from tidal_gui.style import LabelStyle
class Label(QLabel):
def __init__(self, text: str = "", style: LabelStyle = LabelStyle.Default):
super(Label, self).__init__()
self.setText(text)
self.setObjectName(style.name + "Label")
@@ -1,25 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : layout.py
@Date : 2021/8/13
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout
def createHBoxLayout(widgets):
layout = QHBoxLayout()
for item in widgets:
layout.addWidget(item)
return layout
def createVBoxLayout(widgets):
layout = QVBoxLayout()
for item in widgets:
layout.addWidget(item)
return layout
@@ -1,20 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : line.py
@Date : 2021/8/17
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtWidgets import QFrame
class Line(QFrame):
def __init__(self, shape: str = 'V'):
super(Line, self).__init__()
self.setFrameShape(QFrame.VLine if shape == 'V' else QFrame.HLine)
self.setFrameShadow(QFrame.Sunken)
self.setObjectName('VLineQFrame' if shape == 'V' else 'HLineQFrame')
@@ -1,17 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : lineEdit.py
@Date : 2021/05/08
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtWidgets import QLineEdit
class LineEdit(QLineEdit):
def __init__(self, placeholderText: str = ""):
super(LineEdit, self).__init__()
self.setPlaceholderText(placeholderText)
@@ -1,25 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : listWidget.py
@Date : 2021/8/17
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtCore import QSize
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QListWidget, QListWidgetItem
from tidal_gui.style import ListWidgetStyle
class ListWidget(QListWidget):
def __init__(self, style: ListWidgetStyle = ListWidgetStyle.Default):
super(ListWidget, self).__init__()
self.setObjectName(style.name + "ListWidget")
def addIConTextItem(self, iconUrl: str, text: str):
self.addItem(QListWidgetItem(QIcon(iconUrl), text))
@@ -1,32 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : pushButton.py
@Date : 2021/05/08
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QPushButton
from tidal_gui.style import ButtonStyle
class PushButton(QPushButton):
def __init__(self,
text: str = '',
style: ButtonStyle = ButtonStyle.Default,
width=0,
iconUrl=''):
super(PushButton, self).__init__()
self.setText(text)
self.setObjectName(style.name + "PushButton")
if width > 0:
self.setFixedWidth(width)
if iconUrl != '':
self.setIcon(QIcon(iconUrl))
@@ -1,48 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : tableView.py
@Date : 2021/9/10
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QTableView, QTableWidgetItem, QAbstractItemView
class TableView(QTableView):
def __init__(self, columnNames: list, rowCount: int = 20):
super(TableView, self).__init__()
self._model = QStandardItemModel()
self._model.setColumnCount(len(columnNames))
self._model.setRowCount(rowCount)
for index, name in enumerate(columnNames):
self._model.setHeaderData(index, Qt.Horizontal, name)
self.setModel(self._model)
# self.setHorizontalHeaderItem(index, QTableWidgetItem(name))
# for index in range(0, rowCount):
# self.setRowHeight(index, 50)
self.setShowGrid(False)
self.verticalHeader().setVisible(False)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setSelectionMode(QAbstractItemView.SingleSelection)
self.horizontalHeader().setStretchLastSection(True)
self.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.setFocusPolicy(Qt.NoFocus)
def addItem(self, rowIdx: int, colIdx: int, text: str):
item = QStandardItem(text)
item.setTextAlignment(Qt.AlignCenter)
self._model.setItem(rowIdx, colIdx, item)
#
# def addWidgetItem(self, rowIdx: int, colIdx: int, widget):
# self.setCellWidget(rowIdx, colIdx, widget)
@@ -1,56 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : tableWidget.py
@Date : 2021/8/18
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QAbstractItemView
class TableWidget(QTableWidget):
def __init__(self, columnNames: list, rowCount: int = 20):
super(TableWidget, self).__init__()
self.setColumnCount(len(columnNames))
self.setRowCount(rowCount)
for index, name in enumerate(columnNames):
self.setHorizontalHeaderItem(index, QTableWidgetItem(name))
for index in range(0, rowCount):
self.setRowHeight(index, 50)
self.setShowGrid(False)
self.verticalHeader().setVisible(False)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setSelectionMode(QAbstractItemView.SingleSelection)
self.horizontalHeader().setStretchLastSection(True)
self.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.setFocusPolicy(Qt.NoFocus)
def changeRowCount(self, rows: int):
if rows != self.rowCount():
self.setRowCount(rows)
for index in range(0, rows):
self.setRowHeight(index, 50)
def addItem(self, rowIdx: int, colIdx: int, text: str):
item = QTableWidgetItem(text)
item.setTextAlignment(Qt.AlignCenter)
self.setItem(rowIdx, colIdx, item)
def addPicItem(self, rowIdx: int, colIdx: int, url: str):
item = QTableWidgetItem()
item.setTextAlignment(Qt.AlignCenter)
item.setIcon(QIcon(url))
self.setItem(rowIdx, colIdx, item)
def addWidgetItem(self, rowIdx: int, colIdx: int, widget):
self.setCellWidget(rowIdx, colIdx, widget)
-16
View File
@@ -1,16 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : downloader.py
@Date : 2021/09/15
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
class DownloaderImp():
pass
downloadImp = DownloaderImp()
@@ -1,4 +0,0 @@
@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629184159878" class="icon" viewBox="0 0 1092 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="23123" xmlns:xlink="http://www.w3.org/1999/xlink" width="136.5" height="128"><defs><style type="text/css"></style></defs><path d="M538.624 1017.344L0.580267 405.162667 212.445867 0h652.356266L1076.565333 405.162667z" fill="#46F256" p-id="23124"></path><path d="M538.624 748.6464l-317.44-351.607467 67.618133-61.098666 249.787734 276.718933 249.821866-276.6848 67.618134 61.064533z" fill="#000000" p-id="23125"></path></svg>

Before

Width:  |  Height:  |  Size: 673 B

@@ -1,4 +0,0 @@
@@ -1 +0,0 @@
<svg t="1629268466285" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="18338" width="128" height="128"><path d="M294.314667 0L242.432 119.424H165.418667v107.648h29.653333L225.152 418.133333H178.005333l62.293334 351.146667 40.021333-0.426667 40.192 255.146667h380.501333l2.645334-17.066667 37.546666-238.08 37.888 0.426667 62.293334-351.189333h-45.056l30.08-191.018667h32.256V119.466667h-81.834667L724.906667 0H294.314667z m22.528 34.346667h385.834666l32.896 75.946666H283.818667l33.024-75.946666z m-117.333334 119.338666H824.32v39.253334H199.509333v-39.253334z m19.328 298.581334h581.76l-50.176 282.453333-241.024-2.56-240.469333 2.56-50.090667-282.453333z" p-id="18339" fill="#ffffff"></path></svg>

Before

Width:  |  Height:  |  Size: 743 B

@@ -1,5 +0,0 @@
<svg fill="#ffffff" t="1606188206696" class="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="2750" width="16" height="16">
<path d="M376.123077 836.923077L51.2 510.030769c-11.815385-11.815385-11.815385-31.507692 0-43.323077l43.323077-43.323077c11.815385-11.815385 31.507692-11.815385 43.323077 0L382.030769 669.538462c7.876923 7.876923 21.661538 7.876923 29.538462 0L890.092308 187.076923c11.815385-11.815385 31.507692-11.815385 43.323077 0l43.323077 43.323077c11.815385 11.815385 11.815385 31.507692 0 43.323077L419.446154 836.923077c-11.815385 13.784615-31.507692 13.784615-43.323077 0z"
p-id="2751"></path>
</svg>

Before

Width:  |  Height:  |  Size: 672 B

@@ -1,6 +0,0 @@
<!-- <svg t="1605685211717" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1511"
width="150" height="150">
<path d="M316.16 366.506667L512 561.92l195.84-195.413333L768 426.666667l-256 256-256-256z" fill="#cbcbcb"
p-id="1512"></path>
</svg> -->
<svg t="1629251448482" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1609" width="128" height="128"><path d="M179.758545 374.008242a31.030303 31.030303 0 0 1 43.876849 0L512 662.372848l288.364606-288.364606a31.030303 31.030303 0 0 1 43.876849 43.876849l-310.303031 310.30303a31.030303 31.030303 0 0 1-43.876848 0l-310.303031-310.30303a31.030303 31.030303 0 0 1 0-43.876849z" p-id="1610" fill="#cbcbcb"></path></svg>

Before

Width:  |  Height:  |  Size: 769 B

@@ -1,6 +0,0 @@
<!-- <svg t="1605685211717" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1511"
width="150" height="150">
<path d="M316.16 366.506667L512 561.92l195.84-195.413333L768 426.666667l-256 256-256-256z" fill="#326cf3"
p-id="1512"></path>
</svg> -->
<svg t="1629251448482" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1609" width="128" height="128"><path d="M179.758545 374.008242a31.030303 31.030303 0 0 1 43.876849 0L512 662.372848l288.364606-288.364606a31.030303 31.030303 0 0 1 43.876849 43.876849l-310.303031 310.30303a31.030303 31.030303 0 0 1-43.876848 0l-310.303031-310.30303a31.030303 31.030303 0 0 1 0-43.876849z" p-id="1610" fill="#326cf3"></path></svg>

Before

Width:  |  Height:  |  Size: 769 B

@@ -1 +0,0 @@
<svg t="1629268481541" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="19187" width="128" height="128"><path d="M512.032 831.904c-19.168 0-38.304-9.92-58.144-29.76-7.808-7.808-7.808-20.48 0-28.288s20.48-7.808 28.288 0C494.368 786.08 504.16 792 512.032 792s17.664-5.92 29.856-18.144c7.808-7.808 20.48-7.808 28.288 0s7.808 20.48 0 28.288c-19.84 19.84-38.976 29.76-58.144 29.76z m-512-306.4c0 49.888 4.256 95.136 12.8 135.68s20.544 75.744 36 105.536 35.008 55.904 58.656 78.336 49.344 40.928 77.056 55.456c27.744 14.528 59.456 26.304 95.2 35.264S351.84 951.04 388.8 954.624 466.496 960 510.944 960c44.448 0 85.248-1.792 122.4-5.376s73.6-9.856 109.344-18.848c35.744-8.96 67.552-20.736 95.456-35.264s53.792-33.024 77.6-55.456c23.808-22.432 43.456-48.544 58.944-78.336s27.552-64.96 36.256-105.536c8.704-40.576 13.056-85.792 13.056-135.68 0-89.376-27.744-166.368-83.2-230.976 3.2-8.608 5.952-18.496 8.256-29.6s4.544-26.816 6.656-47.104c2.144-20.288 1.344-43.712-2.4-70.272S942.56 93.888 932.256 66.24l-8-1.632c-5.344-1.088-14.048-0.704-26.144 1.088s-26.208 5.024-42.4 9.696-37.056 13.92-62.656 27.744-52.608 31.328-81.056 52.512c-48.352-14.72-115.008-30.112-200-30.112s-151.808 15.392-200.544 30.112c-28.448-21.184-55.552-38.592-81.344-52.224s-46.4-22.976-61.856-28c-15.456-5.024-29.792-8.256-42.944-9.696s-21.6-1.888-25.344-1.344c-3.744 0.544-6.496 1.152-8.256 1.888-10.304 27.648-17.408 54.752-21.344 81.312s-4.8 49.888-2.656 69.984c2.144 20.096 4.448 35.904 6.944 47.392S80 286.304 83.2 294.56C27.744 358.816 0 435.808 0 525.536z m136.544 113.888c0-58.016 21.344-110.624 64-157.856 12.8-14.4 27.648-25.312 44.544-32.704s36.096-11.616 57.6-12.608 42.048-0.8 61.6 0.608 43.744 3.296 72.544 5.696 53.696 3.616 74.656 3.616c20.96 0 45.856-1.184 74.656-3.616s52.992-4.288 72.544-5.696c19.552-1.408 40.096-1.6 61.6-0.608s40.8 5.216 57.856 12.608c17.056 7.392 32 18.304 44.8 32.704 42.656 47.232 64 99.84 64 157.856 0 34.016-3.552 64.32-10.656 90.944s-16.096 48.928-26.944 66.912c-10.848 18.016-26.048 33.216-45.6 45.632s-38.496 22.016-56.8 28.8c-18.304 6.784-41.952 12.096-70.944 15.904s-54.944 6.112-77.856 6.912c-22.944 0.8-51.808 1.216-86.656 1.216s-63.648-0.416-86.4-1.216c-22.752-0.8-48.608-3.104-77.6-6.912s-52.608-9.12-70.944-15.904c-18.304-6.816-37.248-16.416-56.8-28.8s-34.752-27.616-45.6-45.632c-10.848-18.016-19.84-40.32-26.944-66.912s-10.656-56.928-10.656-90.944zM256.032 608c0-53.024 28.64-96 64-96s64 42.976 64 96-28.64 96-64 96-64-42.976-64-96z m384 0c0-53.024 28.64-96 64-96s64 42.976 64 96-28.64 96-64 96-64-42.976-64-96z" p-id="19188"></path></svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

@@ -1 +0,0 @@
<svg t="1629270772080" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1817" width="128" height="128"><path d="M658.059636 187.826424a31.030303 31.030303 0 0 1 0 43.876849l-288.364606 288.364606 288.364606 288.364606a31.030303 31.030303 0 0 1-43.876848 43.876848l-310.30303-310.30303a31.030303 31.030303 0 0 1 0-43.876848l310.30303-310.303031a31.030303 31.030303 0 0 1 43.876848 0z" p-id="1818"></path></svg>

Before

Width:  |  Height:  |  Size: 452 B

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629182866847" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22424" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M938.666667 682.666667v170.666666a85.333333 85.333333 0 0 1-85.333334 85.333334H170.666667a85.333333 85.333333 0 0 1-85.333334-85.333334v-170.666666h85.333334v170.666666h682.666666v-170.666666h85.333334z m-384-145.664l140.501333-140.501334 60.330667 60.330667L512 700.330667l-243.498667-243.498667 60.330667-60.330667L469.333333 537.002667V85.333333h85.333334v451.669334z" p-id="22425" fill="#ffffff"></path></svg>

Before

Width:  |  Height:  |  Size: 792 B

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629183863957" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22616" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M938.666667 682.666667v170.666666a85.333333 85.333333 0 0 1-85.333334 85.333334H170.666667a85.333333 85.333333 0 0 1-85.333334-85.333334v-170.666666h85.333334v170.666666h682.666666v-170.666666h85.333334z m-384-145.664l140.501333-140.501334 60.330667 60.330667L512 700.330667l-243.498667-243.498667 60.330667-60.330667L469.333333 537.002667V85.333333h85.333334v451.669334z" p-id="22617" fill="#e6e6e6"></path></svg>

Before

Width:  |  Height:  |  Size: 792 B

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629182847499" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22040" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M512 981.333333C252.8 981.333333 42.666667 771.2 42.666667 512S252.8 42.666667 512 42.666667s469.333333 210.133333 469.333333 469.333333-210.133333 469.333333-469.333333 469.333333z m0-85.333333a384 384 0 1 0 0-768 384 384 0 0 0 0 768z m42.837333-298.752h42.624v85.333333h-170.666666v-85.333333h42.666666v-85.333333h-42.666666v-85.333334h128v170.666667z m-42.837333-213.333333a42.666667 42.666667 0 1 1 0-85.333334 42.666667 42.666667 0 0 1 0 85.333334z" p-id="22041" fill="#ffffff"></path></svg>

Before

Width:  |  Height:  |  Size: 874 B

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629181942259" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="21410" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M696.32 635.989333l229.845333 229.845334-60.330666 60.330666-229.845334-229.845333a341.333333 341.333333 0 1 1 60.330667-60.330667zM426.666667 682.666667a256 256 0 1 0 0-512 256 256 0 0 0 0 512z" p-id="21411" fill="#ffffff"></path></svg>

Before

Width:  |  Height:  |  Size: 615 B

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1629182857650" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22232" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M890.581333 797.013333l-94.592 94.592-121.088-33.706666-34.602666 14.250666L578.133333 981.333333h-133.76l-61.824-109.525333-34.56-14.506667-121.088 33.322667-94.549333-94.549333 33.706667-121.088-14.250667-34.602667L42.666667 578.133333v-133.76l109.568-61.824 14.506666-34.56-33.322666-121.088 94.506666-94.506666 121.088 33.749333 34.56-14.250667L445.696 42.666667h133.802667l61.824 109.568 34.56 14.506666 121.045333-33.322666 94.72 94.506666-33.792 121.130667 14.293333 34.56L981.333333 445.738667v133.802666l-109.525333 61.781334-14.506667 34.688 33.28 121.045333z m-123.392-126.805333l37.205334-88.832L896 529.664v-34.304l-91.605333-52.053333-36.650667-88.874667 28.245333-101.333333-24.277333-24.234667-101.674667 27.946667-88.746666-37.205334L529.621333 128h-34.304l-52.053333 91.605333-88.874667 36.650667-101.376-28.288-24.149333 24.149333 27.946667 101.674667-37.205334 88.746667L128 494.208v34.346667l91.52 52.138666 36.650667 88.874667-28.245334 101.376 24.192 24.192 101.674667-27.946667 88.746667 37.205334 51.626666 91.562666h34.346667l52.138667-91.52 88.874666-36.650666 101.376 28.245333 24.234667-24.234667-27.946667-101.589333zM512 682.666667a170.666667 170.666667 0 1 1 0-341.333334 170.666667 170.666667 0 0 1 0 341.333334z m0-85.333334a85.333333 85.333333 0 1 0 0-170.666666 85.333333 85.333333 0 0 0 0 170.666666z" p-id="22233" fill="#ffffff"></path></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

@@ -1 +0,0 @@
<svg t="1629268420515" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16731" width="128" height="128"><path d="M350.8 591.8c-7 38.4-34.8 217.4-43 268-0.6 3.6-2 5-6 5H152.6c-15.2 0-26.2-13.2-24.2-27.8L245.6 93.2c3-19.2 20.2-33.8 40-33.8 304.6 0 330.2-7.4 408 22.8 120.2 46.6 131.2 159 88 280.6-43 125.2-145 179-280.2 180.6-86.8 1.4-139-14-150.6 48.4zM842.2 304c-3.6-2.6-5-3.6-6 2.6-4 22.8-10.2 45-17.6 67.2-79.8 227.6-301 207.8-409 207.8-12.2 0-20.2 6.6-21.8 18.8-45.2 280.8-54.2 339.4-54.2 339.4-2 14.2 7 25.8 21.2 25.8h127c17.2 0 31.4-12.6 34.8-29.8 1.4-10.8-2.2 12.2 28.8-182.6 9.2-44 28.6-39.4 58.6-39.4 142 0 252.8-57.6 285.8-224.6 13-69.6 9.2-142.8-47.6-185.2z" p-id="16732" fill="#ffffff"></path></svg>

Before

Width:  |  Height:  |  Size: 753 B

@@ -1 +0,0 @@
<svg t="1629270798317" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1968" width="128" height="128"><path d="M365.940364 187.826424a31.030303 31.030303 0 0 1 43.876848 0l310.30303 310.303031a31.030303 31.030303 0 0 1 0 43.876848l-310.30303 310.30303a31.030303 31.030303 0 0 1-43.876848-43.876848l288.364606-288.364606-288.364606-288.364606a31.030303 31.030303 0 0 1 0-43.876849z" p-id="1969"></path></svg>

Before

Width:  |  Height:  |  Size: 451 B

@@ -1 +0,0 @@
<svg t="1629269306451" class="icon" viewBox="0 0 1057 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15526" width="128" height="128"><path d="M409.012356 811.965935c-108.676129 0.660645-213.058065-41.851871-289.924129-117.991225A401.242839 401.242839 0 0 1 0.006937 406.594065a401.242839 401.242839 0 0 1 119.015226-287.512775A408.344774 408.344774 0 0 1 409.012356 0.990968a408.344774 408.344774 0 0 1 289.924129 118.05729 401.275871 401.275871 0 0 1 119.08129 287.44671 401.275871 401.275871 0 0 1-119.048258 287.380645 408.344774 408.344774 0 0 1-289.891096 118.090322h-0.066065z m0-695.130838A290.617806 290.617806 0 0 0 201.63584 200.836129a285.563871 285.563871 0 0 0-84.69471 205.625806c0 162.221419 128.495484 289.626839 292.071226 289.626839 163.641806 0 292.13729-127.405419 292.13729-289.560774 0-162.221419-128.495484-289.725935-292.071225-289.725935h-0.066065zM957.942421 1005.799226l-173.980904-171.866839a55.130839 55.130839 0 0 1 0-80.235355c23.221677-22.990452 58.004645-22.990452 81.193291 0l173.947871 171.965936a55.130839 55.130839 0 0 1 0 80.235355 56.419097 56.419097 0 0 1-81.160258 0v-0.099097z" p-id="15527" fill="#ffffff"></path></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

@@ -1 +0,0 @@
<svg t="1629255942168" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8597" width="128" height="128"><path d="M512 0C229.248 0 0 229.248 0 512s229.248 512 512 512 512-229.248 512-512S794.752 0 512 0zM432.64 748.256 197.056 512.64l90.496-90.496 145.056 145.12 307.744-307.744 90.496 90.496L432.64 748.256z" p-id="8598" fill="#2DB84D"></path></svg>

Before

Width:  |  Height:  |  Size: 391 B

@@ -1 +0,0 @@
<svg t="1629255998157" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8792" width="128" height="128"><path d="M512 0C229.248 0 0 229.248 0 512s229.248 512 512 512 512-229.248 512-512S794.752 0 512 0zM320 768 320 256l512.256 256L320 768z" p-id="8793" fill="#00BCD4"></path></svg>

Before

Width:  |  Height:  |  Size: 323 B

@@ -1 +0,0 @@
<svg t="1629256110134" class="icon" viewBox="0 0 1185 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3025" width="128" height="128"><path d="M700.365715 60.074208l468.319709 783.01037a118.307323 118.307323 0 0 1-45.345458 164.539234 127.444603 127.444603 0 0 1-62.324434 16.297089H124.376114A122.739586 122.739586 0 0 1 0 903.567918a117.557248 117.557248 0 0 1 16.706221-60.346963L485.02593 60.210586A126.694528 126.694528 0 0 1 655.020257 16.365278a122.739586 122.739586 0 0 1 45.345458 43.845308zM592.764011 916.046443a80.803561 80.803561 0 1 0-80.80356-80.803561 80.803561 80.803561 0 0 0 80.735372 80.803561z m0-673.567572a95.464122 95.464122 0 0 0-94.373104 106.988006l34.09433 270.640786a61.369793 61.369793 0 0 0 121.103058 0l34.094329-270.640786a95.464122 95.464122 0 0 0-94.373103-106.919818z" p-id="3026" fill="#DB3340"></path></svg>

Before

Width:  |  Height:  |  Size: 857 B

@@ -1 +0,0 @@
<svg t="1629251564375" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1864" width="128" height="128"><path d="M490.061576 311.947636a31.030303 31.030303 0 0 1 43.876848 0l310.303031 310.303031a31.030303 31.030303 0 0 1-43.876849 43.876848L512 377.762909l-288.364606 288.364606a31.030303 31.030303 0 0 1-43.876849-43.876848l310.303031-310.303031z" p-id="1865" fill="#326cf3"></path></svg>

Before

Width:  |  Height:  |  Size: 432 B

@@ -1,5 +0,0 @@
<svg fill="#cbcbcb" t="1605778065489" class="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="6682" width="16" height="16">
<path d="M622.276923 508.061538l257.969231-257.96923c11.815385-11.815385 11.815385-29.538462 0-41.353846l-41.353846-41.353847c-11.815385-11.815385-29.538462-11.815385-41.353846 0L539.569231 425.353846c-7.876923 7.876923-19.692308 7.876923-27.569231 0L254.030769 165.415385c-11.815385-11.815385-29.538462-11.815385-41.353846 0l-41.353846 41.353846c-11.815385 11.815385-11.815385 29.538462 0 41.353846l257.969231 257.969231c7.876923 7.876923 7.876923 19.692308 0 27.56923L169.353846 793.6c-11.815385 11.815385-11.815385 29.538462 0 41.353846l41.353846 41.353846c11.815385 11.815385 29.538462 11.815385 41.353846 0L512 618.338462c7.876923-7.876923 19.692308-7.876923 27.569231 0l257.969231 257.96923c11.815385 11.815385 29.538462 11.815385 41.353846 0l41.353846-41.353846c11.815385-11.815385 11.815385-29.538462 0-41.353846L622.276923 535.630769c-5.907692-7.876923-5.907692-19.692308 0-27.569231z"
p-id="6683"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

@@ -1,5 +0,0 @@
<svg fill="#ffffff" t="1605778065489" class="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="6682" width="16" height="16">
<path d="M622.276923 508.061538l257.969231-257.96923c11.815385-11.815385 11.815385-29.538462 0-41.353846l-41.353846-41.353847c-11.815385-11.815385-29.538462-11.815385-41.353846 0L539.569231 425.353846c-7.876923 7.876923-19.692308 7.876923-27.569231 0L254.030769 165.415385c-11.815385-11.815385-29.538462-11.815385-41.353846 0l-41.353846 41.353846c-11.815385 11.815385-11.815385 29.538462 0 41.353846l257.969231 257.969231c7.876923 7.876923 7.876923 19.692308 0 27.56923L169.353846 793.6c-11.815385 11.815385-11.815385 29.538462 0 41.353846l41.353846 41.353846c11.815385 11.815385 29.538462 11.815385 41.353846 0L512 618.338462c7.876923-7.876923 19.692308-7.876923 27.569231 0l257.969231 257.96923c11.815385 11.815385 29.538462 11.815385 41.353846 0l41.353846-41.353846c11.815385-11.815385 11.815385-29.538462 0-41.353846L622.276923 535.630769c-5.907692-7.876923-5.907692-19.692308 0-27.569231z"
p-id="6683"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

@@ -1,5 +0,0 @@
<svg fill="#cbcbcb" t="1605778299751" class="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="12048" width="16" height="16">
<path d="M170.666667 85.333333h682.666666a85.333333 85.333333 0 0 1 85.333334 85.333334v682.666666a85.333333 85.333333 0 0 1-85.333334 85.333334H170.666667a85.333333 85.333333 0 0 1-85.333334-85.333334V170.666667a85.333333 85.333333 0 0 1 85.333334-85.333334z m0 85.333334v682.666666h682.666666V170.666667H170.666667z"
p-id="12049"></path>
</svg>

Before

Width:  |  Height:  |  Size: 526 B

@@ -1,4 +0,0 @@
<svg fill="#cbcbcb" t="1605777927585" class="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="5690" width="16" height="16">
<path d="M938.666667 469.333333v85.333334H85.333333v-85.333334z" p-id="5691"></path>
</svg>

Before

Width:  |  Height:  |  Size: 260 B

@@ -1,633 +0,0 @@
:root {
--Font_Family: Microsoft YaHei UI;
--Font_Size: 12px;
--Font_Size_TableHeader: 15px;
--Font_Size_PageTitle: 15px;
--Font_Size_HugeTitle: 30px;
--Font_Size_MsgLabel: 15px;
--Color_Default: #ffffff;
--Color_DefaultHover: #f0f0f0;
--Color_DefaultPressed: #ececec;
--Color_DefaultText: #212121;
--Color_Primary: #326cf3;
--Color_PrimaryHover: #477bf4;
--Color_PrimaryPressed: #84a7f8;
--Color_PrimaryText: #ffffff;
--Color_Success: #2db84d;
--Color_SuccessHover: #42bf5f;
--Color_SuccessPressed: #81d494;
--Color_Danger: #db3340;
--Color_DangerHover: #df4853;
--Color_DangerPressed: #e9858c;
--Color_Warning: #e9af20;
--Color_WarningHover: #ebb737;
--Color_WarningPressed: #f2cf79;
--Color_Info: #00bcd4;
--Color_InfoHover: #1ac3d8;
--Color_InfoPressed: #66d7e5;
--Color_Border: #cbcbcb;
--Color_WindowsIcon: #cbcbcb;
--Color_Background: #eeeeee;
--Color_Shadow: #AA000000;
--Color_Transparent: transparent;
--Size_InputPaddingLR: 8px;
--Size_InputPaddingTB: 6px;
--Size_HeaderHeight: 50px;
--Size_ItemHeight: 18px;
--Size_ProgressHeight: 26px;
--Size_ControlHeight: 18px;
--Size_ControlPaddingLR: 8px;
--Size_ControlPaddingTB: 6px;
--Size_IconSize: 24px;
--Size_CornerRadius: 4px;
--Size_CalendarWidth: 287px;
--Size_CalendarHeight: 300px;
}
/* #QSS_START */
* {
font-family: var(--Font_Family);
font-size: var(--Font_Size);
background: var(--Color_Default);
color: var(--Color_DefaultText);
}
/* Widget */
QWidget#MainViewLeftWidget {
background: #000000;
}
QWidget#TestWidget {
background: #000000;
}
QWidget#AboutWidget {
}
/* PushButton Style */
QPushButton {
border-style: solid;
border-width: 1px;
border-color: var(--Color_DefaultPressed);
padding-left: var(--Size_InputPaddingLR);
padding-right: var(--Size_InputPaddingLR);
padding-top: var(--Size_InputPaddingTB);
padding-bottom: var(--Size_InputPaddingTB);
border-radius: var(--Size_CornerRadius);
color: var(--Color_DefaultText);
background: var(--Color_Default);
}
QPushButton::hover {
color: var(--Color_DefaultText);
background: var(--Color_DefaultHover);
}
QPushButton::pressed {
color: var(--Color_DefaultText);
background: var(--Color_DefaultPressed);
}
QPushButton#PrimaryPushButton {
border-color: var(--Color_PrimaryPressed);
color: var(--Color_PrimaryText);
background: var(--Color_Primary);
}
QPushButton#PrimaryPushButton::hover {
background: var(--Color_PrimaryHover);
}
QPushButton#PrimaryPushButton::pressed {
background: var(--Color_PrimaryPressed);
}
QPushButton#SuccessPushButton {
border-color: var(--Color_SuccessPressed);
color: var(--Color_PrimaryText);
background: var(--Color_Success);
}
QPushButton#SuccessPushButton::hover {
background: var(--Color_SuccessHover);
}
QPushButton#SuccessPushButton::pressed {
background: var(--Color_SuccessPressed);
}
QPushButton#DangerPushButton {
border-color: var(--Color_DangerPressed);
color: var(--Color_PrimaryText);
background: var(--Color_Danger);
}
QPushButton#DangerPushButton::hover {
background: var(--Color_DangerHover);
}
QPushButton#DangerPushButton::pressed {
background: var(--Color_DangerPressed);
}
QPushButton#WarningPushButton {
border-color: var(--Color_WarningPressed);
color: var(--Color_PrimaryText);
background: var(--Color_Warning);
}
QPushButton#WarningPushButton::hover {
background: var(--Color_WarningHover);
}
QPushButton#WarningPushButton::pressed {
background: var(--Color_WarningPressed);
}
QPushButton#InfoPushButton {
border-color: var(--Color_InfoPressed);
color: var(--Color_PrimaryText);
background: var(--Color_Info);
}
QPushButton#InfoPushButton::hover {
background: var(--Color_InfoHover);
}
QPushButton#InfoPushButton::pressed {
background: var(--Color_InfoPressed);
}
/* Software Buton */
QPushButton#SoftwareIconPushButton {
border-style: none;
border-radius: 0px;
height: 26;
width: 26;
background: var(--Color_Transparent);
image: url($PACKAGE_PATH$/resource/svg/V.svg)
}
QPushButton#SoftwareIconPushButton::hover {
image: url($PACKAGE_PATH$/resource/svg/V.svg)
}
QPushButton#SoftwareIconPushButton::pressed {
image: url($PACKAGE_PATH$/resource/svg/V.svg)
}
/* Windows Buton */
QPushButton#CloseWindowPushButton {
border-style: none;
border-radius: 0px;
background: var(--Color_Transparent);
image: url($PACKAGE_PATH$/resource/svg/windows/close.svg)
}
QPushButton#CloseWindowPushButton::hover {
background: #ff1a1a;
image: url($PACKAGE_PATH$/resource/svg/windows/closeHover.svg)
}
QPushButton#CloseWindowPushButton::pressed {
background: #ff6666;
image: url($PACKAGE_PATH$/resource/svg/windows/closeHover.svg)
}
QPushButton#MaxWindowPushButton {
border-style: none;
border-radius: 0px;
background: var(--Color_Transparent);
image: url($PACKAGE_PATH$/resource/svg/windows/max.svg)
}
QPushButton#MaxWindowPushButton::hover {
background: var(--Color_DefaultHover);
}
QPushButton#MaxWindowPushButton::pressed {
background: var(var(--Color_DefaultPressed));
}
QPushButton#MinWindowPushButton {
border-style: none;
border-radius: 0px;
background: var(--Color_Transparent);
image: url($PACKAGE_PATH$/resource/svg/windows/min.svg)
}
QPushButton#MinWindowPushButton::hover {
background: var(--Color_DefaultHover);
}
QPushButton#MinWindowPushButton::pressed {
background: var(var(--Color_DefaultPressed));
}
/* Icon Button */
QPushButton#SearchIconPushButton {
border-style: none;
border-radius: 0px;
height: 26;
width: 26;
background: var(--Color_Transparent);
image: url($PACKAGE_PATH$/resource/svg/leftTab/search.svg)
}
QPushButton#SearchIconPushButton::hover {
image: url($PACKAGE_PATH$/resource/svg/leftTab/search.svg)
}
QPushButton#SearchIconPushButton::pressed {
image: url($PACKAGE_PATH$/resource/svg/leftTab/search.svg)
}
QPushButton#TaskIconPushButton {
border-style: none;
border-radius: 0px;
height: 26;
width: 26;
background: var(--Color_Transparent);
image: url($PACKAGE_PATH$/resource/svg/leftTab/download.svg)
}
QPushButton#TaskIconPushButton::hover {
image: url($PACKAGE_PATH$/resource/svg/leftTab/downloadHover.svg)
}
QPushButton#TaskIconPushButton::pressed {
image: url($PACKAGE_PATH$/resource/svg/leftTab/downloadHover.svg)
}
QPushButton#SettingsIconPushButton {
border-style: none;
border-radius: 0px;
height: 26;
width: 26;
background: var(--Color_Transparent);
image: url($PACKAGE_PATH$/resource/svg/leftTab/settings.svg)
}
QPushButton#SettingsIconPushButton::hover {
image: url($PACKAGE_PATH$/resource/svg/leftTab/settings.svg)
}
QPushButton#SettingsIconPushButton::pressed {
image: url($PACKAGE_PATH$/resource/svg/leftTab/settings.svg)
}
QPushButton#AboutIconPushButton {
border-style: none;
border-radius: 0px;
height: 26;
width: 26;
background: var(--Color_Transparent);
image: url($PACKAGE_PATH$/resource/svg/leftTab/info.svg)
}
QPushButton#AboutIconPushButton::hover {
image: url($PACKAGE_PATH$/resource/svg/leftTab/info.svg)
}
QPushButton#AboutIconPushButton::pressed {
image: url($PACKAGE_PATH$/resource/svg/leftTab/info.svg)
}
QPushButton#PrePagePushButton {
border-style: none;
border-radius: 0px;
height: 18;
width: 18;
background: var(--Color_DefaultHover);
image: url($PACKAGE_PATH$/resource/svg/left.svg)
}
QPushButton#PrePagePushButton::hover {
image: url($PACKAGE_PATH$/resource/svg/left.svg)
}
QPushButton#PrePagePushButton::pressed {
image: url($PACKAGE_PATH$/resource/svg/left.svg)
}
QPushButton#NextPagePushButton {
border-style: none;
border-radius: 0px;
height: 18;
width: 18;
background: var(--Color_DefaultHover);
image: url($PACKAGE_PATH$/resource/svg/right.svg)
}
QPushButton#NextPagePushButton::hover {
image: url($PACKAGE_PATH$/resource/svg/right.svg)
}
QPushButton#NextPagePushButton::pressed {
image: url($PACKAGE_PATH$/resource/svg/right.svg)
}
/* LineEdit Style */
QLineEdit {
border-style: solid;
border-width: 1px;
border-color: var(--Color_Border);
padding-left: var(--Size_InputPaddingLR);
padding-right: var(--Size_InputPaddingLR);
padding-top: var(--Size_InputPaddingTB);
padding-bottom: var(--Size_InputPaddingTB);
border-radius: var(--Size_CornerRadius);
min-height: var(--Size_ControlHeight);
color: var(--Color_DefaultText);
background: var(--Color_Default);
}
QLineEdit::hover {
border-color: var(--Color_Primary);
}
QLineEdit::focus {
border-color: var(--Color_Primary);
}
/* CheckBox Style */
QCheckBox::indicator {
width: 14px;
height: 14px;
padding: 2px;
border: 1px solid var(--Color_Border);
border-radius: 2px;
}
QCheckBox::indicator::unchecked:hover {
border: 1px solid var(--Color_PrimaryHover);
}
QCheckBox::indicator::checked {
background: var(--Color_Primary);
image: url($PACKAGE_PATH$/resource/svg/check.svg);
border: 1px solid var(--Color_Primary);
}
/* TabWidget */
QTabWidget::pane {
border:none;
border-top: 1px solid var(--Color_Border);
}
QTabBar::tab {
border:none;
padding-left: 10px;
padding-right: 10px;
padding-bottom: 3px;
font-size: var(--Font_Size_TableHeader);
font-weight: bold;
min-width: 70;
}
QTabBar::tab:selected {
color: var(--Color_Primary);
border-color: var(--Color_Primary);
border-style: solid;
border-bottom-width: 3px;
}
/* Label */
QLabel#PageTitleLabel {
font-size: var(--Font_Size_PageTitle);
font-weight: bold;
}
QLabel#PageSubTitleLabel {
font-size: var(--Font_Size_PageTitle);
}
QLabel#HugeTitleLabel {
font-size: var(--Font_Size_HugeTitle);
font-weight: bold;
}
QLabel#LogoBottomLabel {
font-size: var(--Font_Size_MsgLabel);
color: #ffffff;
}
/* QFrame */
QFrame#VLineQFrame
{
border-top-style: none;
border-bottom-style: none;
border-right-style: none;
border-left: 1px solid var(--Color_Border);
}
QFrame#HLineQFrame
{
border-top: 1px solid var(--Color_Border);
border-bottom-style: none;
border-right-style: none;
border-left-style: none;
}
/* QComboBox */
QComboBox {
border-style: solid;
border-width: 1px;
border-color: var(--Color_Border);
padding-left: var(--Size_InputPaddingLR);
padding-right: var(--Size_InputPaddingLR);
padding-top: var(--Size_InputPaddingTB);
padding-bottom: var(--Size_InputPaddingTB);
border-radius: var(--Size_CornerRadius);
min-height: var(--Size_ControlHeight);
color: var(--Color_DefaultText);
background: var(--Color_Default);
}
QComboBox::hover {
border-color: var(--Color_Primary);
}
QComboBox::focus {
border-color: var(--Color_Primary);
}
QComboBox::drop-down {
subcontrol-position:center right;
margin-right: 15px;
border-left-style: none;
}
QComboBox::down-arrow {
image: url($PACKAGE_PATH$/resource/svg/down.svg);
width : 24px;
height : 24px;
}
QComboBox::down-arrow:hover {
image: url($PACKAGE_PATH$/resource/svg/downHover.svg);
}
QComboBox::down-arrow:on {
image: url($PACKAGE_PATH$/resource/svg/upHover.svg);
}
QComboBox QAbstractItemView {
margin-top:5px;
border:1px solid var(--Color_Primary);
outline:none;
}
QComboBox QAbstractItemView::item {
height: var(--Size_ItemHeight);
padding-top: var(--Size_InputPaddingTB);
padding-bottom: var(--Size_InputPaddingTB);
}
QComboBox QAbstractItemView::item:selected{
color: var(--Color_PrimaryText);
background: var(--Color_Primary);
}
/* QListWidget */
QListWidget#TaskTabListWidget {
border-style: none;
background: var(--Color_Default);
max-width: 150px;
outline:none;
}
QListWidget#TaskTabListWidget::item
{
height:32px;
padding-left: var(--Size_ControlPaddingLR);
border: none;
border-radius: var(--Size_CornerRadius);
margin-top:5px;
}
QListWidget#TaskTabListWidget::item:hover
{
background: var(--Color_DefaultHover);
color: var(--Color_DefaultText);
}
QListWidget#TaskTabListWidget::item:selected
{
background: var(--Color_Primary);
color: var(--Color_PrimaryText);
}
QListWidget#TaskContentListWidget {
border-style: none;
background: var(--Color_Default);
}
/* QTableWidget */
QTableWidget {
border-left: none;
border-right: none;
border-top: none;
border-bottom: 1px solid var(--Color_Border);
text-align: center;
color: var(--Color_DefaultText);
background: var(--Color_DefaultHover);
padding:5px;
}
QTableWidget::item{
margin-top: 5px;
background: var(--Color_Default);
}
QTableWidget::item:selected{
color: var(--Color_PrimaryText);
background: var(--Color_Primary);
}
QTableWidget QHeaderView::section {
color: var(--Color_DefaultText);
background: var(--Color_DefaultHover);
text-align: center;
height: var(--Size_HeaderHeight);
border: none;
font-size: var(--Font_Size_TableHeader);
font-weight: bold;
}
QTableWidget QScrollBar::vertical{
background:transparent;
width: 4px;
border-radius:6px;
}
QTableWidget QScrollBar::handle{
background: lightgray;
border-radius:6px;
}
QTableWidget QScrollBar::handle:hover{background:gray;}
QTableWidget QScrollBar::sub-line{background:transparent;}
QTableWidget QScrollBar::add-line{background:transparent;}
/* QTableView */
QTableView {
border-left: none;
border-right: none;
border-top: none;
border-bottom: 1px solid var(--Color_Border);
text-align: center;
color: var(--Color_DefaultText);
background: var(--Color_DefaultHover);
padding:5px;
}
QTableView::item{
margin-top: 5px;
background: var(--Color_Default);
}
QTableView::item:selected{
color: var(--Color_PrimaryText);
background: var(--Color_Primary);
}
QTableView QHeaderView::section {
color: var(--Color_DefaultText);
background: var(--Color_DefaultHover);
text-align: center;
height: var(--Size_HeaderHeight);
border: none;
font-size: var(--Font_Size_TableHeader);
font-weight: bold;
}
QTableView QScrollBar::vertical{
background:transparent;
width: 4px;
border-radius:6px;
}
QTableView QScrollBar::handle{
background: lightgray;
border-radius:6px;
}
QTableView QScrollBar::handle:hover{background:gray;}
QTableView QScrollBar::sub-line{background:transparent;}
QTableView QScrollBar::add-line{background:transparent;}
-54
View File
@@ -1,54 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : enum.py
@Date : 2021/05/08
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
'''
from enum import Enum
class ButtonStyle(Enum):
Default = 0,
Primary = 1,
Success = 2,
Danger = 3,
Warning = 4,
Info = 5,
CloseWindow = 6,
MaxWindow = 7,
MinWindow = 8,
SearchIcon = 9,
TaskIcon = 10,
SettingsIcon = 11,
AboutIcon = 12,
SoftwareIcon = 13
PrePage = 14
NextPage = 15
class LabelStyle(Enum):
Default = 0,
PageTitle = 1,
PageSubTitle = 2,
HugeTitle = 3,
LogoBottom = 4,
class ThemeStyle(Enum):
Default = 0,
Dark = 1,
class ListWidgetStyle(Enum):
Default = 0,
TaskTab = 1,
TaskContent = 2,
-60
View File
@@ -1,60 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : qssParse.py
@Date : 2021/05/08
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
import aigpy
from tidal_gui.style import ThemeStyle
def __getParam__(line: str):
key = aigpy.string.getSub(line, "--", ":")
value = aigpy.string.getSub(line, ":", ";")
return key, value
def __parseParamsList__(content: str) -> dict:
globalStr = aigpy.string.getSub(content, ":root", "}")
lines = globalStr.split("\n")
array = {}
for line in lines:
key, value = __getParam__(line)
if key == "" or value == "":
continue
array[key] = value
return array
def __parseQss__(content: str, params: dict) -> str:
content = aigpy.string.getSub(content, "/* #QSS_START */")
for key in params:
content = content.replace("var(--" + key + ")", params[key])
content = content.replace("$PACKAGE_PATH$", getPackagePath())
return content
def __getQss__(filePath: str) -> str:
content = aigpy.file.getContent(filePath)
params = __parseParamsList__(content)
qss = __parseQss__(content, params)
return qss
def getPackagePath():
path = __file__
return aigpy.path.getDirName(path).replace('\\', '/')
def getThemeQssContent(style: ThemeStyle = ThemeStyle.Default):
name = "theme" + style.name + ".qss"
path = getPackagePath() + "/resource/"
return __getQss__(path + name)
-90
View File
@@ -1,90 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : tidalImp.py
@Date : 2021/9/2
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
import time
import requests
import tidal_dl.model
from aigpy.stringHelper import isNull
from tidal_dl import TokenSettings, TOKEN, TidalAPI
class TidalImp(TidalAPI):
def __init__(self):
super(TidalImp, self).__init__()
def loginByConfig(self):
if isNull(TOKEN.accessToken):
return False
msg, check = self.verifyAccessToken(TOKEN.accessToken)
if check:
self.key.countryCode = TOKEN.countryCode
self.key.userId = TOKEN.userid
self.key.accessToken = TOKEN.accessToken
return True
msg, check = self.refreshAccessToken(TOKEN.refreshToken)
if check:
TOKEN.userid = self.key.userId
TOKEN.countryCode = self.key.countryCode
TOKEN.accessToken = self.key.accessToken
TOKEN.expiresAfter = time.time() + int(self.key.expiresIn)
TokenSettings.save(TOKEN)
return True
else:
tmp = TokenSettings() # clears saved tokens
TokenSettings.save(tmp)
return False
def loginByWeb(self):
start = time.time()
elapsed = 0
while elapsed < self.key.authCheckTimeout:
elapsed = time.time() - start
msg, check = self.checkAuthStatus()
if not check:
if msg == "pending":
time.sleep(self.key.authCheckInterval + 1)
continue
return False
if check:
TOKEN.userid = self.key.userId
TOKEN.countryCode = self.key.countryCode
TOKEN.accessToken = self.key.accessToken
TOKEN.refreshToken = self.key.refreshToken
TOKEN.expiresAfter = time.time() + int(self.key.expiresIn)
TokenSettings.save(TOKEN)
return True
return False
@staticmethod
def getArtistsNames(self, artists: list[tidal_dl.model.Artist]):
ret = []
for item in artists:
ret.append(item.name)
return ','.join(ret)
@staticmethod
def getDurationString(seconds: int):
m, s = divmod(seconds, 60)
h, m = divmod(m, 60)
return "%02d:%02d:%02d" % (h, m, s)
def getCoverData(self, sid, width="320", height="320"):
url = self.getCoverUrl(sid, width, height)
try:
respond = requests.get(url)
return respond.content
except:
return ''
tidalImp = TidalImp()
@@ -1,10 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : __init__.py
@Date : 2021/05/11
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
@@ -1,74 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : aboutView.py
@Date : 2021/8/17
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QGridLayout, QHBoxLayout, QLabel
from tidal_gui.control.label import Label
from tidal_gui.control.pushButton import PushButton
from tidal_gui.style import LabelStyle, ButtonStyle
from tidal_gui.theme import getPackagePath
class AboutView(QWidget):
def __init__(self):
super(AboutView, self).__init__()
self.__initView__()
def __initView__(self):
grid = QGridLayout(self)
grid.addWidget(self.__initLogo__(), 0, 0, Qt.AlignLeft)
grid.addLayout(self.__initContent__(), 0, 1)
def __initLogo__(self):
path = getPackagePath() + "/resource/svg/V.svg"
self._logo = QLabel()
self._logo.setPixmap(QPixmap(path))
return self._logo
def __initButton__(self):
path = getPackagePath() + "/resource/svg/"
self._feedbackBtn = PushButton('Feedback', ButtonStyle.Default, iconUrl=path + 'github.svg')
self._buymeacoffeeBtn = PushButton('Buymeacoffee', ButtonStyle.Info, iconUrl=path + 'buymeacoffee.svg')
self._paypalBtn = PushButton('Paypal', ButtonStyle.Primary, iconUrl=path + 'paypal.svg')
layout = QHBoxLayout()
layout.addWidget(self._feedbackBtn)
layout.addWidget(self._buymeacoffeeBtn)
layout.addWidget(self._paypalBtn)
return layout
def __initContent__(self):
self._titleLabel = Label('', LabelStyle.HugeTitle)
self._authorLabel = Label('')
self._versionLabel = Label('')
self._lastVersionLabel = Label('')
layout = QVBoxLayout()
layout.addWidget(self._titleLabel)
layout.addWidget(self._authorLabel)
layout.addWidget(self._versionLabel)
layout.addWidget(self._lastVersionLabel)
layout.addLayout(self.__initButton__())
return layout
def setTitle(self, text: str):
self._titleLabel.setText(text)
def setAuthor(self, text: str):
self._authorLabel.setText('MADE WITH ♥ BY ' + text)
def setVersion(self, text: str):
self._versionLabel.setText('VERSION ' + text)
def setLastVersion(self, text: str):
self._lastVersionLabel.setText('LAST-VERSION ' + text)
@@ -1,156 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : loginView.py
@Date : 2021/04/30
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import *
from tidal_gui.control.checkBox import CheckBox
from tidal_gui.control.framelessWidget import FramelessWidget
from tidal_gui.control.label import Label
from tidal_gui.control.layout import createHBoxLayout
from tidal_gui.control.lineEdit import LineEdit
from tidal_gui.control.pushButton import PushButton
from tidal_gui.style import ButtonStyle, LabelStyle
from tidal_gui.theme import getPackagePath
class LoginView(FramelessWidget):
viewWidth = 650
viewHeight = 400
logoWidth = 300
def __init__(self):
super(LoginView, self).__init__()
self.setFixedSize(self.viewWidth, self.viewHeight)
self.__initView__()
self.setWindowButton(True, False, False)
def __initAccountTab__(self):
self._deviceCodeEdit = LineEdit()
self._confirmBtn = PushButton("LOGIN", ButtonStyle.Primary)
grid = QGridLayout()
grid.setSpacing(15)
grid.setRowStretch(0, 1)
grid.addLayout(createHBoxLayout([Label("DeviceCode"), self._deviceCodeEdit]), 1, 0, 1, 2)
grid.setRowStretch(3, 1)
grid.addWidget(self._confirmBtn, 5, 0, 1, 2)
grid.setRowStretch(6, 1)
widget = QWidget()
widget.setLayout(grid)
return widget
def __initProxyTab__(self):
self._enableProxyCheck = CheckBox('')
self._proxyHostEdit = LineEdit()
self._proxyPortEdit = LineEdit()
self._proxyUserEdit = LineEdit()
self._proxyPwdEdit = LineEdit()
grid = QGridLayout()
grid.setSpacing(8)
grid.setRowStretch(0, 1)
grid.addWidget(Label("HttpProxy"), 1, 0)
grid.addWidget(self._enableProxyCheck, 1, 1)
grid.addWidget(Label("Host"), 2, 0)
grid.addWidget(self._proxyHostEdit, 2, 1)
grid.addWidget(Label("Port"), 3, 0)
grid.addWidget(self._proxyPortEdit, 3, 1)
grid.addWidget(Label("UserName"), 4, 0)
grid.addWidget(self._proxyUserEdit, 4, 1)
grid.addWidget(Label("Password"), 5, 0)
grid.addWidget(self._proxyPwdEdit, 5, 1)
grid.setRowStretch(6, 1)
widget = QWidget()
widget.setLayout(grid)
return widget
def __initIconWidget__(self):
self._icon = Label('')
self._icon.setStyleSheet("QLabel{background-color:rgb(0,0,0);}")
self._icon.setPixmap(QPixmap(getPackagePath() + "/resource/svg/V.svg"))
self._icon.setAlignment(Qt.AlignCenter)
self._iconLabel = Label('', LabelStyle.LogoBottom)
self._iconLabel.setAlignment(Qt.AlignCenter)
self._iconLabel.hide()
layout = QVBoxLayout()
layout.setSpacing(15)
layout.setContentsMargins(0, 0, 0, 0)
layout.addStretch(1)
layout.addWidget(self._icon)
layout.addWidget(self._iconLabel)
layout.addStretch(1)
widget = QWidget()
widget.setStyleSheet("QWidget{background-color:rgb(0,0,0);}")
widget.setLayout(layout)
return widget
def __initView__(self):
iconWidget = self.__initIconWidget__()
self._tab = QTabWidget(self)
self._tab.addTab(self.__initAccountTab__(), "LOGIN")
self._tab.addTab(self.__initProxyTab__(), "PROXY")
self._tab.setFixedWidth(self.viewWidth - self.logoWidth - 60)
self._tab.hide()
grid = self.getGrid()
grid.setSpacing(15)
grid.setContentsMargins(0, 0, 0, 0)
grid.addWidget(iconWidget)
grid.addWidget(self._tab, 0, 1, Qt.AlignCenter)
self.setValidMoveWidget(iconWidget)
def showEnterView(self):
self._tab.show()
def hideEnterView(self):
self._tab.hide()
def setDeviceCode(self, text):
self._deviceCodeEdit.setText(text)
def enableHttpProxy(self) -> bool:
return self._enableProxyCheck.isChecked()
def getProxyInfo(self) -> dict:
infos = {'host': self._proxyHostEdit.text(), 'port': self._proxyPortEdit.text(),
'username': self._proxyUserEdit.text(), 'password': self._proxyPwdEdit.text()}
return infos
def connectConfirmButton(self, func):
self._confirmBtn.clicked.connect(func)
def enableConfirmButton(self, enable):
self._confirmBtn.setEnabled(enable)
def setMsg(self, text):
if len(text) <= 0:
self._iconLabel.hide()
else:
self._iconLabel.setText(text)
self._iconLabel.show()
def showErrMessage(self, text: str):
qmb = QMessageBox(self)
qmb.setWindowTitle('Error')
qmb.setIcon(QMessageBox.Warning)
qmb.setText(text)
qmb.addButton(QPushButton('OK', qmb), QMessageBox.YesRole)
qmb.open()
@@ -1,116 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : main.py
@Date : 2021/05/11
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from enum import IntEnum
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QVBoxLayout, QWidget, QGridLayout
from tidal_gui.control.framelessWidget import FramelessWidget
from tidal_gui.control.pushButton import PushButton
from tidal_gui.style import ButtonStyle
class PageType(IntEnum):
Search = 0,
Task = 1,
Settings = 2,
About = 3,
Max = 4,
class MainView(FramelessWidget):
viewWidth = 1200
viewHeight = 700
def __init__(self):
super(MainView, self).__init__()
self.setMinimumHeight(self.viewHeight)
self.setMinimumWidth(self.viewWidth)
self.__initPages__()
self.__initView__()
self.setWindowButton(True, True, True)
def __initPages__(self):
self._pages = []
for index in range(0, PageType.Max):
self._pages.append(None)
def __initView__(self):
leftTab = self.__initLeftTab__()
content = self.__initContent__()
grid = self.getGrid()
grid.addWidget(leftTab, 0, 0, Qt.AlignLeft)
grid.addLayout(content, 0, 1)
self.setValidMoveWidget(leftTab)
def __initLeftTab__(self):
self._icon = PushButton("", ButtonStyle.SoftwareIcon)
self._searchBtn = PushButton("", ButtonStyle.SearchIcon)
self._taskBtn = PushButton("", ButtonStyle.TaskIcon)
self._settingsBtn = PushButton("", ButtonStyle.SettingsIcon)
self._aboutBtn = PushButton("", ButtonStyle.AboutIcon)
self._searchBtn.clicked.connect(lambda: self.showPage(PageType.Search))
self._taskBtn.clicked.connect(lambda: self.showPage(PageType.Task))
self._settingsBtn.clicked.connect(lambda: self.showPage(PageType.Settings))
self._aboutBtn.clicked.connect(lambda: self.showPage(PageType.About))
layout = QVBoxLayout()
layout.setSpacing(15)
layout.setContentsMargins(15, 45, 15, 20)
layout.addWidget(self._icon)
layout.addWidget(self._searchBtn)
layout.addWidget(self._taskBtn)
layout.addStretch(1)
layout.addWidget(self._settingsBtn)
layout.addWidget(self._aboutBtn)
widget = QWidget()
widget.setLayout(layout)
widget.setObjectName("MainViewLeftWidget")
return widget
def __initContent__(self) -> QGridLayout:
self._searchView = None
self._settingsView = None
self._aboutView = None
self._taskView = None
self._contentLayout = QGridLayout()
self._contentLayout.setContentsMargins(10, 30, 10, 10)
return self._contentLayout
def showPage(self, pageType: PageType = PageType.Search):
for index in range(0, PageType.Max):
if index == pageType:
self._pages[index].show()
else:
self._pages[index].hide()
def __setContentPage__(self, view, pageType: PageType):
self._pages[pageType] = view
self._pages[pageType].hide()
self._contentLayout.addWidget(view, 0, 0)
def setSearchView(self, view):
self.__setContentPage__(view, PageType.Search)
def setTaskView(self, view):
self.__setContentPage__(view, PageType.Task)
def setSettingsView(self, view):
self.__setContentPage__(view, PageType.Settings)
def setAboutView(self, view: QWidget):
# self.__setContentPage__(view, PageType.About)
self._pages[PageType.About] = view
self._pages[PageType.About].hide()
@@ -1,199 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : searchView.py
@Date : 2021/8/17
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
import tidal_dl.model
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QTabWidget
from tidal_dl import Type
from tidal_gui.control.comboBox import ComboBox
from tidal_gui.control.label import Label
from tidal_gui.control.layout import createHBoxLayout
from tidal_gui.control.lineEdit import LineEdit
from tidal_gui.control.pushButton import PushButton
from tidal_gui.control.tableView import TableView
from tidal_gui.control.tableWidget import TableWidget
from tidal_gui.style import ButtonStyle
from tidal_gui.theme import getPackagePath
from tidal_gui.tidalImp import tidalImp
class SearchView(QWidget):
def __init__(self):
super(SearchView, self).__init__()
self._rowCount = 20
self._table = {}
self.__initView__()
self._searchEdit.setFocus()
self._searchBtn.setDefault(True)
def __initView__(self):
grid = QVBoxLayout(self)
grid.addLayout(self.__initHead__(), Qt.AlignTop)
grid.addLayout(self.__initContent__())
grid.addLayout(self.__initTail__(), Qt.AlignBottom)
def __initHead__(self):
self._searchEdit = LineEdit()
self._searchBtn = PushButton('Search', ButtonStyle.Primary,
iconUrl=getPackagePath() + "/resource/svg/search.svg")
layout = createHBoxLayout([self._searchEdit, self._searchBtn])
return layout
def __initTail__(self):
self._trackQualityComboBox = ComboBox([])
self._videoQualityComboBox = ComboBox([])
self._prePageBtn = PushButton('', ButtonStyle.PrePage)
self._nextPageBtn = PushButton('', ButtonStyle.NextPage)
self._pageIndexEdit = LineEdit('')
self._downloadBtn = PushButton('Download', ButtonStyle.Primary)
layout = QHBoxLayout()
layout.addWidget(Label('Track:'))
layout.addWidget(self._trackQualityComboBox)
layout.addWidget(Label('Video:'))
layout.addWidget(self._videoQualityComboBox)
layout.addStretch(1)
layout.addWidget(self._prePageBtn)
layout.addWidget(self._pageIndexEdit)
layout.addWidget(self._nextPageBtn)
layout.addWidget(self._downloadBtn)
return layout
def __initContent__(self):
self._tabWidget = QTabWidget(self)
self._tabWidget.addTab(self.__initTable__(Type.Album), "ALBUM")
self._tabWidget.addTab(self.__initTable__(Type.Track), "TRACK")
self._tabWidget.addTab(self.__initTable__(Type.Video), "VIDEO")
self._tabWidget.addTab(self.__initTable__(Type.Playlist), "PLAYLIST")
layout = QVBoxLayout()
layout.addWidget(self._tabWidget)
return layout
def __initTable__(self, stype: Type):
if stype == Type.Album:
columnHeads = ['#', ' ', 'Title', 'Artists', 'Release', 'Duration']
self._table[stype] = TableWidget(columnHeads)
self._table[stype].setColumnWidth(0, 50)
self._table[stype].setColumnWidth(1, 60)
self._table[stype].setColumnWidth(2, 400)
self._table[stype].setColumnWidth(3, 200)
elif stype == Type.Track:
columnHeads = ['#', ' ', 'Title', 'Album', 'Artists', 'Duration']
self._table[stype] = TableWidget(columnHeads)
self._table[stype].setColumnWidth(0, 50)
self._table[stype].setColumnWidth(1, 60)
self._table[stype].setColumnWidth(2, 400)
self._table[stype].setColumnWidth(3, 200)
self._table[stype].setColumnWidth(4, 200)
elif stype == Type.Video:
columnHeads = ['#', ' ', 'Title', 'Artists', 'Duration']
self._table[stype] = TableWidget(columnHeads)
self._table[stype].setColumnWidth(0, 50)
self._table[stype].setColumnWidth(1, 60)
self._table[stype].setColumnWidth(2, 400)
self._table[stype].setColumnWidth(3, 200)
self._table[stype].setColumnWidth(4, 200)
elif stype == Type.Playlist:
columnHeads = ['#', 'Title', 'Artist', 'Duration']
self._table[stype] = TableWidget(columnHeads)
self._table[stype].setColumnWidth(0, 50)
self._table[stype].setColumnWidth(1, 400)
self._table[stype].setColumnWidth(2, 200)
self._table[stype].setColumnWidth(3, 200)
return self._table[stype]
def setTableItems(self, stype: Type, indexOffset: int, result: tidal_dl.model.SearchResult):
if stype == Type.Album:
items = result.albums.items
self._table[stype].changeRowCount(len(items))
for index, item in enumerate(items):
self._table[stype].addItem(index, 0, str(index + 1 + indexOffset))
self._table[stype].addItem(index, 1, tidalImp.getFlag(item, Type.Album, True))
self._table[stype].addItem(index, 2, item.title)
self._table[stype].addItem(index, 3, item.artists[0].name)
self._table[stype].addItem(index, 4, str(item.releaseDate))
self._table[stype].addItem(index, 5, tidalImp.getDurationString(item.duration))
elif stype == Type.Track:
items = result.tracks.items
self._table[stype].changeRowCount(len(items))
for index, item in enumerate(items):
self._table[stype].addItem(index, 0, str(index + 1 + indexOffset))
self._table[stype].addItem(index, 1, tidalImp.getFlag(item, Type.Track, True))
self._table[stype].addItem(index, 2, item.title)
self._table[stype].addItem(index, 3, item.album.title)
self._table[stype].addItem(index, 4, item.artists[0].name)
self._table[stype].addItem(index, 5, tidalImp.getDurationString(item.duration))
elif stype == Type.Video:
items = result.videos.items
self._table[stype].changeRowCount(len(items))
for index, item in enumerate(items):
self._table[stype].addItem(index, 0, str(index + 1 + indexOffset))
self._table[stype].addItem(index, 1, tidalImp.getFlag(item, Type.Video, True))
self._table[stype].addItem(index, 2, item.title)
self._table[stype].addItem(index, 3, item.artists[0].name)
self._table[stype].addItem(index, 4, tidalImp.getDurationString(item.duration))
elif stype == Type.Playlist:
items = result.playlists.items
self._table[stype].changeRowCount(len(items))
for index, item in enumerate(items):
self._table[stype].addItem(index, 0, str(index + 1 + indexOffset))
self._table[stype].addItem(index, 1, item.title)
self._table[stype].addItem(index, 2, '')
self._table[stype].addItem(index, 3, tidalImp.getDurationString(item.duration))
self._table[stype].viewport().update()
def getSearchText(self):
return self._searchEdit.text()
def setPageIndex(self, index):
self._pageIndexEdit.setText(str(index))
def getPageIndex(self):
return int(self._pageIndexEdit.text())
def getSelectedTabIndex(self):
return self._tabWidget.currentIndex()
def getSelectedTableIndex(self, stype: Type):
array = self._table[stype].selectedIndexes()
if len(array) <= 0:
return -1
return array[0].row()
def setTrackQualityItems(self, items: list):
self._trackQualityComboBox.setItems(items)
def setVideoQualityItems(self, items: list):
self._videoQualityComboBox.setItems(items)
def getTrackQualityText(self):
return self._trackQualityComboBox.currentText()
def getVideoQualityText(self):
return self._videoQualityComboBox.currentText()
def connectButton(self, name: str, func):
if name == 'search':
self._searchBtn.clicked.connect(func)
self._searchEdit.returnPressed.connect(func)
elif name == 'prePage':
self._prePageBtn.clicked.connect(func)
elif name == 'nextPage':
self._nextPageBtn.clicked.connect(func)
elif name == 'download':
self._downloadBtn.clicked.connect(func)
def connectTab(self, func):
self._tabWidget.currentChanged.connect(func)
@@ -1,96 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : settingsView.py
@Date : 2021/05/11
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QGridLayout
from tidal_gui.control.checkBox import CheckBox
from tidal_gui.control.comboBox import ComboBox
from tidal_gui.control.label import Label
from tidal_gui.control.line import Line
from tidal_gui.control.lineEdit import LineEdit
from tidal_gui.control.pushButton import PushButton
from tidal_gui.style import LabelStyle, ButtonStyle, ThemeStyle
class SettingsView(QWidget):
def __init__(self):
super(SettingsView, self).__init__()
self.__initView__()
def __initView__(self):
grid = QVBoxLayout(self)
grid.addLayout(self.__initHeader__())
grid.addLayout(self.__initContent__())
grid.addLayout(self.__initToolButton__())
def __initHeader__(self):
self._header = Label("SETTINGS", LabelStyle.PageTitle)
layout = QVBoxLayout()
layout.addWidget(self._header)
layout.addWidget(Line('H'))
layout.setSpacing(10)
layout.setContentsMargins(0, 0, 0, 10)
return layout
def __initToolButton__(self) -> QHBoxLayout:
self._logoutBtn = PushButton('Logout', ButtonStyle.Danger, 100)
self._cancelBtn = PushButton('Cancel', ButtonStyle.Default, 100)
self._confirmBtn = PushButton('OK', ButtonStyle.Primary, 100)
layout = QHBoxLayout()
layout.addWidget(self._logoutBtn)
layout.addStretch(1)
layout.addWidget(self._cancelBtn)
layout.addWidget(self._confirmBtn)
return layout
def __addContent__(self, control, desc=''):
rowIdx = self._contentLayout.rowCount()
if desc != '':
self._contentLayout.addWidget(Label(desc), rowIdx, 0, Qt.AlignRight)
self._contentLayout.addWidget(control, rowIdx, 1)
def __initContent__(self):
self._contentLayout = QGridLayout()
self._contentLayout.setSpacing(15)
self._pathEdit = LineEdit()
self._threadNumComboBox = ComboBox([1, 5, 10, 20])
self._searchNumComboBox = ComboBox([10, 20, 30, 40, 50])
self.__addContent__(self._pathEdit, 'Path:')
self.__addContent__(self._threadNumComboBox, 'ThreadNum:')
self.__addContent__(self._searchNumComboBox, 'SearchNum:')
self._contentLayout.setRowStretch(self._contentLayout.rowCount(), 1)
self._albumFolderFormatEdit = LineEdit()
self._trackFileFormatEdit = LineEdit()
self._videoFileFormatEdit = LineEdit()
self.__addContent__(self._albumFolderFormatEdit, 'AlbumFolderFormat:')
self.__addContent__(self._trackFileFormatEdit, 'TrackFileFormat:')
self.__addContent__(self._videoFileFormatEdit, 'VideoFileFormat:')
self._saveCoverCheck = CheckBox('Download album cover')
self._skipExistCheck = CheckBox('Skip exist file when downloading')
self._convertMp4ToM4a = CheckBox('Convert mp4 to m4a')
self.__addContent__(self._saveCoverCheck)
self.__addContent__(self._skipExistCheck)
self.__addContent__(self._convertMp4ToM4a)
self._contentLayout.setRowStretch(self._contentLayout.rowCount(), 1)
self._themeComboBox = ComboBox(list(map(lambda x: x.name, ThemeStyle)))
self._languageComboBox = ComboBox(['Default'])
self.__addContent__(self._themeComboBox, 'Theme:')
self.__addContent__(self._languageComboBox, 'Language:')
self._contentLayout.setRowStretch(self._contentLayout.rowCount(), 10)
return self._contentLayout
@@ -1,68 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : taskItemView.py
@Date : 2021/9/14
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QTableWidget, QVBoxLayout
from tidal_gui.control.label import Label
from tidal_gui.control.layout import createHBoxLayout, createVBoxLayout
from tidal_gui.control.pushButton import PushButton
class TaskItemView(QWidget):
def __init__(self):
super(TaskItemView, self).__init__()
self.__initView__()
def __initView__(self):
grid = QVBoxLayout(self)
grid.addLayout(self.__initHead__())
grid.addWidget(self.__initList__())
def __initHead__(self):
self._btnRetry = PushButton()
self._btnCancel = PushButton()
self._btnDelete = PushButton()
self._btnOpen = PushButton()
self._btnExpand = PushButton()
btnLayout = createHBoxLayout([self._btnRetry, self._btnCancel,
self._btnDelete, self._btnOpen,
self._btnExpand])
self._titleLabel = Label()
self._descLabel = Label()
self._errLabel = Label()
self._errLabel.hide()
labelLayout = createVBoxLayout([self._titleLabel, self._descLabel, self._errLabel])
self._picLabel = Label()
headLayout = QHBoxLayout()
headLayout.addWidget(self._picLabel)
headLayout.addLayout(labelLayout)
headLayout.addStretch(1)
headLayout.addLayout(btnLayout)
return headLayout
def __initList__(self):
self._list = QTableWidget()
return self._list
def setLabel(self, title, desc):
self._titleLabel.setText(title)
self._descLabel.setText(desc)
def setErrmsg(self, msg):
self._errLabel.setText(msg)
def setPic(self, data):
pass
def addList(self):
pass
@@ -1,73 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : taskView.py
@Date : 2021/8/17
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtWidgets import QWidget, QGridLayout, QListWidgetItem
from tidal_gui.control.label import Label
from tidal_gui.control.line import Line
from tidal_gui.control.listWidget import ListWidget
from tidal_gui.style import LabelStyle, ListWidgetStyle
from tidal_gui.theme import getPackagePath
class TaskView(QWidget):
def __init__(self):
super(TaskView, self).__init__()
self._listMap = {'Download': ListWidget(ListWidgetStyle.TaskContent),
'Complete': ListWidget(ListWidgetStyle.TaskContent),
'Error': ListWidget(ListWidgetStyle.TaskContent)}
self._pageMap = {'Download': QWidget(),
'Complete': QWidget(),
'Error': QWidget()}
self.__initView__()
def __initView__(self):
grid = QGridLayout(self)
grid.addLayout(self.__initLefTab__(), 0, 0, Qt.AlignLeft)
grid.addWidget(self.__createContent__('Download'), 0, 1, Qt.AlignTop)
grid.addWidget(self.__createContent__('Complete'), 0, 1, Qt.AlignTop)
grid.addWidget(self.__createContent__('Error'), 0, 1, Qt.AlignTop)
def __initLefTab__(self):
self._listTab = ListWidget(ListWidgetStyle.TaskTab)
self._listTab.setIconSize(QSize(20, 20))
iconPath = getPackagePath() + "/resource/svg/taskTab/"
self._listTab.addIConTextItem(iconPath + 'download.svg', 'Download')
self._listTab.addIConTextItem(iconPath + 'complete.svg', 'Complete')
self._listTab.addIConTextItem(iconPath + 'Error.svg', 'Error')
self._listTab.itemClicked.connect(self.__tabItemChanged__)
layout = QGridLayout()
layout.addWidget(Label("TASK LIST", LabelStyle.PageTitle), 0, 0, Qt.AlignLeft)
layout.addWidget(self._listTab, 1, 0, Qt.AlignLeft)
layout.addWidget(Line('V'), 0, 1, 2, 1, Qt.AlignLeft)
return layout
def __createContent__(self, typeStr: str):
layout = QGridLayout()
layout.setContentsMargins(0, 0, 10, 10)
layout.setSpacing(10)
layout.addWidget(Label(typeStr, LabelStyle.PageSubTitle), 0, 0, Qt.AlignTop)
layout.addWidget(Line('H'), 1, 0, Qt.AlignTop)
layout.addWidget(self._listMap[typeStr], 2, 0)
self._pageMap[typeStr].setLayout(layout)
return self._pageMap[typeStr]
def __tabItemChanged__(self, item: QListWidgetItem):
for name in self._listMap:
if name == item.text():
self._pageMap[name].show()
else:
self._pageMap[name].hide()
@@ -1,11 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : __init__.py
@Date : 2021/8/17
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
@@ -1,22 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : aboutModel.py
@Date : 2021/8/17
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from tidal_gui.view.aboutView import AboutView
from tidal_gui.viewModel.viewModel import ViewModel
class AboutModel(ViewModel):
def __init__(self):
super(AboutModel, self).__init__()
self.view = AboutView()
self.view.setTitle('TIDAL-GUI')
self.view.setAuthor('Yaronzz')
self.view.setVersion('1.0.0.1')
self.view.setLastVersion('1.0.0.1')
@@ -1,68 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : loginModel.py
@Date : 2021/8/17
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
import _thread
import time
import webbrowser
from PyQt5.QtCore import QTimer, pyqtSignal, QObject
from tidal_gui.tidalImp import tidalImp
from tidal_gui.view.loginView import LoginView
from tidal_gui.viewModel.viewModel import ViewModel
class LoginModel(ViewModel):
SIGNAL_LOGIN_SUCCESS = pyqtSignal()
def __init__(self):
super(LoginModel, self).__init__()
self.view = LoginView()
self.view.connectConfirmButton(self.__openWebAndWait__)
def loginByConfig(self):
self.view.hideEnterView()
self.view.setMsg("LOGIN...")
def __thread_login__(model: LoginModel):
if tidalImp.loginByConfig():
model.SIGNAL_LOGIN_SUCCESS.emit()
return
model.getDeviceCode()
_thread.start_new_thread(__thread_login__, (self,))
def getDeviceCode(self):
self.view.hideEnterView()
self.view.setMsg("GET DEVICE-CODE...")
def __thread_getCode__(model: LoginModel):
msg, check = tidalImp.getDeviceCode()
if check:
model.view.enableConfirmButton(True)
model.view.setDeviceCode(tidalImp.key.userCode)
model.view.setMsg(' ')
model.view.showEnterView()
else:
model.view.setMsg(msg)
_thread.start_new_thread(__thread_getCode__, (self,))
def __openWebAndWait__(self):
self.view.enableConfirmButton(False)
webbrowser.open('link.tidal.com', new=0, autoraise=True)
def __thread_waitLogin__(model: LoginModel):
if tidalImp.loginByWeb():
model.SIGNAL_LOGIN_SUCCESS.emit()
else:
model.getDeviceCode()
_thread.start_new_thread(__thread_waitLogin__, (self,))
@@ -1,47 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : mainModel.py
@Date : 2021/8/17
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from tidal_gui.view.mainView import MainView
from tidal_gui.viewModel.aboutModel import AboutModel
from tidal_gui.viewModel.loginModel import LoginModel
from tidal_gui.viewModel.searchModel import SearchModel
from tidal_gui.viewModel.settingsModel import SettingsModel
from tidal_gui.viewModel.taskModel import TaskModel
from tidal_gui.viewModel.viewModel import ViewModel
class MainModel(ViewModel):
def __init__(self):
super(MainModel, self).__init__()
self.loginModel = LoginModel()
self.searchModel = SearchModel()
self.taskModel = TaskModel()
self.settingsModel = SettingsModel()
self.aboutModel = AboutModel()
self.loginModel.SIGNAL_LOGIN_SUCCESS.connect(self.__loginSuccess__)
self.searchModel.SIGNAL_ADD_TASKITEM.connect(self.taskModel.addTaskItem)
self.view = MainView()
self.view.setSearchView(self.searchModel.view)
self.view.setTaskView(self.taskModel.view)
self.view.setSettingsView(self.settingsModel.view)
self.view.setAboutView(self.aboutModel.view)
self.view.showPage()
def show(self):
self.view.hide()
self.loginModel.loginByConfig()
self.loginModel.show()
def __loginSuccess__(self):
self.loginModel.hide()
self.view.show()
@@ -1,101 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : searchModel.py
@Date : 2021/8/17
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
import _thread
import threading
import aigpy.stringHelper
import tidal_dl
from PyQt5.QtCore import pyqtSignal
from aigpy.modelHelper import ModelBase
from tidal_dl import Type
from tidal_dl.model import Album, SearchResult
from tidal_gui.tidalImp import tidalImp
from tidal_gui.view.searchView import SearchView
from tidal_gui.viewModel.viewModel import ViewModel
class SearchModel(ViewModel):
SIGNAL_ADD_TASKITEM = pyqtSignal(ModelBase)
def __init__(self):
super(SearchModel, self).__init__()
self._lock = threading.Lock()
self._resultData = SearchResult()
self.view = SearchView()
self.view.setPageIndex(1)
self.view.connectButton('search', self.__search__)
self.view.connectButton('prePage', self.__searchPrePage__)
self.view.connectButton('nextPage', self.__searchNextPage__)
self.view.connectButton('download', self.__download__)
self.view.connectTab(self.__search__)
def __startThread__(self):
def __thread_search__(model: SearchModel):
typeIndex = model.view.getSelectedTabIndex()
pageIndex = model.view.getPageIndex()
searchText = model.view.getSearchText()
limit = 20
offset = (pageIndex - 1) * limit
stype = tidal_dl.Type(typeIndex)
msg, model._resultData = tidalImp.search(searchText, stype, offset, limit)
if not aigpy.stringHelper.isNull(msg):
# errmessage
model._lock.release()
return
model.view.setTableItems(stype, offset, model._resultData)
model._lock.release()
_thread.start_new_thread(__thread_search__, (self,))
def __search__(self):
if not self._lock.acquire(False):
return
self.view.setPageIndex(1)
self.__startThread__()
def __searchNextPage__(self):
if not self._lock.acquire(False):
return
self.view.setPageIndex(self.view.getPageIndex() + 1)
self.__startThread__()
def __searchPrePage__(self):
if not self._lock.acquire(False):
return
index = self.view.getPageIndex() - 1
if index < 1:
index = 1
self.view.setPageIndex(index)
self.__startThread__()
def __download__(self):
typeIndex = self.view.getSelectedTabIndex()
stype = tidal_dl.Type(typeIndex)
index = self.view.getSelectedTableIndex(stype)
if index <= 0:
pass
data = None
if stype == Type.Album:
data = self._resultData.albums.items[index]
elif stype == Type.Track:
data = self._resultData.tracks.items[index]
elif stype == Type.Video:
data = self._resultData.videos.items[index]
elif stype == Type.Playlist:
data = self._resultData.playlists.items[index]
if data is not None:
self.SIGNAL_ADD_TASKITEM.emit(data)
@@ -1,18 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : settingsModel.py
@Date : 2021/8/17
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from tidal_gui.view.settingsView import SettingsView
from tidal_gui.viewModel.viewModel import ViewModel
class SettingsModel(ViewModel):
def __init__(self):
super(SettingsModel, self).__init__()
self.view = SettingsView()
@@ -1,66 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : taskItemModel.py
@Date : 2021/9/14
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
import _thread
import aigpy.stringHelper
from tidal_dl import Type
from tidal_dl.model import Album, Track, Video, Playlist
from tidal_gui.tidalImp import tidalImp
from tidal_gui.view.taskItemView import TaskItemView
from tidal_gui.viewModel.viewModel import ViewModel
class TaskItemModel(ViewModel):
def __init__(self, data):
super(TaskItemModel, self).__init__()
self.view = TaskItemView()
if isinstance(data, Album):
self.__initAlbum__(data)
elif isinstance(data, Track):
self.__initTrack__(data)
elif isinstance(data, Video):
self.__initVideo__(data)
elif isinstance(data, Playlist):
self.__initPlaylist__(data)
def __initAlbum__(self, data: Album):
title = data.title
desc = f"by {data.artist.name} " \
f"{tidalImp.getDurationString(data.duration)} " \
f"Track-{data.numberOfTracks} " \
f"Video-{data.numberOfVideos}"
self.view.setLabel(title, desc)
def __thread_func__(model: TaskItemModel, album: Album):
cover = tidalImp.getCoverData(album.cover, '1280', '1280')
self.view.setPic(cover)
msg, tracks, videos = tidalImp.getItems(album.id, Type.Album)
if not aigpy.stringHelper.isNull(msg):
model.view.setErrmsg(msg)
return
# TODO
for item in tracks:
pass
for item in videos:
pass
_thread.start_new_thread(__thread_func__, (self, data))
def __initTrack__(self, data: Track):
pass
def __initVideo__(self, data: Video):
pass
def __initPlaylist__(self, data: Playlist):
pass
@@ -1,25 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : taskModel.py
@Date : 2021/8/17
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from tidal_dl import Type
from tidal_gui.view.taskView import TaskView
from tidal_gui.viewModel.taskItemModel import TaskItemModel
from tidal_gui.viewModel.viewModel import ViewModel
class TaskModel(ViewModel):
def __init__(self):
super(TaskModel, self).__init__()
self.view = TaskView()
def addTaskItem(self, data):
item = TaskItemModel(data)
@@ -1,23 +0,0 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : viewModel.py
@Date : 2021/8/17
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtCore import QObject
class ViewModel(QObject):
def __init__(self):
super(ViewModel, self).__init__()
self.view = None
def show(self):
self.view.show()
def hide(self):
self.view.hide()
-56
View File
@@ -1,56 +0,0 @@
cd TIDALDL-PY
rm -rf dist
rm -rf build
rm -rf exe
rm -rf tidal_gui.egg-info
mkdir exe
# pack
python setup.py sdist bdist_wheel
# creat exe file
pyinstaller -F tidal_gui/__init__.py
# rename exe name
mv dist/__init__.exe exe/tidal-gui.exe
pip uninstall -y tidal-gui
# creat requirements.txt
# pipreqs ./ --force --encoding=utf8
# python setup.py install
# upload
twine upload dist/*
# powershell·
cd TIDALDL-PY
Remove-Item dist -recurse -Force
Remove-Item build -recurse -Force
Remove-Item exe -recurse -Force
Remove-Item tidal_dl.egg-info -recurse -Force
md exe
# pack
python setup.py sdist bdist_wheel
# creat exe file
pyinstaller -F tidal_dl/__init__.py
#pyinstaller -F -i ../logo.ico tidal_dl/__init__.py
# rename exe name
cp dist/__init__.exe exe/tidal-dl.exe
rm dist/__init__.exe
pip uninstall -y tidal-dl
# creat requirements.txt
# pipreqs ./ --force
# python setup.py install
# upload
twine upload dist/*
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
include tidal_gui/resource/themeDefault.qss
include tidal_gui/resource/svg/*.svg
include tidal_gui/resource/svg/*/*.svg
+12 -8
View File
@@ -1,8 +1,12 @@
requests==2.22.0
colorama==0.4.3
prettytable==0.7.2
mutagen==1.45.1
psutil==5.7.3
pycryptodome==3.9.9
aigpy==2021.9.10.3
lyricsgenius==3.0.1
requests==2.31.0
colorama==0.4.4
prettytable==3.1.1
mutagen==1.45.1
psutil==5.9.0
pycryptodome==3.14.1
aigpy==2022.7.8.1
lyricsgenius==3.0.1
pydub==0.25.1
PyQt5==5.15.7
qt-material==2.12
@@ -1,16 +1,16 @@
from setuptools import setup, find_packages
setup(
name = 'tidal-gui',
version = '1.0.0.1',
version = '2022.01.18.3',
license = "Apache2",
description = "Tidal Music Downloader.",
description = "Tidal Music Downloader-GUI.",
author = 'YaronH',
author_email = "yaronhuang@foxmail.com",
packages = find_packages(),
packages=find_packages(exclude=['tidal_dl*']),
include_package_data = True,
platforms = "any",
install_requires=["aigpy", "PyQt5", "requests>=2.22.0", "pycryptodome", "pydub", "prettytable", "lyricsgenius"],
install_requires=["tidal-dl"],
entry_points={'console_scripts': [ 'tidal-gui = tidal_gui:main', ]}
)
+8 -3
View File
@@ -10,9 +10,14 @@ setup(
author='YaronH',
author_email="yaronhuang@foxmail.com",
packages=find_packages(),
include_package_data=True,
packages=find_packages(exclude=['tidal_gui*']),
include_package_data=False,
platforms="any",
install_requires=["aigpy>=2021.9.10.3", "requests>=2.22.0", "pycryptodome", "pydub", "prettytable", "lyricsgenius"],
install_requires=["aigpy>=2022.7.8.1",
"requests>=2.22.0",
"pycryptodome",
"pydub",
"prettytable",
"lxml"],
entry_points={'console_scripts': ['tidal-dl = tidal_dl:main', ]}
)
+162 -295
View File
@@ -1,295 +1,162 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : __init__.py
@Time : 2020/11/08
@Author : Yaronzz
@Version : 2.1
@Contact : yaronhuang@foxmail.com
@Desc :
'''
import getopt
import logging
import ssl
import sys
import time
from aigpy.cmdHelper import green, yellow
from aigpy.pathHelper import mkdirs
from aigpy.pipHelper import getLastVersion
from aigpy.stringHelper import isNull
from aigpy.systemHelper import cmpVersion
from tidal_dl.download import start
from tidal_dl.enums import AudioQuality, VideoQuality, Type
from tidal_dl.lang.language import setLang, initLang, getLangChoicePrint
from tidal_dl.printf import Printf, VERSION
from tidal_dl.settings import Settings, TokenSettings, getLogPath
from tidal_dl.tidal import TidalAPI
from tidal_dl.util import API
ssl._create_default_https_context = ssl._create_unverified_context
TOKEN = TokenSettings.read()
CONF = Settings.read()
LANG = initLang(CONF.language)
logging.basicConfig(filename=getLogPath(),
level=logging.INFO,
format='%(asctime)s - %(levelname)s: %(message)s')
def displayTime(seconds, granularity=2):
if seconds <= 0:
return "unknown"
result = []
intervals = (
('weeks', 604800),
('days', 86400),
('hours', 3600),
('minutes', 60),
('seconds', 1),
)
for name, count in intervals:
value = seconds // count
if value:
seconds -= value * count
if value == 1:
name = name.rstrip('s')
result.append("{} {}".format(value, name))
return ', '.join(result[:granularity])
def login():
print(LANG.AUTH_START_LOGIN)
msg, check = API.getDeviceCode()
if not check:
Printf.err(msg)
return
print(LANG.AUTH_LOGIN_CODE.format(green(API.key.userCode)))
print(LANG.AUTH_NEXT_STEP.format(green(API.key.verificationUrl), yellow(displayTime(API.key.authCheckTimeout))))
print(LANG.AUTH_WAITING)
start = time.time()
elapsed = 0
while elapsed < API.key.authCheckTimeout:
elapsed = time.time() - start
# print("Check auth status...")
msg, check = API.checkAuthStatus()
if not check:
if msg == "pending":
time.sleep(API.key.authCheckInterval + 1)
continue
Printf.err(msg)
break
if check:
Printf.success(LANG.MSG_VALID_ACCESSTOKEN.format(displayTime(int(API.key.expiresIn))))
TOKEN.userid = API.key.userId
TOKEN.countryCode = API.key.countryCode
TOKEN.accessToken = API.key.accessToken
TOKEN.refreshToken = API.key.refreshToken
TOKEN.expiresAfter = time.time() + int(API.key.expiresIn)
TokenSettings.save(TOKEN)
break
if elapsed >= API.key.authCheckTimeout:
Printf.err(LANG.AUTH_TIMEOUT)
return
def setAccessToken():
while True:
print("-------------AccessToken---------------")
token = Printf.enter("accessToken('0' go back):")
if token == '0':
return
msg, check = API.loginByAccessToken(token, TOKEN.userid)
if not check:
Printf.err(msg)
continue
break
print("-------------RefreshToken---------------")
refreshToken = Printf.enter("refreshToken('0' to skip):")
if refreshToken == '0':
refreshToken = TOKEN.refreshToken
TOKEN.assesstoken = token
TOKEN.refreshToken = refreshToken
TOKEN.expiresAfter = 0
TokenSettings.save(TOKEN)
def checkLogin():
if not isNull(TOKEN.accessToken):
# print('Checking Access Token...') #add to translations
msg, check = API.verifyAccessToken(TOKEN.accessToken)
if check:
Printf.info(LANG.MSG_VALID_ACCESSTOKEN.format(displayTime(int(TOKEN.expiresAfter - time.time()))))
return
else:
Printf.info(LANG.MSG_INVAILD_ACCESSTOKEN)
msg, check = API.refreshAccessToken(TOKEN.refreshToken)
if check:
Printf.success(LANG.MSG_VALID_ACCESSTOKEN.format(displayTime(int(API.key.expiresIn))))
TOKEN.userid = API.key.userId
TOKEN.countryCode = API.key.countryCode
TOKEN.accessToken = API.key.accessToken
TOKEN.expiresAfter = time.time() + int(API.key.expiresIn)
TokenSettings.save(TOKEN)
return
else:
Printf.err(msg)
tmp = TokenSettings() # clears saved tokens
TokenSettings.save(tmp)
login()
return
def checkLogout():
global LANG
login()
return
def changeSettings():
global LANG
Printf.settings(CONF)
choice = Printf.enter(LANG.CHANGE_START_SETTINGS)
if choice == '0':
return
CONF.downloadPath = Printf.enterPath(LANG.CHANGE_DOWNLOAD_PATH, LANG.MSG_PATH_ERR, '0', CONF.downloadPath)
CONF.audioQuality = AudioQuality(int(Printf.enterLimit(
LANG.CHANGE_AUDIO_QUALITY, LANG.MSG_INPUT_ERR, ['0', '1', '2', '3'])))
CONF.videoQuality = VideoQuality(int(Printf.enterLimit(
LANG.CHANGE_VIDEO_QUALITY, LANG.MSG_INPUT_ERR, ['1080', '720', '480', '360'])))
CONF.onlyM4a = Printf.enter(LANG.CHANGE_ONLYM4A) == '1'
CONF.checkExist = Printf.enter(LANG.CHANGE_CHECK_EXIST) == '1'
CONF.includeEP = Printf.enter(LANG.CHANGE_INCLUDE_EP) == '1'
CONF.saveCovers = Printf.enter(LANG.CHANGE_SAVE_COVERS) == '1'
CONF.showProgress = Printf.enter(LANG.CHANGE_SHOW_PROGRESS) == '1'
CONF.saveAlbumInfo = Printf.enter(LANG.CHANGE_SAVE_ALBUM_INFO) == '1'
CONF.showTrackInfo = Printf.enter(LANG.CHANGE_SHOW_TRACKINFO) == '1'
CONF.usePlaylistFolder = Printf.enter(LANG.SETTING_USE_PLAYLIST_FOLDER + "('0'-No,'1'-Yes):") == '1'
CONF.language = Printf.enter(LANG.CHANGE_LANGUAGE + "(" + getLangChoicePrint() + "):")
CONF.albumFolderFormat = Printf.enterFormat(
LANG.CHANGE_ALBUM_FOLDER_FORMAT, CONF.albumFolderFormat, Settings.getDefaultAlbumFolderFormat())
CONF.trackFileFormat = Printf.enterFormat(LANG.CHANGE_TRACK_FILE_FORMAT,
CONF.trackFileFormat, Settings.getDefaultTrackFileFormat())
CONF.addLyrics = Printf.enter(LANG.CHANGE_ADD_LYRICS) == '1'
CONF.lyricsServerProxy = Printf.enterFormat(
LANG.CHANGE_LYRICS_SERVER_PROXY, CONF.lyricsServerProxy, CONF.lyricsServerProxy)
CONF.lyricFile = Printf.enter(LANG.CHANGE_ADD_LRC_FILE) == '1'
LANG = setLang(CONF.language)
Settings.save(CONF)
def mainCommand():
try:
opts, args = getopt.getopt(sys.argv[1:], "hvl:o:q:r:", ["help", "version",
"link=", "output=", "quality", "resolution"])
except getopt.GetoptError as errmsg:
Printf.err(vars(errmsg)['msg'] + ". Use 'tidal-dl -h' for useage.")
return
link = None
for opt, val in opts:
if opt in ('-h', '--help'):
Printf.usage()
continue
if opt in ('-v', '--version'):
Printf.logo()
continue
if opt in ('-l', '--link'):
checkLogin()
link = val
continue
if opt in ('-o', '--output'):
CONF.downloadPath = val
Settings.save(CONF)
continue
if opt in ('-q', '--quality'):
CONF.audioQuality = Settings.getAudioQuality(val)
Settings.save(CONF)
continue
if opt in ('-r', '--resolution'):
CONF.videoQuality = Settings.getVideoQuality(val)
Settings.save(CONF)
continue
if not mkdirs(CONF.downloadPath):
Printf.err(LANG.MSG_PATH_ERR + CONF.downloadPath)
return
if link is not None:
Printf.info(LANG.SETTING_DOWNLOAD_PATH + ':' + CONF.downloadPath)
start(TOKEN, CONF, link)
def debug():
checkLogin()
API.key.accessToken = TOKEN.accessToken
API.key.userId = TOKEN.userid
API.key.countryCode = TOKEN.countryCode
# https://api.tidal.com/v1/mixes/{01453963b7dbd41c8b82ccb678d127/items?countryCode={country}
API.getMix("01453963b7dbd41c8b82ccb678d127")
# msg, result = API.search('Mojito', Type.Null, 0, 10)
msg, lyric = API.getLyrics('144909909')
pass
def main():
if len(sys.argv) > 1:
mainCommand()
return
Printf.logo()
Printf.settings(CONF)
checkLogin()
onlineVer = getLastVersion('tidal-dl')
if not isNull(onlineVer):
icmp = cmpVersion(onlineVer, VERSION)
if icmp > 0:
Printf.info(LANG.PRINT_LATEST_VERSION + ' ' + onlineVer)
while True:
Printf.choices()
choice = Printf.enter(LANG.PRINT_ENTER_CHOICE)
if choice == "0":
return
elif choice == "1":
checkLogin()
elif choice == "2":
changeSettings()
elif choice == "3":
checkLogout()
elif choice == "4":
setAccessToken()
elif choice == "10": # test track
start(TOKEN, CONF, '70973230')
elif choice == "11": # test video
start(TOKEN, CONF, '188932980')
elif choice == "12": # test album
start(TOKEN, CONF, '58138532')
elif choice == "13": # test playlist
start(TOKEN, CONF, '98235845-13e8-43b4-94e2-d9f8e603cee7')
elif choice == "14": # test playlist
start(TOKEN, CONF, '01453963b7dbd41c8b82ccb678d127')
else:
start(TOKEN, CONF, choice)
if __name__ == "__main__":
# debug()
main()
# test example
# track 70973230 77798028 212657
# video 155608351 188932980
# album 58138532 77803199 21993753 79151897 56288918
# playlist 98235845-13e8-43b4-94e2-d9f8e603cee7
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : __init__.py
@Time : 2020/11/08
@Author : Yaronzz
@Version : 3.0
@Contact : yaronhuang@foxmail.com
@Desc :
'''
import sys
import getopt
import aigpy
from events import *
from settings import *
from gui import startGui
from printf import Printf
def mainCommand():
try:
opts, args = getopt.getopt(sys.argv[1:],
"hvgl:o:q:r:",
["help", "version", "gui", "link=", "output=", "quality", "resolution"])
except getopt.GetoptError as errmsg:
Printf.err(vars(errmsg)['msg'] + ". Use 'tidal-dl -h' for usage.")
return
link = None
showGui = False
for opt, val in opts:
if opt in ('-h', '--help'):
Printf.usage()
return
if opt in ('-v', '--version'):
Printf.logo()
return
if opt in ('-g', '--gui'):
showGui = True
continue
if opt in ('-l', '--link'):
link = val
continue
if opt in ('-o', '--output'):
SETTINGS.downloadPath = val
SETTINGS.save()
continue
if opt in ('-q', '--quality'):
SETTINGS.audioQuality = SETTINGS.getAudioQuality(val)
SETTINGS.save()
continue
if opt in ('-r', '--resolution'):
SETTINGS.videoQuality = SETTINGS.getVideoQuality(val)
SETTINGS.save()
continue
if not aigpy.path.mkdirs(SETTINGS.downloadPath):
Printf.err(LANG.select.MSG_PATH_ERR + SETTINGS.downloadPath)
return
if showGui:
startGui()
return
if link is not None:
if not loginByConfig():
loginByWeb()
Printf.info(LANG.select.SETTING_DOWNLOAD_PATH + ':' + SETTINGS.downloadPath)
start(link)
def main():
SETTINGS.read(getProfilePath())
TOKEN.read(getTokenPath())
TIDAL_API.apiKey = apiKey.getItem(SETTINGS.apiKeyIndex)
if len(sys.argv) > 1:
mainCommand()
return
Printf.logo()
Printf.settings()
if not apiKey.isItemValid(SETTINGS.apiKeyIndex):
changeApiKey()
loginByWeb()
elif not loginByConfig():
loginByWeb()
Printf.checkVersion()
while True:
Printf.choices()
choice = Printf.enter(LANG.select.PRINT_ENTER_CHOICE)
if choice == "0":
return
elif choice == "1":
if not loginByConfig():
loginByWeb()
elif choice == "2":
loginByWeb()
elif choice == "3":
loginByAccessToken()
elif choice == "4":
changePathSettings()
elif choice == "5":
changeQualitySettings()
elif choice == "6":
changeSettings()
elif choice == "7":
if changeApiKey():
loginByWeb()
else:
start(choice)
def test():
SETTINGS.read(getProfilePath())
TOKEN.read(getTokenPath())
if not loginByConfig():
loginByWeb()
SETTINGS.audioQuality = AudioQuality.Master
SETTINGS.videoFileFormat = VideoQuality.P240
SETTINGS.checkExist = False
SETTINGS.includeEP = True
SETTINGS.saveCovers = True
SETTINGS.lyricFile = True
SETTINGS.showProgress = True
SETTINGS.showTrackInfo = True
SETTINGS.saveAlbumInfo = True
SETTINGS.downloadVideos = True
SETTINGS.downloadPath = "./download/"
SETTINGS.usePlaylistFolder = True
SETTINGS.albumFolderFormat = R"{ArtistName}/{Flag} {AlbumTitle} [{AlbumID}] [{AlbumYear}]"
SETTINGS.playlistFolderFormat = R"Playlist/{PlaylistName} [{PlaylistUUID}]"
SETTINGS.trackFileFormat = R"{TrackNumber} - {ArtistName} - {TrackTitle}{ExplicitFlag}"
SETTINGS.videoFileFormat = R"{VideoNumber} - {ArtistName} - {VideoTitle}{ExplicitFlag}"
SETTINGS.multiThread = False
SETTINGS.apiKeyIndex = 4
SETTINGS.checkExist = False
Printf.settings()
TIDAL_API.getPlaylistSelf()
# test example
# https://tidal.com/browse/track/70973230
# track 70973230 77798028 212657
start('242700165')
# album 58138532 77803199 21993753 79151897 56288918
# start('58138532')
# playlist 98235845-13e8-43b4-94e2-d9f8e603cee7
# start('98235845-13e8-43b4-94e2-d9f8e603cee7')
# video 155608351 188932980 https://tidal.com/browse/track/55130637
# start("155608351")https://tidal.com/browse/track/199683732
if __name__ == '__main__':
# test()
main()
+108
View File
@@ -0,0 +1,108 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : apiKey.py
@Date : 2021/11/30
@Author : Yaronzz
@Version : 3.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
import json
import requests
__KEYS_JSON__ = '''
{
"version": "1.0.1",
"keys": [
{
"platform": "Fire TV",
"formats": "Normal/High/HiFi(No Master)",
"clientId": "OmDtrzFgyVVL6uW56OnFA2COiabqm",
"clientSecret": "zxen1r3pO0hgtOC7j6twMo9UAqngGrmRiWpV7QC1zJ8=",
"valid": "False",
"from": "Fokka-Engineering (https://github.com/Fokka-Engineering/libopenTIDAL/blob/655528e26e4f3ee2c426c06ea5b8440cf27abc4a/README.md#example)"
},
{
"platform": "Fire TV",
"formats": "Master-Only(Else Error)",
"clientId": "7m7Ap0JC9j1cOM3n",
"clientSecret": "vRAdA108tlvkJpTsGZS8rGZ7xTlbJ0qaZ2K9saEzsgY=",
"valid": "True",
"from": "Dniel97 (https://github.com/Dniel97/RedSea/blob/4ba02b88cee33aeb735725cb854be6c66ff372d4/config/settings.example.py#L68)"
},
{
"platform": "Android TV",
"formats": "Normal/High/HiFi(No Master)",
"clientId": "Pzd0ExNVHkyZLiYN",
"clientSecret": "W7X6UvBaho+XOi1MUeCX6ewv2zTdSOV3Y7qC3p3675I=",
"valid": "False",
"from": ""
},
{
"platform": "TV",
"formats": "Normal/High/HiFi/Master",
"clientId": "8SEZWa4J1NVC5U5Y",
"clientSecret": "owUYDkxddz+9FpvGX24DlxECNtFEMBxipU0lBfrbq60=",
"valid": "False",
"from": "morguldir (https://github.com/morguldir/python-tidal/commit/50f1afcd2079efb2b4cf694ef5a7d67fdf619d09)"
},
{
"platform": "Android Auto",
"formats": "Normal/High/HiFi/Master",
"clientId": "zU4XHVVkc2tDPo4t",
"clientSecret": "VJKhDFqJPqvsPVNBV6ukXTJmwlvbttP7wlMlrc72se4=",
"valid": "True",
"from": "1nikolas (https://github.com/yaronzz/Tidal-Media-Downloader/pull/840)"
}
]
}
'''
__API_KEYS__ = json.loads(__KEYS_JSON__)
__ERROR_KEY__ = {
'platform': 'None',
'formats': '',
'clientId': '',
'clientSecret': '',
'valid': 'False',
},
def getNum():
return len(__API_KEYS__['keys'])
def getItem(index: int):
if index < 0 or index >= len(__API_KEYS__['keys']):
return __ERROR_KEY__
return __API_KEYS__['keys'][index]
def isItemValid(index: int):
item = getItem(index)
return item['valid'] == 'True'
def getItems():
return __API_KEYS__['keys']
def getLimitIndexs():
array = []
for i in range(len(__API_KEYS__['keys'])):
array.append(str(i))
return array
def getVersion():
return __API_KEYS__['version']
# Load from gist
try:
respond = requests.get('https://api.github.com/gists/48d01f5a24b4b7b37f19443977c22cd6')
if respond.status_code == 200:
content = respond.json()['files']['tidal-api-key.json']['content']
__API_KEYS__ = json.loads(content)
except:
pass
+181 -514
View File
@@ -6,550 +6,217 @@
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
@Desc :
'''
import logging
import os
import datetime
import aigpy
import lyricsgenius
from tidal_dl.decryption import decrypt_file
from tidal_dl.decryption import decrypt_security_token
from tidal_dl.enums import Type, AudioQuality
from tidal_dl.model import Track, Video, Lyrics, Mix
from tidal_dl.printf import Printf
from tidal_dl.settings import Settings
from tidal_dl.tidal import TidalAPI
from tidal_dl.util import getVideoPath, getTrackPath, getAlbumPath, getArtistsName, convertToM4a, setMetaData, \
isNeedDownload, API, getLyricsFromGemius
from concurrent.futures import ThreadPoolExecutor
from decryption import *
from printf import *
from tidal import *
def __loadAPI__(user):
API.key.accessToken = user.accessToken
API.key.userId = user.userid
API.key.countryCode = user.countryCode
# API.key.sessionId = user.sessionid1
def __isSkip__(finalpath, url):
if not SETTINGS.checkExist:
return False
curSize = aigpy.file.getSize(finalpath)
if curSize <= 0:
return False
netSize = aigpy.net.getSize(url)
return curSize >= netSize
def __loadVideoAPI__(user):
API.key.accessToken = user.accessToken
API.key.userId = user.userid
API.key.countryCode = user.countryCode
# API.key.sessionId = user.sessionid2 if not aigpy.string.isNull(user.sessionid2) else user.sessionid1
# def __getIndexStr__(index):
# pre = "0"
# if index < 10:
# return pre + str(index)
# if index < 99:
# return str(index)
# return str(index)
# def __getExtension__(url):
# if '.flac' in url:
# return '.flac'
# if '.mp4' in url:
# return '.mp4'
# return '.m4a'
# def __getArtists__(array):
# ret = []
# for item in array:
# ret.append(item.name)
# return ret
# def __getArtistsString__(artists):
# return ", ".join(map(lambda artist: artist.name, artists))
# def __parseContributors__(roleType, Contributors):
# if Contributors is None:
# return None
# try:
# ret = []
# for item in Contributors['items']:
# if item['role'] == roleType:
# ret.append(item['name'])
# return ret
# except:
# return None
# GEMIUS = lyricsgenius.Genius('vNKbAWAE3rVY_48nRaiOrDcWNLvsxS-Z8qyG5XfEzTOtZvkTfg6P3pxOVlA2BjaW')
#
#
# def __getLyrics__(trackName, artistName, proxy):
# try:
# if not aigpy.string.isNull(proxy):
# GEMIUS._session.proxies = {
# 'http': f'http://{proxy}',
# 'https': f'http://{proxy}',
# }
#
# song = GEMIUS.search_song(trackName, artistName)
# return song.lyrics
# except:
# return ""
#
# def __setMetaData__(track, album, filepath, contributors, lyrics):
# obj = aigpy.tag.TagTool(filepath)
# obj.album = track.album.title
# obj.title = track.title
# if not aigpy.string.isNull(track.version):
# obj.title += ' (' + track.version + ')'
#
# obj.artist = map(lambda artist: artist.name, track.artists) # __getArtists__(track.artists)
# obj.copyright = track.copyRight
# obj.tracknumber = track.trackNumber
# obj.discnumber = track.volumeNumber
# obj.composer = __parseContributors__('Composer', contributors)
# obj.isrc = track.isrc
#
# obj.albumartist = map(lambda artist: artist.name, album.artists) #__getArtists__(album.artists)
# obj.date = album.releaseDate
# obj.totaldisc = album.numberOfVolumes
# obj.lyrics = lyrics
# if obj.totaldisc <= 1:
# obj.totaltrack = album.numberOfTracks
# coverpath = API.getCoverUrl(album.cover, "1280", "1280")
# obj.save(coverpath)
# return
# def __convertToM4a__(filepath, codec):
# if 'ac4' in codec or 'mha1' in codec:
# return filepath
# if '.mp4' not in filepath:
# return filepath
# newpath = filepath.replace('.mp4', '.m4a')
# aigpy.path.remove(newpath)
# os.rename(filepath, newpath)
# return newpath
# def __stripPathParts__(stripped_path, separator):
# result = ""
# stripped_path = stripped_path.split(separator)
# for stripped_path_part in stripped_path:
# result += stripped_path_part.strip()
# if not stripped_path.index(stripped_path_part) == len(stripped_path) - 1:
# result += separator
# return result.strip()
#
#
# def __stripPath__(path):
# result = __stripPathParts__(path, "/")
# result = __stripPathParts__(result, "\\")
# return result.strip()
# "{ArtistName}/{Flag} [{AlbumID}] [{AlbumYear}] {AlbumTitle}"
# def getAlbumPath(conf: Settings, album):
# base = conf.downloadPath + '/Album/'
# artist = aigpy.path.replaceLimitChar(__getArtistsString__(album.artists), '-')
# # album folder pre: [ME][ID]
# flag = API.getFlag(album, Type.Album, True, "")
# if conf.audioQuality != AudioQuality.Master:
# flag = flag.replace("M", "")
# if not conf.addExplicitTag:
# flag = flag.replace("E", "")
# if not aigpy.string.isNull(flag):
# flag = "[" + flag + "] "
#
# sid = str(album.id)
# # album and addyear
# albumname = aigpy.path.replaceLimitChar(album.title, '-')
# year = ""
# if album.releaseDate is not None:
# year = aigpy.string.getSubOnlyEnd(album.releaseDate, '-')
# # retpath
# retpath = conf.albumFolderFormat
# if retpath is None or len(retpath) <= 0:
# retpath = Settings.getDefaultAlbumFolderFormat()
# retpath = retpath.replace(R"{ArtistName}", artist.strip())
# retpath = retpath.replace(R"{Flag}", flag)
# retpath = retpath.replace(R"{AlbumID}", sid)
# retpath = retpath.replace(R"{AlbumYear}", year)
# retpath = retpath.replace(R"{AlbumTitle}", albumname.strip())
# retpath = __stripPath__(retpath.strip())
# return base + retpath
#
#
# def __getAlbumPath2__(conf, album):
# # outputdir/Album/artist/
# artist = aigpy.path.replaceLimitChar(__getArtistsString__(album.artists), '-').strip()
# base = conf.downloadPath + '/Album/' + artist + '/'
#
# # album folder pre: [ME][ID]
# flag = API.getFlag(album, Type.Album, True, "")
# if conf.audioQuality != AudioQuality.Master:
# flag = flag.replace("M", "")
# if not conf.addExplicitTag:
# flag = flag.replace("E", "")
# if not aigpy.string.isNull(flag):
# flag = "[" + flag + "] "
#
# sid = "[" + str(album.id) + "] " if conf.addAlbumIDBeforeFolder else ""
#
# # album and addyear
# albumname = aigpy.path.replaceLimitChar(album.title, '-').strip()
# year = ""
# if conf.addYear and album.releaseDate is not None:
# year = "[" + aigpy.string.getSubOnlyEnd(album.releaseDate, '-') + "] "
# return base + flag + sid + year + albumname + '/'
#
#
# def getPlaylistPath(conf, playlist):
# # outputdir/Playlist/
# base = conf.downloadPath + '/Playlist/'
# # name
# name = aigpy.path.replaceLimitChar(playlist.title, '-')
# return base + name + '/'
#
#
# # "{TrackNumber} - {ArtistName} - {TrackTitle}{ExplicitFlag}"
#
#
# def getTrackPath(conf: Settings, track, stream, album=None, playlist=None):
# if album is not None:
# base = getAlbumPath(conf, album) + '/'
# if album.numberOfVolumes > 1:
# base += 'CD' + str(track.volumeNumber) + '/'
# if playlist is not None and conf.usePlaylistFolder:
# base = getPlaylistPath(conf, playlist)
# # number
# number = __getIndexStr__(track.trackNumber)
# if playlist is not None and conf.usePlaylistFolder:
# number = __getIndexStr__(track.trackNumberOnPlaylist)
# # artist
# artist = aigpy.path.replaceLimitChar(__getArtistsString__(track.artists), '-')
# # title
# title = track.title
# if not aigpy.string.isNull(track.version):
# title += ' (' + track.version + ')'
# title = aigpy.path.replaceLimitChar(title, '-')
# # get explicit
# explicit = "(Explicit)" if conf.addExplicitTag and track.explicit else ''
# # album and addyear
# albumname = aigpy.path.replaceLimitChar(album.title, '-')
# year = ""
# if album.releaseDate is not None:
# year = aigpy.string.getSubOnlyEnd(album.releaseDate, '-')
# # extension
# extension = __getExtension__(stream.url)
# retpath = conf.trackFileFormat
# if retpath is None or len(retpath) <= 0:
# retpath = Settings.getDefaultTrackFileFormat()
# retpath = retpath.replace(R"{TrackNumber}", number)
# retpath = retpath.replace(R"{ArtistName}", artist.strip())
# retpath = retpath.replace(R"{TrackTitle}", title)
# retpath = retpath.replace(R"{ExplicitFlag}", explicit)
# retpath = retpath.replace(R"{AlbumYear}", year)
# retpath = retpath.replace(R"{AlbumTitle}", albumname.strip())
# retpath = retpath.strip()
# return base + retpath + extension
#
#
# def __getTrackPath2__(conf, track, stream, album=None, playlist=None):
# if album is not None:
# base = getAlbumPath(conf, album)
# if album.numberOfVolumes > 1:
# base += 'CD' + str(track.volumeNumber) + '/'
# if playlist is not None and conf.usePlaylistFolder:
# base = getPlaylistPath(conf, playlist)
#
# # hyphen
# hyphen = ' - ' if conf.addHyphen else ' '
# # get number
# number = ''
# if conf.useTrackNumber:
# number = __getIndexStr__(track.trackNumber) + hyphen
# if playlist is not None:
# number = __getIndexStr__(track.trackNumberOnPlaylist) + hyphen
# # get artist
# artist = ''
# if conf.artistBeforeTitle:
# artist = aigpy.path.replaceLimitChar(__getArtistsString__(track.artists), '-') + hyphen
# # get explicit
# explicit = "(Explicit)" if conf.addExplicitTag and track.explicit else ''
# # title
# title = track.title
# if not aigpy.string.isNull(track.version):
# title += ' - ' + track.version
# title = aigpy.path.replaceLimitChar(title, '-')
# # extension
# extension = __getExtension__(stream.url)
# return base + number + artist.strip() + title + explicit + extension
#
#
# def getVideoPath(conf, video, album=None, playlist=None):
# if album is not None and album.title is not None:
# base = getAlbumPath(conf, album)
# elif playlist is not None and conf.usePlaylistFolder:
# base = getPlaylistPath(conf, playlist)
# else:
# base = conf.downloadPath + '/Video/'
#
# # hyphen
# hyphen = ' - ' if conf.addHyphen else ' '
# # get number
# number = ''
# if conf.useTrackNumber:
# number = __getIndexStr__(video.trackNumber) + hyphen
# # get artist
# artist = ''
# if conf.artistBeforeTitle:
# artist = aigpy.path.replaceLimitChar(__getArtistsString__(video.artists), '-') + hyphen
# # get explicit
# explicit = "(Explicit)" if conf.addExplicitTag and video.explicit else ''
# # title
# title = aigpy.path.replaceLimitChar(video.title, '-')
# # extension
# extension = ".mp4"
# return base + number + artist.strip() + title + explicit + extension
# def __isNeedDownload__(path, url):
# curSize = aigpy.file.getSize(path)
# if curSize <= 0:
# return True
# netSize = aigpy.net.getSize(url)
# if curSize >= netSize:
# return False
# return True
def __downloadVideo__(conf, video: Video, album=None, playlist=None):
if video.allowStreaming is False:
Printf.err("Download failed! " + video.title + ' not allow streaming.')
return
msg, stream = API.getVideoStreamUrl(video.id, conf.videoQuality)
Printf.video(video, stream)
if not aigpy.string.isNull(msg):
Printf.err(video.title + "." + msg)
return
path = getVideoPath(conf, video, album, playlist)
logging.info("[DL Video] name=" + aigpy.path.getFileName(path) + "\nurl=" + stream.m3u8Url)
check, msg = aigpy.m3u8.download(stream.m3u8Url, path)
if check is True:
Printf.success(aigpy.path.getFileName(path))
def __encrypted__(stream, srcPath, descPath):
if aigpy.string.isNull(stream.encryptionKey):
os.replace(srcPath, descPath)
else:
Printf.err("\nDownload failed!" + msg + '(' + aigpy.path.getFileName(path) + ')')
key, nonce = decrypt_security_token(stream.encryptionKey)
decrypt_file(srcPath, descPath, key, nonce)
os.remove(srcPath)
def __downloadTrack__(conf: Settings, track: Track, album=None, playlist=None):
def __parseContributors__(roleType, Contributors):
if Contributors is None:
return None
try:
# if track.allowStreaming is False:
# Printf.err("Download failed! " + track.title + ' not allow streaming.')
# return
msg, stream = API.getStreamUrl(track.id, conf.audioQuality)
if conf.showTrackInfo:
Printf.track(track, stream)
if not aigpy.string.isNull(msg) or stream is None:
Printf.err(track.title + "." + msg)
return
path = getTrackPath(conf, track, stream, album, playlist)
# check exist
if conf.checkExist and isNeedDownload(path, stream.url) == False:
Printf.success(aigpy.path.getFileName(path) + " (skip:already exists!)")
return
logging.info("[DL Track] name=" + aigpy.path.getFileName(path) + "\nurl=" + stream.url)
tool = aigpy.download.DownloadTool(path + '.part', [stream.url])
check, err = tool.start(conf.showProgress)
if not check:
Printf.err("Download failed! " + aigpy.path.getFileName(path) + ' (' + str(err) + ')')
return
# encrypted -> decrypt and remove encrypted file
if aigpy.string.isNull(stream.encryptionKey):
os.replace(path + '.part', path)
else:
key, nonce = decrypt_security_token(stream.encryptionKey)
decrypt_file(path + '.part', path, key, nonce)
os.remove(path + '.part')
path = convertToM4a(path, stream.codec)
# contributors
msg, contributors = API.getTrackContributors(track.id)
msg, tidalLyrics = API.getLyrics(track.id)
lyrics = '' if tidalLyrics is None else tidalLyrics.subtitles
if conf.addLyrics and lyrics == '':
lyrics = getLyricsFromGemius(track.title, getArtistsName(track.artists), conf.lyricsServerProxy)
if conf.lyricFile:
if tidalLyrics is None:
Printf.info(f'Failed to get lyrics from tidal!"{track.title}"')
else:
lrcPath = path.rsplit(".", 1)[0] + '.lrc'
aigpy.fileHelper.write(lrcPath, tidalLyrics.subtitles, 'w')
setMetaData(track, album, path, contributors, lyrics)
Printf.success(aigpy.path.getFileName(path))
except Exception as e:
Printf.err("Download failed! " + track.title + ' (' + str(e) + ')')
ret = []
for item in Contributors['items']:
if item['role'] == roleType:
ret.append(item['name'])
return ret
except:
return None
def __downloadCover__(conf, album):
if album == None:
def __setMetaData__(track: Track, album: Album, filepath, contributors, lyrics):
obj = aigpy.tag.TagTool(filepath)
obj.album = track.album.title
obj.title = track.title
if not aigpy.string.isNull(track.version):
obj.title += ' (' + track.version + ')'
obj.artist = list(map(lambda artist: artist.name, track.artists))
obj.copyright = track.copyRight
obj.tracknumber = track.trackNumber
obj.discnumber = track.volumeNumber
obj.composer = __parseContributors__('Composer', contributors)
obj.isrc = track.isrc
obj.albumartist = list(map(lambda artist: artist.name, album.artists))
obj.date = album.releaseDate
obj.totaldisc = album.numberOfVolumes
obj.lyrics = lyrics
if obj.totaldisc <= 1:
obj.totaltrack = album.numberOfTracks
coverpath = TIDAL_API.getCoverUrl(album.cover, "1280", "1280")
obj.save(coverpath)
def downloadCover(album):
if album is None:
return
path = getAlbumPath(conf, album) + '/cover.jpg'
url = API.getCoverUrl(album.cover, "1280", "1280")
if url is not None:
aigpy.net.downloadFile(url, path)
path = getAlbumPath(album) + '/cover.jpg'
url = TIDAL_API.getCoverUrl(album.cover, "1280", "1280")
aigpy.net.downloadFile(url, path)
def __saveAlbumInfo__(conf, album, tracks):
if album == None:
def downloadAlbumInfo(album, tracks):
if album is None:
return
path = getAlbumPath(conf, album) + '/AlbumInfo.txt'
path = getAlbumPath(album)
aigpy.path.mkdirs(path)
path += '/AlbumInfo.txt'
infos = ""
infos += "[ID] %s\n" % (str(album.id))
infos += "[Title] %s\n" % (str(album.title))
infos += "[Artists] %s\n" % (str(album.artist.name))
infos += "[Artists] %s\n" % (TIDAL_API.getArtistsName(album.artists))
infos += "[ReleaseDate] %s\n" % (str(album.releaseDate))
infos += "[SongNum] %s\n" % (str(album.numberOfTracks))
infos += "[Duration] %s\n" % (str(album.duration))
infos += '\n'
i = 0
while True:
if i >= int(album.numberOfVolumes):
break
i = i + 1
infos += "===========CD %d=============\n" % i
for index in range(0, album.numberOfVolumes):
volumeNumber = index + 1
infos += f"===========CD {volumeNumber}=============\n"
for item in tracks:
if item.volumeNumber != i:
if item.volumeNumber != volumeNumber:
continue
infos += '{:<8}'.format("[%d]" % item.trackNumber)
infos += "%s\n" % item.title
aigpy.file.write(path, infos, "w+")
def __album__(conf, obj):
Printf.album(obj)
msg, tracks, videos = API.getItems(obj.id, Type.Album)
if not aigpy.string.isNull(msg):
Printf.err(msg)
return
if conf.saveAlbumInfo:
__saveAlbumInfo__(conf, obj, tracks)
if conf.saveCovers:
__downloadCover__(conf, obj)
for item in tracks:
__downloadTrack__(conf, item, obj)
def downloadVideo(video: Video, album: Album = None, playlist: Playlist = None):
try:
stream = TIDAL_API.getVideoStreamUrl(video.id, SETTINGS.videoQuality)
path = getVideoPath(video, album, playlist)
Printf.video(video, stream)
logging.info("[DL Video] name=" + aigpy.path.getFileName(path) + "\nurl=" + stream.m3u8Url)
m3u8content = requests.get(stream.m3u8Url).content
if m3u8content is None:
Printf.err(f"DL Video[{video.title}] getM3u8 failed.{str(e)}")
return False, f"GetM3u8 failed.{str(e)}"
urls = aigpy.m3u8.parseTsUrls(m3u8content)
if len(urls) <= 0:
Printf.err(f"DL Video[{video.title}] getTsUrls failed.{str(e)}")
return False, "GetTsUrls failed.{str(e)}"
check, msg = aigpy.m3u8.downloadByTsUrls(urls, path)
if check:
Printf.success(video.title)
return True
else:
Printf.err(f"DL Video[{video.title}] failed.{msg}")
return False, msg
except Exception as e:
Printf.err(f"DL Video[{video.title}] failed.{str(e)}")
return False, str(e)
def downloadTrack(track: Track, album=None, playlist=None, userProgress=None, partSize=1048576):
try:
stream = TIDAL_API.getStreamUrl(track.id, SETTINGS.audioQuality)
path = getTrackPath(track, stream, album, playlist)
if SETTINGS.showTrackInfo and not SETTINGS.multiThread:
Printf.track(track, stream)
if userProgress is not None:
userProgress.updateStream(stream)
# check exist
if __isSkip__(path, stream.url):
Printf.success(aigpy.path.getFileName(path) + " (skip:already exists!)")
return True, ''
# download
logging.info("[DL Track] name=" + aigpy.path.getFileName(path) + "\nurl=" + stream.url)
tool = aigpy.download.DownloadTool(path + '.part', stream.urls)
tool.setUserProgress(userProgress)
tool.setPartSize(partSize)
check, err = tool.start(SETTINGS.showProgress and not SETTINGS.multiThread)
if not check:
Printf.err(f"DL Track '{track.title}' failed: {str(err)}")
return False, str(err)
# encrypted -> decrypt and remove encrypted file
__encrypted__(stream, path + '.part', path)
# contributors
try:
contributors = TIDAL_API.getTrackContributors(track.id)
except:
contributors = None
# lyrics
try:
lyrics = TIDAL_API.getLyrics(track.id).subtitles
if SETTINGS.lyricFile:
lrcPath = path.rsplit(".", 1)[0] + '.lrc'
aigpy.file.write(lrcPath, lyrics, 'w')
except:
lyrics = ''
__setMetaData__(track, album, path, contributors, lyrics)
Printf.success(track.title)
return True, ''
except Exception as e:
Printf.err(f"DL Track '{track.title}' failed: {str(e)}")
return False, str(e)
def downloadTracks(tracks, album: Album = None, playlist: Playlist = None):
def __getAlbum__(item: Track):
album = TIDAL_API.getAlbum(item.album.id)
if SETTINGS.saveCovers and not SETTINGS.usePlaylistFolder:
downloadCover(album)
return album
if not SETTINGS.multiThread:
for index, item in enumerate(tracks):
itemAlbum = album
if itemAlbum is None:
itemAlbum = __getAlbum__(item)
item.trackNumberOnPlaylist = index + 1
downloadTrack(item, itemAlbum, playlist)
else:
thread_pool = ThreadPoolExecutor(max_workers=5)
for index, item in enumerate(tracks):
itemAlbum = album
if itemAlbum is None:
itemAlbum = __getAlbum__(item)
item.trackNumberOnPlaylist = index + 1
thread_pool.submit(downloadTrack, item, itemAlbum, playlist)
thread_pool.shutdown(wait=True)
def downloadVideos(videos, album: Album, playlist=None):
for item in videos:
__downloadVideo__(conf, item, obj)
def __track__(conf, obj):
msg, album = API.getAlbum(obj.album.id)
if conf.saveCovers:
__downloadCover__(conf, album)
__downloadTrack__(conf, obj, album)
def __video__(conf, obj):
# Printf.video(obj)
__downloadVideo__(conf, obj, obj.album)
def __artist__(conf, obj):
msg, albums = API.getArtistAlbums(obj.id, conf.includeEP)
Printf.artist(obj, len(albums))
if not aigpy.string.isNull(msg):
Printf.err(msg)
return
for item in albums:
__album__(conf, item)
def __playlist__(conf, obj):
Printf.playlist(obj)
msg, tracks, videos = API.getItems(obj.uuid, Type.Playlist)
if not aigpy.string.isNull(msg):
Printf.err(msg)
return
for index, item in enumerate(tracks):
mag, album = API.getAlbum(item.album.id)
item.trackNumberOnPlaylist = index + 1
__downloadTrack__(conf, item, album, obj)
if conf.saveCovers and not conf.usePlaylistFolder:
__downloadCover__(conf, album)
for item in videos:
__downloadVideo__(conf, item, None)
def __mix__(conf, obj: Mix):
Printf.mix(obj)
for index, item in enumerate(obj.tracks):
mag, album = API.getAlbum(item.album.id)
item.trackNumberOnPlaylist = index + 1
__downloadTrack__(conf, item, album)
if conf.saveCovers and not conf.usePlaylistFolder:
__downloadCover__(conf, album)
for item in obj.videos:
__downloadVideo__(conf, item, None)
def file(user, conf, string):
txt = aigpy.file.getContent(string)
if aigpy.string.isNull(txt):
Printf.err("Nothing can read!")
return
array = txt.split('\n')
for item in array:
if aigpy.string.isNull(item):
continue
if item[0] == '#':
continue
if item[0] == '[':
continue
start(user, conf, item)
def start(user, conf, string):
__loadAPI__(user)
if aigpy.string.isNull(string):
Printf.err('Please enter something.')
return
strings = string.split(" ")
for item in strings:
if aigpy.string.isNull(item):
continue
if os.path.exists(item):
file(user, conf, item)
return
msg, etype, obj = API.getByString(item)
if etype == Type.Null or not aigpy.string.isNull(msg):
Printf.err(msg + " [" + item + "]")
return
if etype == Type.Album:
__album__(conf, obj)
if etype == Type.Track:
__track__(conf, obj)
if etype == Type.Video:
__loadVideoAPI__(user)
__video__(conf, obj)
if etype == Type.Artist:
__artist__(conf, obj)
if etype == Type.Playlist:
__playlist__(conf, obj)
if etype == Type.Mix:
__mix__(conf, obj)
downloadVideo(item, album, playlist)
+37 -36
View File
@@ -1,36 +1,37 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : enums.py
@Time : 2020/08/08
@Author : Yaronzz
@Version : 2.0
@Contact : yaronhuang@foxmail.com
@Desc :
'''
from enum import Enum
class AudioQuality(Enum):
Normal = 0
High = 1
HiFi = 2
Master = 3
class VideoQuality(Enum):
P240 = 240
P360 = 360
P480 = 480
P720 = 720
P1080 = 1080
class Type(Enum):
Album = 0
Track = 1
Video = 2
Playlist = 3
Artist = 4
Mix = 5
Null = 6
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : enums.py
@Time : 2020/08/08
@Author : Yaronzz
@Version : 3.0
@Contact : yaronhuang@foxmail.com
@Desc :
'''
from enum import Enum
class AudioQuality(Enum):
Normal = 0
High = 1
HiFi = 2
Master = 3
Max = 4
class VideoQuality(Enum):
P240 = 240
P360 = 360
P480 = 480
P720 = 720
P1080 = 1080
class Type(Enum):
Album = 0
Track = 1
Video = 2
Playlist = 3
Artist = 4
Mix = 5
Null = 6
+320
View File
@@ -0,0 +1,320 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : events.py
@Date : 2022/06/10
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from download import *
'''
=================================
START DOWNLOAD
=================================
'''
def start_album(obj: Album):
Printf.album(obj)
tracks, videos = TIDAL_API.getItems(obj.id, Type.Album)
if SETTINGS.saveAlbumInfo:
downloadAlbumInfo(obj, tracks)
if SETTINGS.saveCovers and obj.cover is not None:
downloadCover(obj)
downloadTracks(tracks, obj)
if SETTINGS.downloadVideos:
downloadVideos(videos, obj)
def start_track(obj: Track):
album = TIDAL_API.getAlbum(obj.album.id)
if SETTINGS.saveCovers:
downloadCover(album)
downloadTrack(obj, album)
def start_video(obj: Video):
downloadVideo(obj, obj.album)
def start_artist(obj: Artist):
albums = TIDAL_API.getArtistAlbums(obj.id, SETTINGS.includeEP)
Printf.artist(obj, len(albums))
for item in albums:
start_album(item)
def start_playlist(obj: Playlist):
Printf.playlist(obj)
tracks, videos = TIDAL_API.getItems(obj.uuid, Type.Playlist)
downloadTracks(tracks, None, obj)
if SETTINGS.downloadVideos:
downloadVideos(videos, None, obj)
def start_mix(obj: Mix):
Printf.mix(obj)
downloadTracks(obj.tracks, None, None)
downloadVideos(obj.videos, None, None)
def start_file(string):
txt = aigpy.file.getContent(string)
if aigpy.string.isNull(txt):
Printf.err("Nothing can read!")
return
array = txt.split('\n')
for item in array:
if aigpy.string.isNull(item):
continue
if item[0] == '#':
continue
if item[0] == '[':
continue
start(item)
def start_type(etype: Type, obj):
if etype == Type.Album:
start_album(obj)
elif etype == Type.Track:
start_track(obj)
elif etype == Type.Video:
start_video(obj)
elif etype == Type.Artist:
start_artist(obj)
elif etype == Type.Playlist:
start_playlist(obj)
elif etype == Type.Mix:
start_mix(obj)
def start(string):
if aigpy.string.isNull(string):
Printf.err('Please enter something.')
return
strings = string.split(" ")
for item in strings:
if aigpy.string.isNull(item):
continue
if os.path.exists(item):
start_file(item)
return
try:
etype, obj = TIDAL_API.getByString(item)
except Exception as e:
Printf.err(str(e) + " [" + item + "]")
return
try:
start_type(etype, obj)
except Exception as e:
Printf.err(str(e))
'''
=================================
CHANGE SETTINGS
=================================
'''
def changePathSettings():
Printf.settings()
SETTINGS.downloadPath = Printf.enterPath(
LANG.select.CHANGE_DOWNLOAD_PATH,
LANG.select.MSG_PATH_ERR,
'0',
SETTINGS.downloadPath)
SETTINGS.albumFolderFormat = Printf.enterFormat(
LANG.select.CHANGE_ALBUM_FOLDER_FORMAT,
SETTINGS.albumFolderFormat,
SETTINGS.getDefaultPathFormat(Type.Album))
SETTINGS.playlistFolderFormat = Printf.enterFormat(
LANG.select.CHANGE_PLAYLIST_FOLDER_FORMAT,
SETTINGS.playlistFolderFormat,
SETTINGS.getDefaultPathFormat(Type.Playlist))
SETTINGS.trackFileFormat = Printf.enterFormat(
LANG.select.CHANGE_TRACK_FILE_FORMAT,
SETTINGS.trackFileFormat,
SETTINGS.getDefaultPathFormat(Type.Track))
SETTINGS.videoFileFormat = Printf.enterFormat(
LANG.select.CHANGE_VIDEO_FILE_FORMAT,
SETTINGS.videoFileFormat,
SETTINGS.getDefaultPathFormat(Type.Video))
SETTINGS.save()
def changeQualitySettings():
Printf.settings()
SETTINGS.audioQuality = AudioQuality(
int(Printf.enterLimit(LANG.select.CHANGE_AUDIO_QUALITY,
LANG.select.MSG_INPUT_ERR,
['0', '1', '2', '3', '4'])))
SETTINGS.videoQuality = VideoQuality(
int(Printf.enterLimit(LANG.select.CHANGE_VIDEO_QUALITY,
LANG.select.MSG_INPUT_ERR,
['1080', '720', '480', '360'])))
SETTINGS.save()
def changeSettings():
Printf.settings()
SETTINGS.showProgress = Printf.enterBool(LANG.select.CHANGE_SHOW_PROGRESS)
SETTINGS.showTrackInfo = Printf.enterBool(LANG.select.CHANGE_SHOW_TRACKINFO)
SETTINGS.checkExist = Printf.enterBool(LANG.select.CHANGE_CHECK_EXIST)
SETTINGS.includeEP = Printf.enterBool(LANG.select.CHANGE_INCLUDE_EP)
SETTINGS.saveCovers = Printf.enterBool(LANG.select.CHANGE_SAVE_COVERS)
SETTINGS.saveAlbumInfo = Printf.enterBool(LANG.select.CHANGE_SAVE_ALBUM_INFO)
SETTINGS.downloadVideos = Printf.enterBool(LANG.select.CHANGE_DOWNLOAD_VIDEOS)
SETTINGS.lyricFile = Printf.enterBool(LANG.select.CHANGE_ADD_LRC_FILE)
SETTINGS.multiThread = Printf.enterBool(LANG.select.CHANGE_MULITHREAD_DOWNLOAD)
SETTINGS.usePlaylistFolder = Printf.enterBool(LANG.select.SETTING_USE_PLAYLIST_FOLDER + "('0'-No,'1'-Yes):")
SETTINGS.downloadDelay = Printf.enterBool(LANG.select.CHANGE_USE_DOWNLOAD_DELAY)
SETTINGS.language = Printf.enter(LANG.select.CHANGE_LANGUAGE + "(" + LANG.getLangChoicePrint() + "):")
LANG.setLang(SETTINGS.language)
SETTINGS.save()
def changeApiKey():
item = apiKey.getItem(SETTINGS.apiKeyIndex)
ver = apiKey.getVersion()
Printf.info(f'Current APIKeys: {str(SETTINGS.apiKeyIndex)} {item["platform"]}-{item["formats"]}')
Printf.info(f'Current Version: {str(ver)}')
Printf.apikeys(apiKey.getItems())
index = int(Printf.enterLimit("APIKEY index:", LANG.select.MSG_INPUT_ERR, apiKey.getLimitIndexs()))
if index != SETTINGS.apiKeyIndex:
SETTINGS.apiKeyIndex = index
SETTINGS.save()
TIDAL_API.apiKey = apiKey.getItem(index)
return True
return False
'''
=================================
LOGIN
=================================
'''
def __displayTime__(seconds, granularity=2):
if seconds <= 0:
return "unknown"
result = []
intervals = (
('weeks', 604800),
('days', 86400),
('hours', 3600),
('minutes', 60),
('seconds', 1),
)
for name, count in intervals:
value = seconds // count
if value:
seconds -= value * count
if value == 1:
name = name.rstrip('s')
result.append("{} {}".format(value, name))
return ', '.join(result[:granularity])
def loginByWeb():
try:
print(LANG.select.AUTH_START_LOGIN)
# get device code
url = TIDAL_API.getDeviceCode()
print(LANG.select.AUTH_NEXT_STEP.format(
aigpy.cmd.green(url),
aigpy.cmd.yellow(__displayTime__(TIDAL_API.key.authCheckTimeout))))
print(LANG.select.AUTH_WAITING)
start = time.time()
elapsed = 0
while elapsed < TIDAL_API.key.authCheckTimeout:
elapsed = time.time() - start
if not TIDAL_API.checkAuthStatus():
time.sleep(TIDAL_API.key.authCheckInterval + 1)
continue
Printf.success(LANG.select.MSG_VALID_ACCESSTOKEN.format(
__displayTime__(int(TIDAL_API.key.expiresIn))))
TOKEN.userid = TIDAL_API.key.userId
TOKEN.countryCode = TIDAL_API.key.countryCode
TOKEN.accessToken = TIDAL_API.key.accessToken
TOKEN.refreshToken = TIDAL_API.key.refreshToken
TOKEN.expiresAfter = time.time() + int(TIDAL_API.key.expiresIn)
TOKEN.save()
return True
raise Exception(LANG.select.AUTH_TIMEOUT)
except Exception as e:
Printf.err(f"Login failed.{str(e)}")
return False
def loginByConfig():
try:
if aigpy.string.isNull(TOKEN.accessToken):
return False
if TIDAL_API.verifyAccessToken(TOKEN.accessToken):
Printf.info(LANG.select.MSG_VALID_ACCESSTOKEN.format(
__displayTime__(int(TOKEN.expiresAfter - time.time()))))
TIDAL_API.key.countryCode = TOKEN.countryCode
TIDAL_API.key.userId = TOKEN.userid
TIDAL_API.key.accessToken = TOKEN.accessToken
return True
Printf.info(LANG.select.MSG_INVALID_ACCESSTOKEN)
if TIDAL_API.refreshAccessToken(TOKEN.refreshToken):
Printf.success(LANG.select.MSG_VALID_ACCESSTOKEN.format(
__displayTime__(int(TIDAL_API.key.expiresIn))))
TOKEN.userid = TIDAL_API.key.userId
TOKEN.countryCode = TIDAL_API.key.countryCode
TOKEN.accessToken = TIDAL_API.key.accessToken
TOKEN.expiresAfter = time.time() + int(TIDAL_API.key.expiresIn)
TOKEN.save()
return True
else:
TokenSettings().save()
return False
except Exception as e:
return False
def loginByAccessToken():
try:
print("-------------AccessToken---------------")
token = Printf.enter("accessToken('0' go back):")
if token == '0':
return
TIDAL_API.loginByAccessToken(token, TOKEN.userid)
except Exception as e:
Printf.err(str(e))
return
print("-------------RefreshToken---------------")
refreshToken = Printf.enter("refreshToken('0' to skip):")
if refreshToken == '0':
refreshToken = TOKEN.refreshToken
TOKEN.accessToken = token
TOKEN.refreshToken = refreshToken
TOKEN.expiresAfter = 0
TOKEN.countryCode = TIDAL_API.key.countryCode
TOKEN.save()
+300
View File
@@ -0,0 +1,300 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : test.py
@Date : 2022/03/28
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
"""
import importlib
import sys
import _thread
from events import *
from printf import *
def enableGui():
try:
importlib.import_module('PyQt5')
importlib.import_module('qt_material')
return True
except Exception as e:
return False
if not enableGui():
def startGui():
Printf.err("Not support gui. Please type: `pip3 install PyQt5 qt_material`")
else:
from PyQt5.QtCore import Qt, QObject
from PyQt5.QtGui import QTextCursor, QKeyEvent
from PyQt5.QtCore import pyqtSignal
from PyQt5 import QtWidgets
from qt_material import apply_stylesheet
class EmittingStream(QObject):
textWritten = pyqtSignal(str)
def write(self, text):
self.textWritten.emit(str(text))
class MainView(QtWidgets.QWidget):
s_downloadEnd = pyqtSignal(str, bool, str)
def __init__(self, ) -> None:
super().__init__()
self.initView()
self.setMinimumSize(800, 620)
self.setWindowTitle("TIDAL-DL")
def __info__(self, msg):
QtWidgets.QMessageBox.information(self, 'Info', msg, QtWidgets.QMessageBox.Yes)
def __output__(self, text):
cursor = self.c_printTextEdit.textCursor()
cursor.movePosition(QTextCursor.End)
cursor.insertText(text)
self.c_printTextEdit.setTextCursor(cursor)
self.c_printTextEdit.ensureCursorVisible()
def initView(self):
self.c_lineSearch = QtWidgets.QLineEdit()
self.c_btnSearch = QtWidgets.QPushButton("Search")
self.c_btnDownload = QtWidgets.QPushButton("Download")
self.c_combType = QtWidgets.QComboBox()
self.c_combTQuality = QtWidgets.QComboBox()
self.c_combVQuality = QtWidgets.QComboBox()
# Supported types for search
self.m_supportType = [Type.Album, Type.Playlist, Type.Track, Type.Video, Type.Artist]
for item in self.m_supportType:
self.c_combType.addItem(item.name, item)
for item in AudioQuality:
self.c_combTQuality.addItem(item.name, item)
for item in VideoQuality:
self.c_combVQuality.addItem(item.name, item)
self.c_combTQuality.setCurrentText(SETTINGS.audioQuality.name)
self.c_combVQuality.setCurrentText(SETTINGS.videoQuality.name)
# init table
columnNames = ['#', 'Title', 'Artists', 'Quality']
self.c_tableInfo = QtWidgets.QTableWidget()
self.c_tableInfo.setColumnCount(len(columnNames))
self.c_tableInfo.setRowCount(0)
self.c_tableInfo.setShowGrid(False)
self.c_tableInfo.verticalHeader().setVisible(False)
self.c_tableInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.c_tableInfo.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.c_tableInfo.horizontalHeader().setStretchLastSection(True)
self.c_tableInfo.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeMode.ResizeToContents)
self.c_tableInfo.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.c_tableInfo.setFocusPolicy(Qt.NoFocus)
for index, name in enumerate(columnNames):
item = QtWidgets.QTableWidgetItem(name)
self.c_tableInfo.setHorizontalHeaderItem(index, item)
# Create Tree View for playlists.
self.tree_playlists = QtWidgets.QTreeWidget()
self.tree_playlists.setAnimated(False)
self.tree_playlists.setIndentation(20)
self.tree_playlists.setSortingEnabled(True)
self.tree_playlists.setFixedWidth(200)
self.tree_playlists.setColumnCount(1)
self.tree_playlists.setHeaderLabels(("User Playlists",))
# self.tree_playlists.setColumnWidth(0, 100)
self.tree_playlists.setContextMenuPolicy(Qt.CustomContextMenu)
# print
self.c_printTextEdit = QtWidgets.QTextEdit()
self.c_printTextEdit.setReadOnly(True)
self.c_printTextEdit.setFixedHeight(100)
sys.stdout = EmittingStream(textWritten=self.__output__)
sys.stderr = EmittingStream(textWritten=self.__output__)
# layout
self.lineGrid = QtWidgets.QHBoxLayout()
self.lineGrid.addWidget(self.c_combType)
self.lineGrid.addWidget(self.c_lineSearch)
self.lineGrid.addWidget(self.c_btnSearch)
self.line2Grid = QtWidgets.QHBoxLayout()
self.line2Grid.addWidget(QtWidgets.QLabel("QUALITY:"))
self.line2Grid.addWidget(self.c_combTQuality)
self.line2Grid.addWidget(self.c_combVQuality)
self.line2Grid.addStretch(4)
self.line2Grid.addWidget(self.c_btnDownload)
self.funcGrid = QtWidgets.QVBoxLayout()
self.funcGrid.addLayout(self.lineGrid)
self.funcGrid.addWidget(self.c_tableInfo)
self.funcGrid.addLayout(self.line2Grid)
self.funcGrid.addWidget(self.c_printTextEdit)
self.mainGrid = QtWidgets.QHBoxLayout(self)
self.mainGrid.addWidget(self.tree_playlists)
self.mainGrid.addLayout(self.funcGrid)
# connect
self.c_btnSearch.clicked.connect(self.search)
self.c_lineSearch.returnPressed.connect(self.search)
self.c_btnDownload.clicked.connect(self.download)
self.s_downloadEnd.connect(self.downloadEnd)
self.c_combTQuality.currentIndexChanged.connect(self.changeTQuality)
self.c_combVQuality.currentIndexChanged.connect(self.changeVQuality)
self.tree_playlists.itemClicked.connect(self.__displayTracks__)
def keyPressEvent(self, event: QKeyEvent):
if event.modifiers() & Qt.MetaModifier and event.key() == Qt.Key_A:
self.c_tableInfo.selectAll()
def addItem(self, rowIdx: int, colIdx: int, text):
if isinstance(text, str):
item = QtWidgets.QTableWidgetItem(text)
self.c_tableInfo.setItem(rowIdx, colIdx, item)
def search(self):
self.c_tableInfo.setRowCount(0)
self.s_type = self.c_combType.currentData()
self.s_text = self.c_lineSearch.text()
if self.s_text.startswith('http'):
tmpType, tmpId = TIDAL_API.parseUrl(self.s_text)
if tmpType == Type.Null:
self.__info__('Url not support')
return
elif tmpType not in self.m_supportType:
self.__info__(f'Type[{tmpType.name}] not support')
return
tmpData = TIDAL_API.getTypeData(tmpId, tmpType)
if tmpData is None:
self.__info__('Url is wrong!')
return
self.s_type = tmpType
self.s_array = [tmpData]
self.s_result = None
self.c_combType.setCurrentText(tmpType.name)
else:
self.s_result = TIDAL_API.search(self.s_text, self.s_type)
self.s_array = TIDAL_API.getSearchResultItems(self.s_result, self.s_type)
if len(self.s_array) <= 0:
self.__info__('No result')
return
self.setSearchResults(self.s_array, self.s_type)
def setSearchResults(self, s_array, s_type):
self.c_tableInfo.clearSelection()
self.c_tableInfo.setRowCount(len(s_array))
for index, item in enumerate(s_array):
self.addItem(index, 0, str(index + 1))
if s_type in [Type.Album, Type.Track]:
self.addItem(index, 1, item.title)
self.addItem(index, 2, TIDAL_API.getArtistsName(item.artists))
self.addItem(index, 3, item.audioQuality)
elif s_type in [Type.Video]:
self.addItem(index, 1, item.title)
self.addItem(index, 2, TIDAL_API.getArtistsName(item.artists))
self.addItem(index, 3, item.quality)
elif s_type in [Type.Playlist]:
self.addItem(index, 1, item.title)
self.addItem(index, 2, '')
self.addItem(index, 3, '')
elif s_type in [Type.Artist]:
self.addItem(index, 1, item.name)
self.addItem(index, 2, '')
self.addItem(index, 3, '')
self.c_tableInfo.viewport().update()
def download(self):
if self.c_tableInfo.selectionModel().hasSelection() == False:
self.__info__('Please select a row first.')
return
rows = self.c_tableInfo.selectionModel().selectedRows()
items = []
for row in rows:
items.append(self.s_array[row.row()])
self.__downloadFunc__(items)
def __downloadFunc__(self, items):
self.c_btnDownload.setEnabled(False)
def __thread_download__(model: MainView, items):
itemTitle = ''
type = model.s_type
try:
for item in items:
if isinstance(item, Artist):
itemTitle = item.name
else:
itemTitle = item.title
start_type(type, item)
model.s_downloadEnd.emit('Download Success!', True, '')
except Exception as e:
model.s_downloadEnd.emit(itemTitle, False, str(e))
_thread.start_new_thread(__thread_download__, (self, items))
def downloadEnd(self, title, result, msg):
self.c_btnDownload.setEnabled(True)
self.c_btnDownload.setText(f"Download")
if result:
self.__info__(f"Download finished.")
else:
self.__info__(f"Download '{title}' failed:{msg}")
def checkLogin(self):
if not loginByConfig():
self.__info__('Login failed. Please log in using the command line first.')
else:
self.__showSelfPlaylists__()
def changeTQuality(self, index):
SETTINGS.audioQuality = self.c_combTQuality.itemData(index)
SETTINGS.save()
def changeVQuality(self, index):
SETTINGS.videoQuality = self.c_combVQuality.itemData(index)
SETTINGS.save()
def __showSelfPlaylists__(self):
playlists = TIDAL_API.getPlaylistSelf()
for playlist in playlists:
item = QtWidgets.QTreeWidgetItem(self.tree_playlists)
item.setText(0, playlist.title)
item.setText(1, str(playlist.numberOfTracks))
item.setText(2, playlist.uuid)
def __displayTracks__(self, item, column):
tracks, videos = TIDAL_API.getItems(item.text(2), Type.Playlist)
self.s_array = tracks
self.s_type = Type.Track
self.setSearchResults(tracks, Type.Track)
def startGui():
aigpy.cmd.enableColor(False)
app = QtWidgets.QApplication(sys.argv)
apply_stylesheet(app, theme='dark_blue.xml')
window = MainView()
window.show()
window.checkLogin()
app.exec_()
if __name__ == '__main__':
SETTINGS.read(getProfilePath())
TOKEN.read(getTokenPath())
startGui()
+20 -7
View File
@@ -30,14 +30,20 @@ class LangArabic(object):
SETTING_USE_PLAYLIST_FOLDER = "Use playlist folder"
SETTING_MULITHREAD_DOWNLOAD = "Multi thread download"
SETTING_ALBUM_FOLDER_FORMAT = "Album folder format"
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
SETTING_TRACK_FILE_FORMAT = "Track file format"
SETTING_VIDEO_FILE_FORMAT = "Video file format"
SETTING_SHOW_PROGRESS = "Show progress"
SETTING_SHOW_TRACKIFNO = "Show Track Info"
SETTING_SHOW_TRACKINFO = "Show Track Info"
SETTING_SAVE_ALBUMINFO = "Save AlbumInfo.txt"
SETTING_DOWNLOAD_VIDEOS = "Download videos"
SETTING_ADD_LYRICS = "Add lyrics"
SETTING_LYRICS_SERVER_PROXY = "Lyrics server proxy"
SETTING_PATH = "Settings path"
SETTINGS_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_APIKEY = "APIKey support"
SETTING_ADD_TYPE_FOLDER = "Add Type-Folder"
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
CHOICE = "خيار"
FUNCTION = "وظيفة"
@@ -49,6 +55,7 @@ class LangArabic(object):
CHOICE_SET_ACCESS_TOKEN = "اعداد AccessToken"
CHOICE_DOWNLOAD_BY_URL = "التحميل عبر الرابط او رقم التتبع"
CHOICE_LOGOUT = "Logout"
CHOICE_APIKEY = "Select APIKey"
PRINT_ERR = "[خطأ]"
PRINT_INFO = "[معلومة]"
@@ -61,7 +68,7 @@ class LangArabic(object):
CHANGE_START_SETTINGS = "بدء الاعدادات('0'-Return,'1'-Yes):"
CHANGE_DOWNLOAD_PATH = "مجلد التنزيل('0' not modify):"
CHANGE_AUDIO_QUALITY = "دقة الصوت('0'-Normal,'1'-High,'2'-HiFi,'3'-Master):"
CHANGE_AUDIO_QUALITY = "دقة الصوت('0'-Normal,'1'-High,'2'-HiFi,'3'-Master,'4'-Max):"
CHANGE_VIDEO_QUALITY = "دقة الفديو(1080, 720, 480, 360):"
CHANGE_ONLYM4A = "تحويل M4a الى mp4('0'-No,'1'-Yes):"
CHANGE_ADD_EXPLICIT_TAG = "اضافة توقيع الفنان('0'-No,'1'-Yes):"
@@ -74,14 +81,20 @@ class LangArabic(object):
CHANGE_ALBUMID_BEFORE_FOLDER = "اضف رقم التتبع قبل اسم مجلد الالبوم('0'-No,'1'-Yes):"
CHANGE_SAVE_COVERS = "حفظ صورة الالبوم('0'-No,'1'-Yes):"
CHANGE_LANGUAGE = "اختر لغة"
CHANGE_ALBUM_FOLDER_FORMAT = "Album folder format('0' not modify):"
CHANGE_TRACK_FILE_FORMAT = "Track file format('0' not modify):"
CHANGE_ALBUM_FOLDER_FORMAT = "Album folder format('0'-not modify,'default'-to set default):"
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
CHANGE_TRACK_FILE_FORMAT = "Track file format('0'-not modify,'default'-to set default):"
CHANGE_VIDEO_FILE_FORMAT = "Video file format('0'-not modify,'default'-to set default):"
CHANGE_SHOW_PROGRESS = "Show progress('0'-No,'1'-Yes):"
CHANGE_SHOW_TRACKINFO = "Show track info('0'-No,'1'-Yes):"
CHANGE_SAVE_ALBUM_INFO = "Save AlbumInfo.txt('0'-No,'1'-Yes):"
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "Add lyrics('0'-No,'1'-Yes):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0' not modify):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0'-not modify):"
CHANGE_ADD_LRC_FILE = "Save timed lyrics .lrc file ('0'-No,'1'-Yes):"
CHANGE_ADD_TYPE_FOLDER = "Add Type-Folder,eg Album/Video/Playlist('0'-No,'1'-Yes):"
CHANGE_MULITHREAD_DOWNLOAD = "Multi thread download('0'-No,'1'-Yes):"
CHANGE_USE_DOWNLOAD_DELAY = "Use Download Delay('0'-No,'1'-Yes):"
# {} are required in these strings
AUTH_START_LOGIN = "Starting login process..."
@@ -91,7 +104,7 @@ class LangArabic(object):
AUTH_TIMEOUT = "Operation timed out."
MSG_VALID_ACCESSTOKEN = "AccessToken good for {}."
MSG_INVAILD_ACCESSTOKEN = "Expired AccessToken. Attempting to refresh it."
MSG_INVALID_ACCESSTOKEN = "Expired AccessToken. Attempting to refresh it."
MSG_PATH_ERR = "!مجلد التنزيل خاطئ"
MSG_INPUT_ERR = "!ادخال خاطئ"
+23 -10
View File
@@ -15,7 +15,7 @@ class LangChinese(object):
VALUE = ""
SETTING_DOWNLOAD_PATH = "下载目录"
SETTING_ONLY_M4A = "转换mp4为m4a"
SETTING_ADD_EXPLICIT_TAG = "文件名添加脏话标签Explicit"
SETTING_ADD_EXPLICIT_TAG = "文件名添加脏Explicit"
SETTING_ADD_HYPHEN = "文件名用'-'代替空格"
SETTING_ADD_YEAR = "专辑文件夹添加年代标签"
SETTING_USE_TRACK_NUM = "歌曲名称添加序号"
@@ -30,25 +30,32 @@ class LangChinese(object):
SETTING_USE_PLAYLIST_FOLDER = "将歌单下载到歌单目录"
SETTING_MULITHREAD_DOWNLOAD = "多线程下载"
SETTING_ALBUM_FOLDER_FORMAT = "专辑目录格式"
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
SETTING_TRACK_FILE_FORMAT = "歌曲文件名格式"
SETTING_VIDEO_FILE_FORMAT = "视频文件格式"
SETTING_SHOW_PROGRESS = "显示进度条"
SETTING_SHOW_TRACKIFNO = "显示歌曲信息"
SETTING_SHOW_TRACKINFO = "显示歌曲信息"
SETTING_SAVE_ALBUMINFO = "保存AlbumInfo.txt"
SETTING_DOWNLOAD_VIDEOS = "Download videos"
SETTING_ADD_LYRICS = "添加歌词"
SETTING_LYRICS_SERVER_PROXY = "歌词服务器代理"
SETTING_PATH = "Settings path"
SETTINGS_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_ADD_LRC_FILE = "保存歌词文件 (.lrc file)"
SETTING_PATH = "配置文件目录"
SETTING_APIKEY = "APIKey支持"
SETTING_ADD_TYPE_FOLDER = "添加类型文件夹"
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
CHOICE = "选项"
FUNCTION = "功能"
CHOICE_ENTER = "输入"
CHOICE_ENTER_URLID = "输入 'Url或ID':"
CHOICE_EXIT = "退出"
CHOICE_LOGIN = "Check AccessToken"
CHOICE_LOGIN = "检查AccessToken"
CHOICE_SETTINGS = "配置"
CHOICE_SET_ACCESS_TOKEN = "设置AccessToken"
CHOICE_DOWNLOAD_BY_URL = "通过链接或ID下载"
CHOICE_LOGOUT = "注销"
CHOICE_APIKEY = "选择APIKey"
PRINT_ERR = "[错误]"
PRINT_INFO = "[提示]"
@@ -61,7 +68,7 @@ class LangChinese(object):
CHANGE_START_SETTINGS = "开始设置('0'-返回,'1'-是):"
CHANGE_DOWNLOAD_PATH = "下载路径('0' 不修改):"
CHANGE_AUDIO_QUALITY = "音频质量('0'-Normal,'1'-High,'2'-HiFi,'3'-Master):"
CHANGE_AUDIO_QUALITY = "音频质量('0'-Normal,'1'-High,'2'-HiFi,'3'-Master,'4'-Max):"
CHANGE_VIDEO_QUALITY = "视频质量(1080, 720, 480, 360):"
CHANGE_ONLYM4A = "将Mp4格式的音频转为M4a('0'-不,'1'-是):"
CHANGE_ADD_EXPLICIT_TAG = "歌名后添加脏话标签('0'-不,'1'-是):"
@@ -75,13 +82,19 @@ class LangChinese(object):
CHANGE_SAVE_COVERS = "保存封面('0'-不,'1'-是):"
CHANGE_LANGUAGE = "选择语言"
CHANGE_ALBUM_FOLDER_FORMAT = "专辑目录格式('0' 不修改):"
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
CHANGE_TRACK_FILE_FORMAT = "歌曲文件名格式('0' 不修改):"
CHANGE_VIDEO_FILE_FORMAT = "视频文件名格式('0'-not modify,'default'-to set default):"
CHANGE_SHOW_PROGRESS = "显示进度条('0'-不,'1'-是):"
CHANGE_SHOW_TRACKINFO = "显示歌曲信息('0'-否,'1'-是):"
CHANGE_SAVE_ALBUM_INFO = "保存AlbumInfo.txt('0'-否,'1'-是):"
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "添加歌词('0'-否,'1'-是):"
CHANGE_LYRICS_SERVER_PROXY = "歌词服务器代理('0' 不修改):"
CHANGE_ADD_LRC_FILE = "Save timed lyrics .lrc file ('0'-否,'1'-是):"
CHANGE_ADD_LRC_FILE = "保存歌词文件 ('0'-否,'1'-是):"
CHANGE_ADD_TYPE_FOLDER = "Add Type-Folder,eg Album/Video/Playlist('0'-No,'1'-Yes):"
CHANGE_MULITHREAD_DOWNLOAD = "多线程下载('0'-否,'1'-是):"
CHANGE_USE_DOWNLOAD_DELAY = "Use Download Delay('0'-No,'1'-Yes):"
# {} are required in these strings
AUTH_START_LOGIN = "开始启动登录..."
@@ -90,8 +103,8 @@ class LangChinese(object):
AUTH_WAITING = "等待登录验证..."
AUTH_TIMEOUT = "操作超时."
MSG_VALID_ACCESSTOKEN = "AccessToken保质期为 {}."
MSG_INVAILD_ACCESSTOKEN = "AccessToken失效. 正在尝试更新它."
MSG_VALID_ACCESSTOKEN = "AccessToken有效期为 {}."
MSG_INVALID_ACCESSTOKEN = "AccessToken失效. 正在尝试更新它."
MSG_PATH_ERR = "路径错误!"
MSG_INPUT_ERR = "输入错误!"
@@ -106,7 +119,7 @@ class LangChinese(object):
MODEL_VIDEO_NUMBER = '视频数量'
MODEL_RELEASE_DATE = '发布时间'
MODEL_VERSION = '版本'
MODEL_EXPLICIT = '话标志'
MODEL_EXPLICIT = ''
MODEL_ALBUM = '专辑'
MODEL_ID = 'ID'
MODEL_NAME = '名称'
+20 -7
View File
@@ -30,14 +30,20 @@ class LangCroatian(object):
SETTING_USE_PLAYLIST_FOLDER = "Use playlist folder"
SETTING_MULITHREAD_DOWNLOAD = "Multi thread download"
SETTING_ALBUM_FOLDER_FORMAT = "Album folder format"
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
SETTING_TRACK_FILE_FORMAT = "Track file format"
SETTING_VIDEO_FILE_FORMAT = "Video file format"
SETTING_SHOW_PROGRESS = "Show progress"
SETTING_SHOW_TRACKIFNO = "Show Track Info"
SETTING_SHOW_TRACKINFO = "Show Track Info"
SETTING_SAVE_ALBUMINFO = "Save AlbumInfo.txt"
SETTING_DOWNLOAD_VIDEOS = "Download videos"
SETTING_ADD_LYRICS = "Add lyrics"
SETTING_LYRICS_SERVER_PROXY = "Lyrics server proxy"
SETTING_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_PATH = "Settings path"
SETTINGS_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_APIKEY = "APIKey support"
SETTING_ADD_TYPE_FOLDER = "Add Type-Folder"
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
CHOICE = "ODABIR"
FUNCTION = "FUNKCIJA"
@@ -49,6 +55,7 @@ class LangCroatian(object):
CHOICE_SET_ACCESS_TOKEN = "Postavi AccessToken"
CHOICE_DOWNLOAD_BY_URL = "Preuzmi po url-u ili ID-u"
CHOICE_LOGOUT = "Logout"
CHOICE_APIKEY = "Select APIKey"
PRINT_ERR = "[ERR]"
PRINT_INFO = "[INFO]"
@@ -61,7 +68,7 @@ class LangCroatian(object):
CHANGE_START_SETTINGS = "Pokreni postavke (0'-Izlaz,'1'-Da):"
CHANGE_DOWNLOAD_PATH = "Putanja preuzimanja('0' ne mijenjaj):"
CHANGE_AUDIO_QUALITY = "Kvaliteta zvuka('0'-Normalna,'1'-Visoka,'2'-HiFi,'3'-Master):"
CHANGE_AUDIO_QUALITY = "Kvaliteta zvuka('0'-Normalna,'1'-Visoka,'2'-HiFi,'3'-Master,'4'-Max):"
CHANGE_VIDEO_QUALITY = "Kvaliteta videozapisa(1080, 720, 480, 360):"
CHANGE_ONLYM4A = "Pretvori mp4 u m4a('0'-Ne,'1'-Da):"
CHANGE_ADD_EXPLICIT_TAG = "Dodaj eksplicitni znak u imeni datoteke('0'-Ne,'1'-Da):"
@@ -74,14 +81,20 @@ class LangCroatian(object):
CHANGE_ALBUMID_BEFORE_FOLDER = "Dodaj ID oznaku prije imena albuma u datoteci('0'-Ne,'1'-Da):"
CHANGE_SAVE_COVERS = "Spremi ilustracije albuma('0'-Ne,'1'-Da):"
CHANGE_LANGUAGE = "Odaberi jezik"
CHANGE_ALBUM_FOLDER_FORMAT = "Album folder format('0' not modify):"
CHANGE_TRACK_FILE_FORMAT = "Track file format('0' not modify):"
CHANGE_ALBUM_FOLDER_FORMAT = "Album folder format('0'-not modify,'default'-to set default):"
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
CHANGE_TRACK_FILE_FORMAT = "Track file format('0'-not modify,'default'-to set default):"
CHANGE_VIDEO_FILE_FORMAT = "Video file format('0'-not modify,'default'-to set default):"
CHANGE_SHOW_PROGRESS = "Show progress('0'-No,'1'-Yes):"
CHANGE_SHOW_TRACKINFO = "Show track info('0'-No,'1'-Yes):"
CHANGE_SAVE_ALBUM_INFO = "Save AlbumInfo.txt('0'-No,'1'-Yes):"
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "Add lyrics('0'-No,'1'-Yes):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0' not modify):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0'-not modify):"
CHANGE_ADD_LRC_FILE = "Save timed lyrics .lrc file ('0'-No,'1'-Yes):"
CHANGE_ADD_TYPE_FOLDER = "Add Type-Folder,eg Album/Video/Playlist('0'-No,'1'-Yes):"
CHANGE_MULITHREAD_DOWNLOAD = "Multi thread download('0'-No,'1'-Yes):"
CHANGE_USE_DOWNLOAD_DELAY = "Use Download Delay('0'-No,'1'-Yes):"
# {} are required in these strings
AUTH_START_LOGIN = "Starting login process..."
@@ -91,7 +104,7 @@ class LangCroatian(object):
AUTH_TIMEOUT = "Operation timed out."
MSG_VALID_ACCESSTOKEN = "AccessToken good for {}."
MSG_INVAILD_ACCESSTOKEN = "Expired AccessToken. Attempting to refresh it."
MSG_INVALID_ACCESSTOKEN = "Expired AccessToken. Attempting to refresh it."
MSG_PATH_ERR = "Pogreska putanje!"
MSG_INPUT_ERR = "Pogreska unosa!"
+73 -60
View File
@@ -2,10 +2,10 @@
# -*- encoding: utf-8 -*-
'''
@File : czech.py
@Time : 2020/08/20
@Author : Tomikk
@Version : 1.0
@Contact : justtomikk@gmail.com
@Time : 2022/11/13
@Author : Tomikk & Sweder
@Version : 1.2
@Contact : justtomikk@gmail.com & djsweder@gmail.com
@Desc :
'''
@@ -15,42 +15,49 @@ class LangCzech(object):
VALUE = "Hodnota"
SETTING_DOWNLOAD_PATH = "Umístění staženého souboru"
SETTING_ONLY_M4A = "Konvertovat mp4 na m4a"
SETTING_ADD_EXPLICIT_TAG = "Přidat explicitní značku"
SETTING_ADD_HYPHEN = "Používat pomlčky místo mezer"
SETTING_ADD_EXPLICIT_TAG = "Přidat označení explicity"
SETTING_ADD_HYPHEN = "Místo mezer použít pomlčky"
SETTING_ADD_YEAR = "Přidat rok před jméno složky"
SETTING_USE_TRACK_NUM = "Přidat číslo skladby"
SETTING_AUDIO_QUALITY = "Kvalita hudby"
SETTING_VIDEO_QUALITY = "Kvalita videa"
SETTING_CHECK_EXIST = "Zkontrolovat jestli soubor již existuje"
SETTING_CHECK_EXIST = "Zkontrolovat existenci souboru"
SETTING_ARTIST_BEFORE_TITLE = "Jméno interpreta před jménem skladby"
SETTING_ALBUMID_BEFORE_FOLDER = "Id před složkou alba"
SETTING_INCLUDE_EP = "Zahrnout single&ep"
SETTING_INCLUDE_EP = "Zahrnout singly & EP"
SETTING_SAVE_COVERS = "Uložit obal alba"
SETTING_LANGUAGE = "Změna jazyka"
SETTING_USE_PLAYLIST_FOLDER = "Use playlist folder"
SETTING_MULITHREAD_DOWNLOAD = "Multi thread download"
SETTING_ALBUM_FOLDER_FORMAT = "Album folder format"
SETTING_TRACK_FILE_FORMAT = "Track file format"
SETTING_SHOW_PROGRESS = "Show progress"
SETTING_SHOW_TRACKIFNO = "Show Track Info"
SETTING_SAVE_ALBUMINFO = "Save AlbumInfo.txt"
SETTING_ADD_LYRICS = "Add lyrics"
SETTING_LYRICS_SERVER_PROXY = "Lyrics server proxy"
SETTINGS_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_PATH = "Settings path"
SETTING_USE_PLAYLIST_FOLDER = "Používat složku playlistu"
SETTING_MULITHREAD_DOWNLOAD = "Stahování více vlákny"
SETTING_ALBUM_FOLDER_FORMAT = "Formát názvu složky alba"
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
SETTING_TRACK_FILE_FORMAT = "Formát názvu souboru skladby"
SETTING_VIDEO_FILE_FORMAT = "Formát názvu souboru videa"
SETTING_SHOW_PROGRESS = "Zobrazit indikátor stavu stahování"
SETTING_SHOW_TRACKINFO = "Zobrazit informace o skladbě"
SETTING_SAVE_ALBUMINFO = "Uložit soubor AlbumInfo.txt"
SETTING_DOWNLOAD_VIDEOS = "Download videos"
SETTING_ADD_LYRICS = "Přidat texty skladeb"
SETTING_LYRICS_SERVER_PROXY = "Server proxy pro texty skladeb"
SETTING_ADD_LRC_FILE = "Uložit slova skladby s časováním (soubor .lrc)"
SETTING_PATH = "Cesta k souboru s nastavením"
SETTING_APIKEY = "APIKey podporuje"
SETTING_ADD_TYPE_FOLDER = "Složky dle typu obsahu"
SETTING_DOWNLOAD_DELAY = "Stahovat s časovou prodlevou"
CHOICE = "Výběr"
FUNCTION = "Funkce"
CHOICE_ENTER = "Enter"
CHOICE_ENTER = "Zvolit"
CHOICE_ENTER_URLID = "Vložit 'Url/ID':"
CHOICE_EXIT = "Ukončit"
CHOICE_LOGIN = "Check AccessToken"
CHOICE_LOGIN = "Zkontrolovat přístupový token"
CHOICE_SETTINGS = "Nastavení"
CHOICE_SET_ACCESS_TOKEN = "Nastavit přístupový token"
CHOICE_DOWNLOAD_BY_URL = "Stáhnout buď url nebo id"
CHOICE_LOGOUT = "Logout"
CHOICE_DOWNLOAD_BY_URL = "Stáhnout buď dle URL nebo ID"
CHOICE_LOGOUT = "Odhlásit"
CHOICE_APIKEY = "Vybrat APIKey"
PRINT_ERR = "[Error]"
PRINT_ERR = "[Chyba]"
PRINT_INFO = "[Info]"
PRINT_SUCCESS = "[Staženo]"
@@ -59,54 +66,60 @@ class LangCzech(object):
# PRINT_USERNAME = "přihlašovací jméno:"
# PRINT_PASSWORD = "heslo"
CHANGE_START_SETTINGS = "Start settings('0'-Zpět,'1'-Ano):"
CHANGE_DOWNLOAD_PATH = "Cesta stažení('0' not modify):"
CHANGE_AUDIO_QUALITY = "Kvalita hudby('0'-Normal,'1'-High,'2'-HiFi,'3'-Master):"
CHANGE_VIDEO_QUALITY = "Kvalita videa(1080, 720, 480, 360):"
CHANGE_ONLYM4A = "Konvertovat mp4 na m4a('0'-Ne,'1'-Ano):"
CHANGE_ADD_EXPLICIT_TAG = "Přidat explicitní značku k souborům('0'-Ne,'1'-Ano):"
CHANGE_ADD_HYPHEN = "V názvech souborů používat místo mezer pomlčky('0'-Ne,'1'-Ano):"
CHANGE_ADD_YEAR = "Přidat rok vydání do názvu složky('0'-Ne,'1'-Ano):"
CHANGE_USE_TRACK_NUM = "Přidat číslo skladby před název skladby('0'-Ne,'1'-Ano):"
CHANGE_CHECK_EXIST = "Zkontrolovat existujicí soubor před stažením('0'-Ne,'1'-Ano):"
CHANGE_ARTIST_BEFORE_TITLE = "Přidat jméno interpreta před názvem skladby('0'-Ne,'1'-Ano):"
CHANGE_INCLUDE_EP = "Při stahování alba interpreta zahrnout singly a EP('0'-Ne,'1'-Ano):"
CHANGE_ALBUMID_BEFORE_FOLDER = "Přidat ID před složku do alba('0'-Ne,'1'-Ano):"
CHANGE_SAVE_COVERS = "Uložit obaly alb('0'-Ne,'1'-Ano):"
CHANGE_START_SETTINGS = "Spustit nastavení ('0'-Zpět,'1'-Ano):"
CHANGE_DOWNLOAD_PATH = "Umístění stažených souborů ('0' beze změny):"
CHANGE_AUDIO_QUALITY = "Kvalita hudby ('0'-Normální,'1'-Vysoká,'2'-HiFi,'3'-Master,'4'-Max):"
CHANGE_VIDEO_QUALITY = "Kvalita videa (1080, 720, 480, 360):"
CHANGE_ONLYM4A = "Konvertovat mp4 na m4a ('0'-Ne,'1'-Ano):"
CHANGE_ADD_EXPLICIT_TAG = "Přidat označení explicity k souborům ('0'-Ne,'1'-Ano):"
CHANGE_ADD_HYPHEN = "V názvech souborů používat místo mezer pomlčky ('0'-Ne,'1'-Ano):"
CHANGE_ADD_YEAR = "Přidat rok vydání do názvu složky ('0'-Ne,'1'-Ano):"
CHANGE_USE_TRACK_NUM = "Přidat číslo skladby před název skladby ('0'-Ne,'1'-Ano):"
CHANGE_CHECK_EXIST = "Zkontrolovat existenci souboru před stažením ('0'-Ne,'1'-Ano):"
CHANGE_ARTIST_BEFORE_TITLE = "Přidat jméno interpreta před název skladby ('0'-Ne,'1'-Ano):"
CHANGE_INCLUDE_EP = "Při stahování alb interpreta zahrnout singly a EP ('0'-Ne,'1'-Ano):"
CHANGE_ALBUMID_BEFORE_FOLDER = "Přidat ID před název složky s albem ('0'-Ne,'1'-Ano):"
CHANGE_SAVE_COVERS = "Uložit obaly alb ('0'-Ne,'1'-Ano):"
CHANGE_LANGUAGE = "Zvolit jazyk"
CHANGE_ALBUM_FOLDER_FORMAT = "Album folder format('0' not modify):"
CHANGE_TRACK_FILE_FORMAT = "Track file format('0' not modify):"
CHANGE_SHOW_PROGRESS = "Show progress('0'-No,'1'-Yes):"
CHANGE_SHOW_TRACKINFO = "Show track info('0'-No,'1'-Yes):"
CHANGE_SAVE_ALBUM_INFO = "Save AlbumInfo.txt('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "Add lyrics('0'-No,'1'-Yes):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0' not modify):"
CHANGE_ADD_LRC_FILE = "Save timed lyrics .lrc file ('0'-No,'1'-Yes):"
CHANGE_ALBUM_FOLDER_FORMAT = "Formát názvu složky alba ('0' beze změny):"
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
CHANGE_TRACK_FILE_FORMAT = "Formát názvu složky skladny ('0' beze změny):"
CHANGE_VIDEO_FILE_FORMAT = "Formát názvu souboru videa ('0'-beze změny,'default'-pro nastavení výchozího názvu):"
CHANGE_SHOW_PROGRESS = "Zobrazit indikátor stavu stahování ('0'-Ne,'1'-Ano):"
CHANGE_SHOW_TRACKINFO = "Zobrazit info o skladbě ('0'-Ne,'1'-Ano):"
CHANGE_SAVE_ALBUM_INFO = "Uložit soubor AlbumInfo.txt ('0'-Ne,'1'-Ano):"
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "Přidat texty skladeb ('0'-Ne,'1'-Ano):"
CHANGE_LYRICS_SERVER_PROXY = "Server proxy pro texty skladeb ('0' beze změny):"
CHANGE_ADD_LRC_FILE = "Uložit slova skladby s časováním do souboru .lrc) ('0'-Ne,'1'-Ano):"
CHANGE_ADD_TYPE_FOLDER = "Ukládat do složek dle typu obsahu, např. Album/Video/Playlist ('0'-Ne,'1'-Ano):"
CHANGE_MULITHREAD_DOWNLOAD = "Více vláken pro stahování ('0'-Ne,'1'-Ano):"
CHANGE_USE_DOWNLOAD_DELAY = "Stahovat s časovou prodlevou('0'-Ne,'1'-Ano):"
# {} are required in these strings
AUTH_START_LOGIN = "Starting login process..."
AUTH_LOGIN_CODE = "Your login code is {}"
AUTH_NEXT_STEP = "Go to {} within the next {} to complete setup."
AUTH_WAITING = "Waiting for authorization..."
AUTH_TIMEOUT = "Operation timed out."
AUTH_START_LOGIN = "Spouštění přihlašovacího procesu..."
AUTH_LOGIN_CODE = "Váš přihlašovací kód je {}"
AUTH_NEXT_STEP = "K dokončení nastavení přejděte na stránku {} během následujích {}."
AUTH_WAITING = "Čeká se na autorizaci..."
AUTH_TIMEOUT = "Vypršel časový limit procesu."
MSG_VALID_ACCESSTOKEN = "AccessToken good for {}."
MSG_INVAILD_ACCESSTOKEN = "Expired AccessToken. Attempting to refresh it."
MSG_VALID_ACCESSTOKEN = "Přístupový token fukční pro {}."
MSG_INVALID_ACCESSTOKEN = "Platnost přístupového tokenu vypršela. Pokouším se o obnovení."
MSG_PATH_ERR = "Cesta neexistuje!"
MSG_INPUT_ERR = "Chyba vstupu!"
MSG_INPUT_ERR = "Chyba zadání!"
MODEL_ALBUM_PROPERTY = "ALBUM-PROPERTY"
MODEL_TRACK_PROPERTY = "TRACK-PROPERTY"
MODEL_VIDEO_PROPERTY = "VIDEO-PROPERTY"
MODEL_ARTIST_PROPERTY = "ARTIST-PROPERTY"
MODEL_PLAYLIST_PROPERTY = "PLAYLIST-PROPERTY"
MODEL_ALBUM_PROPERTY = "ALBUM-VLASTNOSTI"
MODEL_TRACK_PROPERTY = "SKLADBA-VLASTNOSTI"
MODEL_VIDEO_PROPERTY = "VIDEO-VLASTNOSTI"
MODEL_ARTIST_PROPERTY = "INTERPRET-VLASTNOSTI"
MODEL_PLAYLIST_PROPERTY = "PLAYLIST-VLASTNOSTI"
MODEL_TITLE = 'Název skladby'
MODEL_TRACK_NUMBER = 'Číslo skladby'
MODEL_VIDEO_NUMBER = 'Číslo videa'
MODEL_RELEASE_DATE = 'Datum vydání'
MODEL_VERSION = 'Verze'
MODEL_EXPLICIT = 'Explicit'
MODEL_EXPLICIT = 'Explicitní'
MODEL_ALBUM = 'Album'
MODEL_ID = 'ID'
MODEL_NAME = 'Jméno'
+126 -113
View File
@@ -1,113 +1,126 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : danish.py
@Time : 2021/03/25
@Author : KB885
@Version : 1.0
@Contact :
@Desc :
'''
class LangDanish(object):
SETTING = "INDSTILLINGER"
VALUE = "Værdi"
SETTING_DOWNLOAD_PATH = "Download sti"
SETTING_ONLY_M4A = "Konverter mp4 til m4a"
SETTING_ADD_EXPLICIT_TAG = "Tilføj eksplicit tag"
SETTING_ADD_HYPHEN = "Tilføj bindestreg"
SETTING_ADD_YEAR = "Tilføj år før album mappe"
SETTING_USE_TRACK_NUM = "Tilføj titelnummer"
SETTING_AUDIO_QUALITY = "Lydkvalitet"
SETTING_VIDEO_QUALITY = "Videokvalitet"
SETTING_CHECK_EXIST = "Kontroller eksistens"
SETTING_ARTIST_BEFORE_TITLE = "Kunstnernavn før titelnummer"
SETTING_ALBUMID_BEFORE_FOLDER = "Id før album mappe"
SETTING_INCLUDE_EP = "Inkluder single&ep"
SETTING_SAVE_COVERS = "Gem omslag"
SETTING_LANGUAGE = "Sprog"
SETTING_USE_PLAYLIST_FOLDER = "Brug afspilningsmappen"
SETTING_MULITHREAD_DOWNLOAD = "Flertråede download"
SETTING_ALBUM_FOLDER_FORMAT = "Albummappens format"
SETTING_TRACK_FILE_FORMAT = "Musiknummerets filformat"
SETTING_SHOW_PROGRESS = "Vis fremskridt"
SETTING_SHOW_TRACKIFNO = "Show Track Info"
SETTING_SAVE_ALBUMINFO = "Save AlbumInfo.txt"
SETTING_ADD_LYRICS = "Add lyrics"
SETTING_LYRICS_SERVER_PROXY = "Lyrics server proxy"
SETTING_PATH = "Settings path"
SETTINGS_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
CHOICE = "VALG"
FUNCTION = "FUNKTION"
CHOICE_ENTER = "Indtast"
CHOICE_ENTER_URLID = "Indtast 'Url/ID':"
CHOICE_EXIT = "Afslut"
CHOICE_LOGIN = "Kontroller AccessToken"
CHOICE_SETTINGS = "Indstillinger"
CHOICE_SET_ACCESS_TOKEN = "Sæt AccessToken"
CHOICE_DOWNLOAD_BY_URL = "Download via url eller id"
CHOICE_LOGOUT = "Log ud"
PRINT_ERR = "[FEJL]"
PRINT_INFO = "[INFO]"
PRINT_SUCCESS = "[SUCCES]"
PRINT_ENTER_CHOICE = "Indtast Valg:"
PRINT_LATEST_VERSION = "Seneste version:"
# PRINT_USERNAME = "username:"
# PRINT_PASSWORD = "password:"
CHANGE_START_SETTINGS = "Start indstillinger('0'-Tilbage,'1'-Ja):"
CHANGE_DOWNLOAD_PATH = "Download stil('0' ændrer ikke):"
CHANGE_AUDIO_QUALITY = "Lydkvalitet('0'-Normal,'1'-Høj,'2'-HiFi,'3'-Master):"
CHANGE_VIDEO_QUALITY = "Videokvalitet(1080, 720, 480, 360):"
CHANGE_ONLYM4A = "Konverter mp4 til m4a('0'-Nej,'1'-Ja):"
CHANGE_ADD_EXPLICIT_TAG = "Tilføj eksplicit tag til filnavne('0'-Nej,'1'-Ja):"
CHANGE_ADD_HYPHEN = "Brug bindestreger i stedet for mellemrum i filnavne('0'-Nej,'1'-Ja):"
CHANGE_ADD_YEAR = "Tilføj år til albumnavne('0'-Nej,'1'-Ja):"
CHANGE_USE_TRACK_NUM = "Tilføj titelnummer før filnavne('0'-Nej,'1'-Ja):"
CHANGE_CHECK_EXIST = "Kontrollér filens eksistens før download('0'-Nej,'1'-Ja):"
CHANGE_ARTIST_BEFORE_TITLE = "Tilføj kunsternavn før titlenummer('0'-Nej,'1'-Ja):"
CHANGE_INCLUDE_EP = "Inkluder singler og EP'er når der downloades en kunstners album('0'-Nej,'1'-Ja):"
CHANGE_ALBUMID_BEFORE_FOLDER = "Tilføj id før albummappe('0'-Nej,'1'-Ja):"
CHANGE_SAVE_COVERS = "Gem omslag('0'-Nej,'1'-Ja):"
CHANGE_LANGUAGE = "Vælg sprog"
CHANGE_ALBUM_FOLDER_FORMAT = "Albummappeformat('0' Ændrer ikke, 'default' for at indstille som standard):"
CHANGE_TRACK_FILE_FORMAT = "Musiknummerets filformat('0' Ændrer ikke, 'default' for at indstille som standard):"
CHANGE_SHOW_PROGRESS = "Vis fremskridt('0'-Nej,'1'-Ja):"
CHANGE_SHOW_TRACKINFO = "Show track info('0'-No,'1'-Yes):"
CHANGE_SAVE_ALBUM_INFO = "Save AlbumInfo.txt('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "Add lyrics('0'-No,'1'-Yes):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0' not modify):"
CHANGE_ADD_LRC_FILE = "Save timed lyrics .lrc file ('0'-No,'1'-Yes):"
# {} are required in these strings
AUTH_START_LOGIN = "Starter login-processen."
AUTH_LOGIN_CODE = "Din login kode er {}"
AUTH_NEXT_STEP = "Gå til {} inden for de næste {} for at afslutte opsætningen."
AUTH_WAITING = "Venter på godkendelse..."
AUTH_TIMEOUT = "Tiden løb ud."
MSG_VALID_ACCESSTOKEN = "AccessToken tilgængelig for {}."
MSG_INVAILD_ACCESSTOKEN = "AccessToken udløb. Forsøger at opdatere"
MSG_PATH_ERR = "Sti fejl!"
MSG_INPUT_ERR = "Indtastningsfejl!"
MODEL_ALBUM_PROPERTY = "ALBUM-PROPERTY"
MODEL_TRACK_PROPERTY = "TRACK-PROPERTY"
MODEL_VIDEO_PROPERTY = "VIDEO-PROPERTY"
MODEL_ARTIST_PROPERTY = "ARTIST-PROPERTY"
MODEL_PLAYLIST_PROPERTY = "PLAYLIST-PROPERTY"
MODEL_TITLE = 'Titel'
MODEL_TRACK_NUMBER = 'Titelnummer'
MODEL_VIDEO_NUMBER = 'Videonummer'
MODEL_RELEASE_DATE = 'Udgivelses dato'
MODEL_VERSION = 'Version'
MODEL_EXPLICIT = 'Eksplicit'
MODEL_ALBUM = 'Album'
MODEL_ID = 'ID'
MODEL_NAME = 'Navn'
MODEL_TYPE = 'Type'
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : danish.py
@Time : 2021/03/25
@Author : KB885
@Version : 1.0
@Contact :
@Desc :
'''
class LangDanish(object):
SETTING = "INDSTILLINGER"
VALUE = "Værdi"
SETTING_DOWNLOAD_PATH = "Download sti"
SETTING_ONLY_M4A = "Konverter mp4 til m4a"
SETTING_ADD_EXPLICIT_TAG = "Tilføj eksplicit tag"
SETTING_ADD_HYPHEN = "Tilføj bindestreg"
SETTING_ADD_YEAR = "Tilføj år før album mappe"
SETTING_USE_TRACK_NUM = "Tilføj titelnummer"
SETTING_AUDIO_QUALITY = "Lydkvalitet"
SETTING_VIDEO_QUALITY = "Videokvalitet"
SETTING_CHECK_EXIST = "Kontroller eksistens"
SETTING_ARTIST_BEFORE_TITLE = "Kunstnernavn før titelnummer"
SETTING_ALBUMID_BEFORE_FOLDER = "Id før album mappe"
SETTING_INCLUDE_EP = "Inkluder single&ep"
SETTING_SAVE_COVERS = "Gem omslag"
SETTING_LANGUAGE = "Sprog"
SETTING_USE_PLAYLIST_FOLDER = "Brug afspilningsmappen"
SETTING_MULITHREAD_DOWNLOAD = "Flertråede download"
SETTING_ALBUM_FOLDER_FORMAT = "Albummappens format"
SETTING_PLAYLIST_FOLDER_FORMAT = "Spillelistemappens format"
SETTING_TRACK_FILE_FORMAT = "Musiknummerets filformat"
SETTING_VIDEO_FILE_FORMAT = "Video file format"
SETTING_SHOW_PROGRESS = "Vis fremskridt"
SETTING_SHOW_TRACKINFO = "Show Track Info"
SETTING_SAVE_ALBUMINFO = "Save AlbumInfo.txt"
SETTING_DOWNLOAD_VIDEOS = "Download videos"
SETTING_ADD_LYRICS = "Add lyrics"
SETTING_LYRICS_SERVER_PROXY = "Lyrics server proxy"
SETTING_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_PATH = "Settings path"
SETTING_APIKEY = "APIKey support"
SETTING_ADD_TYPE_FOLDER = "Add Type-Folder"
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
CHOICE = "VALG"
FUNCTION = "FUNKTION"
CHOICE_ENTER = "Indtast"
CHOICE_ENTER_URLID = "Indtast 'Url/ID':"
CHOICE_EXIT = "Afslut"
CHOICE_LOGIN = "Kontroller AccessToken"
CHOICE_SETTINGS = "Indstillinger"
CHOICE_SET_ACCESS_TOKEN = "Sæt AccessToken"
CHOICE_DOWNLOAD_BY_URL = "Download via url eller id"
CHOICE_LOGOUT = "Log ud"
CHOICE_APIKEY = "Select APIKey"
PRINT_ERR = "[FEJL]"
PRINT_INFO = "[INFO]"
PRINT_SUCCESS = "[SUCCES]"
PRINT_ENTER_CHOICE = "Indtast Valg:"
PRINT_LATEST_VERSION = "Seneste version:"
# PRINT_USERNAME = "username:"
# PRINT_PASSWORD = "password:"
CHANGE_START_SETTINGS = "Start indstillinger('0'-Tilbage,'1'-Ja):"
CHANGE_DOWNLOAD_PATH = "Download stil('0' ændrer ikke):"
CHANGE_AUDIO_QUALITY = "Lydkvalitet('0'-Normal,'1'-Høj,'2'-HiFi,'3'-Master,'4'-Max):"
CHANGE_VIDEO_QUALITY = "Videokvalitet(1080, 720, 480, 360):"
CHANGE_ONLYM4A = "Konverter mp4 til m4a('0'-Nej,'1'-Ja):"
CHANGE_ADD_EXPLICIT_TAG = "Tilføj eksplicit tag til filnavne('0'-Nej,'1'-Ja):"
CHANGE_ADD_HYPHEN = "Brug bindestreger i stedet for mellemrum i filnavne('0'-Nej,'1'-Ja):"
CHANGE_ADD_YEAR = "Tilføj år til albumnavne('0'-Nej,'1'-Ja):"
CHANGE_USE_TRACK_NUM = "Tilføj titelnummer før filnavne('0'-Nej,'1'-Ja):"
CHANGE_CHECK_EXIST = "Kontrollér filens eksistens før download('0'-Nej,'1'-Ja):"
CHANGE_ARTIST_BEFORE_TITLE = "Tilføj kunsternavn før titlenummer('0'-Nej,'1'-Ja):"
CHANGE_INCLUDE_EP = "Inkluder singler og EP'er når der downloades en kunstners album('0'-Nej,'1'-Ja):"
CHANGE_ALBUMID_BEFORE_FOLDER = "Tilføj id før albummappe('0'-Nej,'1'-Ja):"
CHANGE_SAVE_COVERS = "Gem omslag('0'-Nej,'1'-Ja):"
CHANGE_LANGUAGE = "Vælg sprog"
CHANGE_ALBUM_FOLDER_FORMAT = "Albummappeformat('0' Ændrer ikke, 'default' for at indstille som standard):"
CHANGE_PLAYLIST_FOLDER_FORMAT = "Spillelistemappeformat('0' Ændrer ikke, 'default' for at indstille som standard):"
CHANGE_TRACK_FILE_FORMAT = "Musiknummerets filformat('0' Ændrer ikke, 'default' for at indstille som standard):"
CHANGE_VIDEO_FILE_FORMAT = "Video file format('0'-not modify,'default'-to set default):"
CHANGE_SHOW_PROGRESS = "Vis fremskridt('0'-Nej,'1'-Ja):"
CHANGE_SHOW_TRACKINFO = "Show track info('0'-No,'1'-Yes):"
CHANGE_SAVE_ALBUM_INFO = "Save AlbumInfo.txt('0'-No,'1'-Yes):"
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "Add lyrics('0'-No,'1'-Yes):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0'-not modify):"
CHANGE_ADD_LRC_FILE = "Save timed lyrics .lrc file ('0'-No,'1'-Yes):"
CHANGE_ADD_TYPE_FOLDER = "Add Type-Folder,eg Album/Video/Playlist('0'-No,'1'-Yes):"
CHANGE_MULITHREAD_DOWNLOAD = "Multi thread download('0'-No,'1'-Yes):"
CHANGE_USE_DOWNLOAD_DELAY = "Use Download Delay('0'-No,'1'-Yes):"
# {} are required in these strings
AUTH_START_LOGIN = "Starter login-processen."
AUTH_LOGIN_CODE = "Din login kode er {}"
AUTH_NEXT_STEP = "Gå til {} inden for de næste {} for at afslutte opsætningen."
AUTH_WAITING = "Venter på godkendelse..."
AUTH_TIMEOUT = "Tiden løb ud."
MSG_VALID_ACCESSTOKEN = "AccessToken tilgængelig for {}."
MSG_INVALID_ACCESSTOKEN = "AccessToken udløb. Forsøger at opdatere"
MSG_PATH_ERR = "Sti fejl!"
MSG_INPUT_ERR = "Indtastningsfejl!"
MODEL_ALBUM_PROPERTY = "ALBUM-PROPERTY"
MODEL_TRACK_PROPERTY = "TRACK-PROPERTY"
MODEL_VIDEO_PROPERTY = "VIDEO-PROPERTY"
MODEL_ARTIST_PROPERTY = "ARTIST-PROPERTY"
MODEL_PLAYLIST_PROPERTY = "PLAYLIST-PROPERTY"
MODEL_TITLE = 'Titel'
MODEL_TRACK_NUMBER = 'Titelnummer'
MODEL_VIDEO_NUMBER = 'Videonummer'
MODEL_RELEASE_DATE = 'Udgivelses dato'
MODEL_VERSION = 'Version'
MODEL_EXPLICIT = 'Eksplicit'
MODEL_ALBUM = 'Album'
MODEL_ID = 'ID'
MODEL_NAME = 'Navn'
MODEL_TYPE = 'Type'
+126
View File
@@ -0,0 +1,126 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : dutch.py
@Time : 2022/03/01
@Author : bladeoner
@Version : 1.0
@Contact :
@Desc :
'''
class LangDutch(object):
SETTING = "INSTELLINGEN"
VALUE = "WAARDE"
SETTING_DOWNLOAD_PATH = "Download pad"
SETTING_ONLY_M4A = "mp4 naar m4a converteren"
SETTING_ADD_EXPLICIT_TAG = "Expliciete tag toevoegen"
SETTING_ADD_HYPHEN = "Koppelteken toevoegen"
SETTING_ADD_YEAR = "Jaar voor albummap toevoegen"
SETTING_USE_TRACK_NUM = "Tracknummer gebruiker toevoegen"
SETTING_AUDIO_QUALITY = "Audiokwaliteit"
SETTING_VIDEO_QUALITY = "Videokwaliteit"
SETTING_CHECK_EXIST = "Controleer of al bestaat"
SETTING_ARTIST_BEFORE_TITLE = "Artiestnaam voor tracktitel"
SETTING_ALBUMID_BEFORE_FOLDER = "ID voor albummap"
SETTING_INCLUDE_EP = "Inclusief singles en EP's"
SETTING_SAVE_COVERS = "Bewaar covers"
SETTING_LANGUAGE = "Taal"
SETTING_USE_PLAYLIST_FOLDER = "Afspeellijst gebruiken"
SETTING_MULITHREAD_DOWNLOAD = "Downloaden met meerdere threads"
SETTING_ALBUM_FOLDER_FORMAT = "Indeling albummap"
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
SETTING_TRACK_FILE_FORMAT = "Bestandsindeling bijhouden"
SETTING_VIDEO_FILE_FORMAT = "Videobestandsindeling"
SETTING_SHOW_PROGRESS = "Toon voortgang"
SETTING_SHOW_TRACKINFO = "Toon trackinfo"
SETTING_SAVE_ALBUMINFO = "AlbumInfo.txt opslaan"
SETTING_DOWNLOAD_VIDEOS = "Download videos"
SETTING_ADD_LYRICS = "Songtekst toevoegen"
SETTING_LYRICS_SERVER_PROXY = "Tekst server proxy"
SETTING_ADD_LRC_FILE = "Getimede songteksten opslaan (.lrc-bestand)"
SETTING_PATH = "Instellingen pad"
SETTING_APIKEY = "APIKey-ondersteuning"
SETTING_ADD_TYPE_FOLDER = "Typemap toevoegen"
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
CHOICE = "KEUZE"
FUNCTION = "FUNCTIE"
CHOICE_ENTER = "Voer in"
CHOICE_ENTER_URLID = "Vul 'Url/ID' in:"
CHOICE_EXIT = "Verlaten"
CHOICE_LOGIN = "Toegangstoken controleren"
CHOICE_SETTINGS = "Instellingen"
CHOICE_SET_ACCESS_TOKEN = "Toegangstoken instellen"
CHOICE_DOWNLOAD_BY_URL = "Downloaden via url of ID"
CHOICE_LOGOUT = "Uitloggen"
CHOICE_APIKEY = "Selecteer APIKey"
PRINT_ERR = "[FOUT]"
PRINT_INFO = "[INFO]"
PRINT_SUCCESS = "[SUCCESS]"
PRINT_ENTER_CHOICE = "Voer keuze in:"
PRINT_LATEST_VERSION = "Laatste versie:"
# PRINT_USERNAME = "gebruikersnaam:"
# PRINT_PASSWORD = "wachtwoord:"
CHANGE_START_SETTINGS = "Start instellingen('0'-Terugkeren,'1'-Ja):"
CHANGE_DOWNLOAD_PATH = "Downloadpad('0'-niet wijzigen):"
CHANGE_AUDIO_QUALITY = "Audiokwaliteit('0'-Normaal,'1'-Hoog,'2'-HiFi,'3'-Master,'4'-Max):"
CHANGE_VIDEO_QUALITY = "Videokwaliteit (1080, 720, 480, 360):"
CHANGE_ONLYM4A = "Converteer mp4 naar m4a('0'-Nee,'1'-Ja):"
CHANGE_ADD_EXPLICIT_TAG = "Expliciete tag toevoegen aan bestandsnamen('0'-Nee,'1'-Ja):"
CHANGE_ADD_HYPHEN = "Gebruik koppeltekens in plaats van spaties in bestandsnamen ('0'-Nee,'1'-Ja):"
CHANGE_ADD_YEAR = "Jaar toevoegen aan albummapnamen ('0'-Nee,'1'-Ja):"
CHANGE_USE_TRACK_NUM = "Voeg tracknummer toe voor bestandsnamen ('0'-Nee,'1'-Ja):"
CHANGE_CHECK_EXIST = "Controleer het bestaande bestand voordat u de track downloadt('0'-Nee,'1'-Ja):"
CHANGE_ARTIST_BEFORE_TITLE = "Voeg artiestnaam toe voor de tracktitel ('0'-Nee,'1'-Ja):"
CHANGE_INCLUDE_EP = "Voeg singles en EP's toe bij het downloaden van de albums van een artiest('0'-Nee,'1'-Ja):"
CHANGE_ALBUMID_BEFORE_FOLDER = "ID toevoegen voor albummap ('0'-Nee,'1'-Ja):"
CHANGE_SAVE_COVERS = "Covers opslaan('0'-Nee,'1'-Ja):"
CHANGE_LANGUAGE = "Selecteer taal"
CHANGE_ALBUM_FOLDER_FORMAT = "Albummapindeling ('0'-niet wijzigen,'default'-om standaard in te stellen):"
CHANGE_PLAYLIST_FOLDER_FORMAT = "Afspeellijstmapindeling format('0'-niet wijzigen,'default'-om standaard in te stellen):"
CHANGE_TRACK_FILE_FORMAT = "Bestandsformaat bijhouden ('0'-niet wijzigen,'default'-om standaard in te stellen):"
CHANGE_VIDEO_FILE_FORMAT = "Videobestandsindeling('0'-niet wijzigen,'default'-om standaard in te stellen):"
CHANGE_SHOW_PROGRESS = "Voortgang weergeven('0'-Nee,'1'-Ja):"
CHANGE_SHOW_TRACKINFO = "Toon trackinfo('0'-Nee,'1'-Ja):"
CHANGE_SAVE_ALBUM_INFO = "Bewaar AlbumInfo.txt('0'-Nee,'1'-Ja):"
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "Songtekst toevoegen('0'-Nee,'1'-Ja):"
CHANGE_LYRICS_SERVER_PROXY = "Songtekst proxyserver('0'-niet wijzigen):"
CHANGE_ADD_LRC_FILE = "Sla getimede songtekst .lrc-bestand op ('0'-Nee,'1'-Ja):"
CHANGE_ADD_TYPE_FOLDER = "Type-map toevoegen, bijv. Album/Video/Playlist('0'-Nee,'1'-Ja):"
CHANGE_MULITHREAD_DOWNLOAD = "Multi thread download('0'-No,'1'-Yes):"
CHANGE_USE_DOWNLOAD_DELAY = "Use Download Delay('0'-No,'1'-Yes):"
# {} are required in these strings
AUTH_START_LOGIN = "Inlogproces starten..."
AUTH_LOGIN_CODE = "Uw inlogcode is {}"
AUTH_NEXT_STEP = "Ga naar {} in de volgende {} om de installatie te voltooien."
AUTH_WAITING = "Wachten op toestemming..."
AUTH_TIMEOUT = "Operatie time-out."
MSG_VALID_ACCESSTOKEN = "Toegangstoken goed voor {}."
MSG_INVALID_ACCESSTOKEN = "Verlopen AccessToken. Poging om het te vernieuwen."
MSG_PATH_ERR = "Pad is incorrect!"
MSG_INPUT_ERR = "Invoerfout!"
MODEL_ALBUM_PROPERTY = "ALBUM-EIGENSCHAP"
MODEL_TRACK_PROPERTY = "TRACK-EIGENSCHAP"
MODEL_VIDEO_PROPERTY = "VIDEO-EIGENSCHAP"
MODEL_ARTIST_PROPERTY = "ARTIEST-EIGENSCHAP"
MODEL_PLAYLIST_PROPERTY = "AFSPEELLIJST-EIGENSCHAP"
MODEL_TITLE = 'Titel'
MODEL_TRACK_NUMBER = 'Tracknummer'
MODEL_VIDEO_NUMBER = 'Videonummer'
MODEL_RELEASE_DATE = 'Publicatiedatum'
MODEL_VERSION = 'Versie'
MODEL_EXPLICIT = 'Expliciet'
MODEL_ALBUM = 'Album'
MODEL_ID = 'ID'
MODEL_NAME = 'Naam'
MODEL_TYPE = 'Type'
+25 -12
View File
@@ -2,9 +2,9 @@
# -*- encoding: utf-8 -*-
'''
@File : english.py
@Time : 2021/11/11
@Time : 2021/11/24
@Author : Yaronzz & jee019
@Version : 1.1
@Version : 1.2
@Contact : yaronhuang@foxmail.com
@Desc :
'''
@@ -30,14 +30,20 @@ class LangEnglish(object):
SETTING_USE_PLAYLIST_FOLDER = "Use playlist folder"
SETTING_MULITHREAD_DOWNLOAD = "Multi thread download"
SETTING_ALBUM_FOLDER_FORMAT = "Album folder format"
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
SETTING_TRACK_FILE_FORMAT = "Track file format"
SETTING_VIDEO_FILE_FORMAT = "Video file format"
SETTING_SHOW_PROGRESS = "Show progress"
SETTING_SHOW_TRACKIFNO = "Show Track Info"
SETTING_SHOW_TRACKINFO = "Show Track Info"
SETTING_SAVE_ALBUMINFO = "Save AlbumInfo.txt"
SETTING_DOWNLOAD_VIDEOS = "Download videos"
SETTING_ADD_LYRICS = "Add lyrics"
SETTING_LYRICS_SERVER_PROXY = "Lyrics server proxy"
SETTINGS_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_PATH = "Settings path"
SETTING_APIKEY = "APIKey support"
SETTING_ADD_TYPE_FOLDER = "Add Type-Folder"
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
CHOICE = "CHOICE"
FUNCTION = "FUNCTION"
@@ -47,8 +53,9 @@ class LangEnglish(object):
CHOICE_LOGIN = "Check AccessToken"
CHOICE_SETTINGS = "Settings"
CHOICE_SET_ACCESS_TOKEN = "Set AccessToken"
CHOICE_DOWNLOAD_BY_URL = "Download by url or id"
CHOICE_DOWNLOAD_BY_URL = "Download by url or ID"
CHOICE_LOGOUT = "Logout"
CHOICE_APIKEY = "Select APIKey"
PRINT_ERR = "[ERR]"
PRINT_INFO = "[INFO]"
@@ -60,8 +67,8 @@ class LangEnglish(object):
# PRINT_PASSWORD = "password:"
CHANGE_START_SETTINGS = "Start settings('0'-Return,'1'-Yes):"
CHANGE_DOWNLOAD_PATH = "Download path('0' not modify):"
CHANGE_AUDIO_QUALITY = "Audio quality('0'-Normal,'1'-High,'2'-HiFi,'3'-Master):"
CHANGE_DOWNLOAD_PATH = "Download path('0'-not modify):"
CHANGE_AUDIO_QUALITY = "Audio quality('0'-Normal,'1'-High,'2'-HiFi,'3'-Master,'4'-Max):"
CHANGE_VIDEO_QUALITY = "Video quality(1080, 720, 480, 360):"
CHANGE_ONLYM4A = "Convert mp4 to m4a('0'-No,'1'-Yes):"
CHANGE_ADD_EXPLICIT_TAG = "Add explicit tag to file names('0'-No,'1'-Yes):"
@@ -74,14 +81,20 @@ class LangEnglish(object):
CHANGE_ALBUMID_BEFORE_FOLDER = "Add id before album folder('0'-No,'1'-Yes):"
CHANGE_SAVE_COVERS = "Save covers('0'-No,'1'-Yes):"
CHANGE_LANGUAGE = "Select language"
CHANGE_ALBUM_FOLDER_FORMAT = "Album folder format('0' not modify,'default' to set default):"
CHANGE_TRACK_FILE_FORMAT = "Track file format('0' not modify,'default' to set default):"
CHANGE_ALBUM_FOLDER_FORMAT = "Album folder format('0'-not modify,'default'-to set default):"
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
CHANGE_TRACK_FILE_FORMAT = "Track file format('0'-not modify,'default'-to set default):"
CHANGE_VIDEO_FILE_FORMAT = "Video file format('0'-not modify,'default'-to set default):"
CHANGE_SHOW_PROGRESS = "Show progress('0'-No,'1'-Yes):"
CHANGE_SHOW_TRACKINFO = "Show track info('0'-No,'1'-Yes):"
CHANGE_SAVE_ALBUM_INFO = "Save AlbumInfo.txt('0'-No,'1'-Yes):"
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "Add lyrics('0'-No,'1'-Yes):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0' not modify):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0'-not modify):"
CHANGE_ADD_LRC_FILE = "Save timed lyrics .lrc file ('0'-No,'1'-Yes):"
CHANGE_ADD_TYPE_FOLDER = "Add Type-Folder,eg Album/Video/Playlist('0'-No,'1'-Yes):"
CHANGE_MULITHREAD_DOWNLOAD = "Multi thread download('0'-No,'1'-Yes):"
CHANGE_USE_DOWNLOAD_DELAY = "Use Download Delay('0'-No,'1'-Yes):"
# {} are required in these strings
AUTH_START_LOGIN = "Starting login process..."
@@ -91,7 +104,7 @@ class LangEnglish(object):
AUTH_TIMEOUT = "Operation timed out."
MSG_VALID_ACCESSTOKEN = "AccessToken good for {}."
MSG_INVAILD_ACCESSTOKEN = "Expired AccessToken. Attempting to refresh it."
MSG_INVALID_ACCESSTOKEN = "Expired AccessToken. Attempting to refresh it."
MSG_PATH_ERR = "Path is error!"
MSG_INPUT_ERR = "Input error!"
@@ -110,4 +123,4 @@ class LangEnglish(object):
MODEL_ALBUM = 'Album'
MODEL_ID = 'ID'
MODEL_NAME = 'Name'
MODEL_TYPE = 'Type'
MODEL_TYPE = 'Type'
+20 -7
View File
@@ -30,14 +30,20 @@ class LangFilipino(object):
SETTING_USE_PLAYLIST_FOLDER = "Use playlist folder"
SETTING_MULITHREAD_DOWNLOAD = "Multi thread download"
SETTING_ALBUM_FOLDER_FORMAT = "Album folder format"
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
SETTING_TRACK_FILE_FORMAT = "Track file format"
SETTING_VIDEO_FILE_FORMAT = "Video file format"
SETTING_SHOW_PROGRESS = "Show progress"
SETTING_SHOW_TRACKIFNO = "Show Track Info"
SETTING_SHOW_TRACKINFO = "Show Track Info"
SETTING_SAVE_ALBUMINFO = "Save AlbumInfo.txt"
SETTING_DOWNLOAD_VIDEOS = "Download videos"
SETTING_ADD_LYRICS = "Add lyrics"
SETTING_LYRICS_SERVER_PROXY = "Lyrics server proxy"
SETTING_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_PATH = "Settings path"
SETTINGS_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_APIKEY = "APIKey support"
SETTING_ADD_TYPE_FOLDER = "Add Type-Folder"
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
CHOICE = "PAGPIPILIAN"
FUNCTION = "SILBI"
@@ -49,6 +55,7 @@ class LangFilipino(object):
CHOICE_SET_ACCESS_TOKEN = "I-set ang AccessToken"
CHOICE_DOWNLOAD_BY_URL = "Mag download gamit ang url o id"
CHOICE_LOGOUT = "Logout"
CHOICE_APIKEY = "Select APIKey"
PRINT_ERR = "[ERR]"
PRINT_INFO = "[INFO]"
@@ -61,7 +68,7 @@ class LangFilipino(object):
CHANGE_START_SETTINGS = "Simulan ang settings('0'-Bumalik,'1'-Oo):"
CHANGE_DOWNLOAD_PATH = "Paroroonan ng Download('0' walang babaguhin):"
CHANGE_AUDIO_QUALITY = "Kalidad ng Audio('0'-Normal,'1'-High,'2'-HiFi,'3'-Master):"
CHANGE_AUDIO_QUALITY = "Kalidad ng Audio('0'-Normal,'1'-High,'2'-HiFi,'3'-Master,'4'-Max):"
CHANGE_VIDEO_QUALITY = "Kalidad ng Audio Video(1080, 720, 480, 360):"
CHANGE_ONLYM4A = "I-convert ang mp4 bilang m4a('0'-Hindi,'1'-Oo):"
CHANGE_ADD_EXPLICIT_TAG = "Lagyan ng explicit tag sa pangalan ng files('0'-Hindi,'1'-Oo):"
@@ -74,14 +81,20 @@ class LangFilipino(object):
CHANGE_ALBUMID_BEFORE_FOLDER = "Lagyan ng id bago ang album folder('0'-Hindi,'1'-Oo):"
CHANGE_SAVE_COVERS = "I-save ang mga covers('0'-Hindi,'1'-Oo):"
CHANGE_LANGUAGE = "Pumili ng lenggwahe"
CHANGE_ALBUM_FOLDER_FORMAT = "Album folder format('0' not modify):"
CHANGE_TRACK_FILE_FORMAT = "Track file format('0' not modify):"
CHANGE_ALBUM_FOLDER_FORMAT = "Album folder format('0' not modify,'default'-to set default):"
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
CHANGE_TRACK_FILE_FORMAT = "Track file format('0' not modify,'default'-to set default):"
CHANGE_VIDEO_FILE_FORMAT = "Video file format('0'-not modify,'default'-to set default):"
CHANGE_SHOW_PROGRESS = "Show progress('0'-No,'1'-Yes):"
CHANGE_SHOW_TRACKINFO = "Show track info('0'-No,'1'-Yes):"
CHANGE_SAVE_ALBUM_INFO = "Save AlbumInfo.txt('0'-No,'1'-Yes):"
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "Add lyrics('0'-No,'1'-Yes):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0' not modify):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0'-not modify):"
CHANGE_ADD_LRC_FILE = "Save timed lyrics .lrc file ('0'-No,'1'-Yes):"
CHANGE_ADD_TYPE_FOLDER = "Add Type-Folder,eg Album/Video/Playlist('0'-No,'1'-Yes):"
CHANGE_MULITHREAD_DOWNLOAD = "Multi thread download('0'-No,'1'-Yes):"
CHANGE_USE_DOWNLOAD_DELAY = "Use Download Delay('0'-No,'1'-Yes):"
# {} are required in these strings
AUTH_START_LOGIN = "Starting login process..."
@@ -91,7 +104,7 @@ class LangFilipino(object):
AUTH_TIMEOUT = "Operation timed out."
MSG_VALID_ACCESSTOKEN = "AccessToken good for {}."
MSG_INVAILD_ACCESSTOKEN = "Expired AccessToken. Attempting to refresh it."
MSG_INVALID_ACCESSTOKEN = "Expired AccessToken. Attempting to refresh it."
MSG_PATH_ERR = "May error sa paroroonan ng download!"
MSG_INPUT_ERR = "May error sa pag-input!"
+126 -113
View File
@@ -1,113 +1,126 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : french.py
@Time : 2020/10/25
@Authors : flamme-demon & joyel24
@Version : 0.3
@Contact :
@Desc :
'''
class LangFrench(object):
SETTING = "RÉGLAGES"
VALUE = "VALEUR"
SETTING_DOWNLOAD_PATH = "Emplacement des téléchargements"
SETTING_ONLY_M4A = "Convertir mp4 en m4a"
SETTING_ADD_EXPLICIT_TAG = "Ajout du tag Explicit - Dossier"
SETTING_ADD_HYPHEN = "Ajouter un trait d'union"
SETTING_ADD_YEAR = "Ajouter l'année avant le nom de l'album - Dossier"
SETTING_USE_TRACK_NUM = "Ajouter le numéro de piste de l'album"
SETTING_AUDIO_QUALITY = "Qualité Audio"
SETTING_VIDEO_QUALITY = "Qualité Video"
SETTING_CHECK_EXIST = "Vérifier l'existence"
SETTING_ARTIST_BEFORE_TITLE = "Nom de l'artiste avant le titre du morceau - Fichier"
SETTING_ALBUMID_BEFORE_FOLDER = "Id avant le nom d'album - Dossier"
SETTING_INCLUDE_EP = "Inclure les singles & EPs"
SETTING_SAVE_COVERS = "Sauvegarder les couvertures"
SETTING_LANGUAGE = "Langue"
SETTING_USE_PLAYLIST_FOLDER = "Utiliser dossier de playlist"
SETTING_MULITHREAD_DOWNLOAD = "Téléchargement multithread"
SETTING_ALBUM_FOLDER_FORMAT = "Format du dossier d'album"
SETTING_TRACK_FILE_FORMAT = "Format du fichier de tracklist"
SETTING_SHOW_PROGRESS = "Afficher la Progression"
SETTING_SHOW_TRACKIFNO = "Show Track Info"
SETTING_SAVE_ALBUMINFO = "Save AlbumInfo.txt"
SETTING_ADD_LYRICS = "Add lyrics"
SETTING_LYRICS_SERVER_PROXY = "Lyrics server proxy"
SETTING_PATH = "Settings path"
SETTINGS_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
CHOICE = "CHOIX"
FUNCTION = "FONCTION"
CHOICE_ENTER = "Saisir"
CHOICE_ENTER_URLID = "Saisir 'Url/ID':"
CHOICE_EXIT = "Quitter"
CHOICE_LOGIN = "Check AccessToken"
CHOICE_SETTINGS = "Réglages"
CHOICE_SET_ACCESS_TOKEN = "Définir le jeton d'accès"
CHOICE_DOWNLOAD_BY_URL = "Téléchargement par url ou id"
CHOICE_LOGOUT = "Logout"
PRINT_ERR = "[ERR]"
PRINT_INFO = "[INFO]"
PRINT_SUCCESS = "[SUCCES]"
PRINT_ENTER_CHOICE = "Saisir le choix:"
PRINT_LATEST_VERSION = "Dernière version:"
# PRINT_USERNAME = "Utilisateur:"
# PRINT_PASSWORD = "Mot de passe:"
CHANGE_START_SETTINGS = "Commencer les réglages ('0'-Retour,'1'-Oui):"
CHANGE_DOWNLOAD_PATH = "Emplacement des téléchargements('0' ne pas modifier):"
CHANGE_AUDIO_QUALITY = "Qualité audio('0'-Normal,'1'-High,'2'-HiFi,'3'-Master):"
CHANGE_VIDEO_QUALITY = "Qualité Video(1080, 720, 480, 360):"
CHANGE_ONLYM4A = "Convertir mp4 en m4a('0'-Non,'1'-Oui):"
CHANGE_ADD_EXPLICIT_TAG = "Ajout du tag Explicit - Fichier('0'-Non,'1'-Oui):"
CHANGE_ADD_HYPHEN = "Utilisez des traits d'union au lieu d'espaces dans les noms de fichiers('0'-Non,'1'-Oui):"
CHANGE_ADD_YEAR = "Ajouter l'année aux noms des dossiers des albums('0'-Non,'1'-Oui):"
CHANGE_USE_TRACK_NUM = "Ajouter le numéro de piste avant le nom des fichiers('0'-Non,'1'-Oui):"
CHANGE_CHECK_EXIST = "Vérifier l'existence du fichier avant le téléchargement('0'-Non,'1'-Oui):"
CHANGE_ARTIST_BEFORE_TITLE = "Ajouter le nom de l'artiste avant le titre de la piste('0'-Non,'1'-Oui):"
CHANGE_INCLUDE_EP = "Inclure les singles et les EPs lors du téléchargement des albums d'un artiste('0'-Non,'1'-Oui):"
CHANGE_ALBUMID_BEFORE_FOLDER = "Ajouter un identifiant avant le dossier album('0'-Non,'1'-Oui):"
CHANGE_SAVE_COVERS = "Sauvegarder les couvertures('0'-Non,'1'-Oui):"
CHANGE_LANGUAGE = "Sélectionnez une langue"
CHANGE_ALBUM_FOLDER_FORMAT = "Format du dossier d'album('0' ne pas modifier):"
CHANGE_TRACK_FILE_FORMAT = "Format du fichier de tracklist('0' ne pas modifier):"
CHANGE_SHOW_PROGRESS = "Afficher la progression('0'-Non,'1'-Oui):"
CHANGE_SHOW_TRACKINFO = "Show track info('0'-No,'1'-Yes):"
CHANGE_SAVE_ALBUM_INFO = "Save AlbumInfo.txt('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "Add lyrics('0'-No,'1'-Yes):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0' not modify):"
CHANGE_ADD_LRC_FILE = "Save timed lyrics .lrc file ('0'-No,'1'-Yes):"
# {} are required in these strings
AUTH_START_LOGIN = "Starting login process..."
AUTH_LOGIN_CODE = "Your login code is {}"
AUTH_NEXT_STEP = "Go to {} within the next {} to complete setup."
AUTH_WAITING = "Waiting for authorization..."
AUTH_TIMEOUT = "Operation timed out."
MSG_VALID_ACCESSTOKEN = "AccessToken good for {}."
MSG_INVAILD_ACCESSTOKEN = "Expired AccessToken. Attempting to refresh it."
MSG_PATH_ERR = "Erreur du chemin d'accès"
MSG_INPUT_ERR = "Erreur de saisie !"
MODEL_ALBUM_PROPERTY = "PROPRIETES-ALBUM"
MODEL_TRACK_PROPERTY = "PROPRIETES-PISTES-AUDIO"
MODEL_VIDEO_PROPERTY = "PROPRIETES-VIDEO"
MODEL_ARTIST_PROPERTY = "PROPRIETES-ARTISTE"
MODEL_PLAYLIST_PROPERTY = "PROPERTES-PLAYLIST"
MODEL_TITLE = 'Titre'
MODEL_TRACK_NUMBER = 'Numéro de piste'
MODEL_VIDEO_NUMBER = 'Numéro de la vidéo'
MODEL_RELEASE_DATE = 'Date de publication'
MODEL_VERSION = 'Version'
MODEL_EXPLICIT = 'Explicit'
MODEL_ALBUM = 'Album'
MODEL_ID = 'ID'
MODEL_NAME = 'Nom'
MODEL_TYPE = 'Type'
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : french.py
@Time : 2020/10/25
@Authors : flamme-demon & joyel24
@Version : 0.3
@Contact :
@Desc :
'''
class LangFrench(object):
SETTING = "RÉGLAGES"
VALUE = "VALEUR"
SETTING_DOWNLOAD_PATH = "Emplacement des téléchargements"
SETTING_ONLY_M4A = "Convertir mp4 en m4a"
SETTING_ADD_EXPLICIT_TAG = "Ajout du tag Explicit - Dossier"
SETTING_ADD_HYPHEN = "Ajouter un trait d'union"
SETTING_ADD_YEAR = "Ajouter l'année avant le nom de l'album - Dossier"
SETTING_USE_TRACK_NUM = "Ajouter le numéro de piste de l'album"
SETTING_AUDIO_QUALITY = "Qualité Audio"
SETTING_VIDEO_QUALITY = "Qualité Video"
SETTING_CHECK_EXIST = "Vérifier l'existence"
SETTING_ARTIST_BEFORE_TITLE = "Nom de l'artiste avant le titre du morceau - Fichier"
SETTING_ALBUMID_BEFORE_FOLDER = "Id avant le nom d'album - Dossier"
SETTING_INCLUDE_EP = "Inclure les singles & EPs"
SETTING_SAVE_COVERS = "Sauvegarder les couvertures"
SETTING_LANGUAGE = "Langue"
SETTING_USE_PLAYLIST_FOLDER = "Utiliser dossier de playlist"
SETTING_MULITHREAD_DOWNLOAD = "Téléchargement multithread"
SETTING_ALBUM_FOLDER_FORMAT = "Format du dossier d'album"
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
SETTING_TRACK_FILE_FORMAT = "Format du fichier de tracklist"
SETTING_VIDEO_FILE_FORMAT = "Video file format"
SETTING_SHOW_PROGRESS = "Afficher la Progression"
SETTING_SHOW_TRACKINFO = "Afficher les information de la musique"
SETTING_SAVE_ALBUMINFO = "Enregistrer AlbumInfo.txt"
SETTING_DOWNLOAD_VIDEOS = "Download videos"
SETTING_ADD_LYRICS = "Inclure les paroles"
SETTING_LYRICS_SERVER_PROXY = "Proxy du serveur de paroles"
SETTING_ADD_LRC_FILE = "Enregistrer les paroles synchronisées (fichier .lrc)"
SETTING_PATH = "Emplacement des paramètres"
SETTING_APIKEY = "Prise en charge de la clé API"
SETTING_ADD_TYPE_FOLDER = "Ajouter un dossier de type"
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
CHOICE = "CHOIX"
FUNCTION = "FONCTION"
CHOICE_ENTER = "Saisir"
CHOICE_ENTER_URLID = "Saisir 'Url/ID':"
CHOICE_EXIT = "Quitter"
CHOICE_LOGIN = "Vérifier le token d'accès"
CHOICE_SETTINGS = "Réglages"
CHOICE_SET_ACCESS_TOKEN = "Définir le jeton d'accès"
CHOICE_DOWNLOAD_BY_URL = "Téléchargement par url ou id"
CHOICE_LOGOUT = "Déconnexion"
CHOICE_APIKEY = "Choisir la clé d'API"
PRINT_ERR = "[ERR]"
PRINT_INFO = "[INFO]"
PRINT_SUCCESS = "[SUCCES]"
PRINT_ENTER_CHOICE = "Saisir le choix:"
PRINT_LATEST_VERSION = "Dernière version:"
# PRINT_USERNAME = "Utilisateur:"
# PRINT_PASSWORD = "Mot de passe:"
CHANGE_START_SETTINGS = "Commencer les réglages ('0'-Retour,'1'-Oui):"
CHANGE_DOWNLOAD_PATH = "Emplacement des téléchargements('0' ne pas modifier):"
CHANGE_AUDIO_QUALITY = "Qualité audio('0'-Normal,'1'-High,'2'-HiFi,'3'-Master,'4'-Max):"
CHANGE_VIDEO_QUALITY = "Qualité Video(1080, 720, 480, 360):"
CHANGE_ONLYM4A = "Convertir mp4 en m4a('0'-Non,'1'-Oui):"
CHANGE_ADD_EXPLICIT_TAG = "Ajout du tag Explicit - Fichier('0'-Non,'1'-Oui):"
CHANGE_ADD_HYPHEN = "Utilisez des traits d'union au lieu d'espaces dans les noms de fichiers('0'-Non,'1'-Oui):"
CHANGE_ADD_YEAR = "Ajouter l'année aux noms des dossiers des albums('0'-Non,'1'-Oui):"
CHANGE_USE_TRACK_NUM = "Ajouter le numéro de piste avant le nom des fichiers('0'-Non,'1'-Oui):"
CHANGE_CHECK_EXIST = "Vérifier l'existence du fichier avant le téléchargement('0'-Non,'1'-Oui):"
CHANGE_ARTIST_BEFORE_TITLE = "Ajouter le nom de l'artiste avant le titre de la piste('0'-Non,'1'-Oui):"
CHANGE_INCLUDE_EP = "Inclure les singles et les EPs lors du téléchargement des albums d'un artiste('0'-Non,'1'-Oui):"
CHANGE_ALBUMID_BEFORE_FOLDER = "Ajouter un identifiant avant le dossier album('0'-Non,'1'-Oui):"
CHANGE_SAVE_COVERS = "Sauvegarder les couvertures('0'-Non,'1'-Oui):"
CHANGE_LANGUAGE = "Sélectionnez une langue"
CHANGE_ALBUM_FOLDER_FORMAT = "Format du dossier d'album('0' ne pas modifier):"
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
CHANGE_TRACK_FILE_FORMAT = "Format du fichier de tracklist('0' ne pas modifier):"
CHANGE_VIDEO_FILE_FORMAT = "Video file format('0'-not modify,'default'-to set default):"
CHANGE_SHOW_PROGRESS = "Afficher la progression('0'-Non,'1'-Oui):"
CHANGE_SHOW_TRACKINFO = "Afficher les information de la piste ('0'-Non,'1'-Oui):"
CHANGE_SAVE_ALBUM_INFO = "Enregistrer AlbumInfo.txt('0'-Non,'1'-Oui):"
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "Ajouter les paroles ('0'-Non,'1'-Oui):"
CHANGE_LYRICS_SERVER_PROXY = "Proxy du serveur de paroles('0'-not modify):"
CHANGE_ADD_LRC_FILE = "Enregistrer les paroles synchronisées (fichier.lrc) ('0'-Non,'1'-Oui):"
CHANGE_ADD_TYPE_FOLDER = "Ajouter un dossier de type,Ex: Album/Video/Playlist('0'-Non,'1'-Oui):"
CHANGE_MULITHREAD_DOWNLOAD = "Multi thread download('0'-Non,'1'-Oui):"
CHANGE_USE_DOWNLOAD_DELAY = "Use Download Delay('0'-No,'1'-Yes):"
# {} are required in these strings
AUTH_START_LOGIN = "Démarrage du processus de connexion..."
AUTH_LOGIN_CODE = "Votre code de connection est le suivant: {}"
AUTH_NEXT_STEP = "Allez à {} avant {} pour finir la configuration."
AUTH_WAITING = "En attente d'autorisation..."
AUTH_TIMEOUT = "Temps écoulé."
MSG_VALID_ACCESSTOKEN = "Token d'accès valable {}."
MSG_INVALID_ACCESSTOKEN = "Token d'accès expiré. Tentative de renouvellement automatique."
MSG_PATH_ERR = "Erreur du chemin d'accès"
MSG_INPUT_ERR = "Erreur de saisie !"
MODEL_ALBUM_PROPERTY = "PROPRIETES-ALBUM"
MODEL_TRACK_PROPERTY = "PROPRIETES-PISTES-AUDIO"
MODEL_VIDEO_PROPERTY = "PROPRIETES-VIDEO"
MODEL_ARTIST_PROPERTY = "PROPRIETES-ARTISTE"
MODEL_PLAYLIST_PROPERTY = "PROPERTES-PLAYLIST"
MODEL_TITLE = 'Titre'
MODEL_TRACK_NUMBER = 'Numéro de piste'
MODEL_VIDEO_NUMBER = 'Numéro de la vidéo'
MODEL_RELEASE_DATE = 'Date de publication'
MODEL_VERSION = 'Version'
MODEL_EXPLICIT = 'Explicit'
MODEL_ALBUM = 'Album'
MODEL_ID = 'ID'
MODEL_NAME = 'Nom'
MODEL_TYPE = 'Type'
+48 -35
View File
@@ -2,9 +2,9 @@
# -*- encoding: utf-8 -*-
'''
@File : german.py
@Time : 2021/01/04
@Authors : Sematre, MineClashTV
@Version : 1.0
@Time : 2022/11/8
@Authors : Sematre, MineClashTV, Click1701
@Version : 1.1
@Contact :
@Desc :
'''
@@ -24,20 +24,26 @@ class LangGerman(object):
SETTING_CHECK_EXIST = "Existenz überprüfen"
SETTING_ARTIST_BEFORE_TITLE = "Künstlername vor Songtitel"
SETTING_ALBUMID_BEFORE_FOLDER = "ID vor Album-Ordner"
SETTING_INCLUDE_EP = "Einschließlich single&ep"
SETTING_INCLUDE_EP = "Singles & EPs einschließen"
SETTING_SAVE_COVERS = "Cover speichern"
SETTING_LANGUAGE = "Sprache"
SETTING_USE_PLAYLIST_FOLDER = "Playlist-Ordner verwenden"
SETTING_MULITHREAD_DOWNLOAD = "Multi-Thread-Download"
SETTING_MULITHREAD_DOWNLOAD = "Multi-Thread Download"
SETTING_ALBUM_FOLDER_FORMAT = "Album-Ordnerformat"
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist-Ordnerformat"
SETTING_TRACK_FILE_FORMAT = "Track-Dateiformat"
SETTING_VIDEO_FILE_FORMAT = "Video-Dateiformat"
SETTING_SHOW_PROGRESS = "Fortschritt anzeigen"
SETTING_SHOW_TRACKIFNO = "Show Track Info"
SETTING_SAVE_ALBUMINFO = "Save AlbumInfo.txt"
SETTING_ADD_LYRICS = "Add lyrics"
SETTING_LYRICS_SERVER_PROXY = "Lyrics server proxy"
SETTING_PATH = "Settings path"
SETTINGS_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_SHOW_TRACKINFO = "Titelinformationen anzeigen"
SETTING_SAVE_ALBUMINFO = "AlbumInfo.txt speichern"
SETTING_DOWNLOAD_VIDEOS = "Download videos"
SETTING_ADD_LYRICS = "Songtexte hinzufügen"
SETTING_LYRICS_SERVER_PROXY = "Songtext Proxy-Server"
SETTING_ADD_LRC_FILE = "Songtext mit Zeitcode speichern (.lrc Datei)"
SETTING_PATH = "Speicherort der Einstellungen"
SETTING_APIKEY = "APIKey Unterstützung"
SETTING_ADD_TYPE_FOLDER = "Unterordner für jede Kategorie erstellen"
SETTING_DOWNLOAD_DELAY = "Downloads zeitverzögert starten"
CHOICE = "AUSWAHL"
FUNCTION = "FUNKTION"
@@ -47,8 +53,9 @@ class LangGerman(object):
CHOICE_LOGIN = "AccessToken überprüfen"
CHOICE_SETTINGS = "Einstellungen"
CHOICE_SET_ACCESS_TOKEN = "AccessToken setzen"
CHOICE_DOWNLOAD_BY_URL = "Herunterladen per URL oder ID"
CHOICE_LOGOUT = "Logout"
CHOICE_DOWNLOAD_BY_URL = "Download per URL oder ID"
CHOICE_LOGOUT = "Ausloggen"
CHOICE_APIKEY = "APIKey Auswahl"
PRINT_ERR = "[FEHLER]"
PRINT_INFO = "[INFO]"
@@ -59,39 +66,45 @@ class LangGerman(object):
# PRINT_USERNAME = "Benutzername:"
# PRINT_PASSWORD = "Passwort:"
CHANGE_START_SETTINGS = "Einstellungen starten ('0'-Zurück,'1'-Ja):"
CHANGE_START_SETTINGS = "Einstellungen starten ('0'-Zurück, '1'-Ja):"
CHANGE_DOWNLOAD_PATH = "Downloadpfad ('0' nicht ändern):"
CHANGE_AUDIO_QUALITY = "Tonqualität ('0'-Normal,'1'-Hoch,'2'-HiFi,'3'-Master):"
CHANGE_AUDIO_QUALITY = "Tonqualität ('0'-Normal, '1'-Hoch, '2'-HiFi, '3'-Master,'4'-Max):"
CHANGE_VIDEO_QUALITY = "Videoqualität (1080, 720, 480, 360):"
CHANGE_ONLYM4A = "mp4 in m4a konvertieren ('0'-Nein,'1'-Ja):"
CHANGE_ADD_EXPLICIT_TAG = "Explicit Tag zum Dateiname hinzufügen ('0'-Nein,'1'-Ja):"
CHANGE_ADD_HYPHEN = "Verwende Bindestriche statt Leerzeichen im Dateinamen ('0'-Nein,'1'-Ja):"
CHANGE_ADD_YEAR = "Jahr zu Album-Ordnernamen hinzufügen ('0'-Nein,'1'-Ja):"
CHANGE_USE_TRACK_NUM = "Titelnummer vor Dateinamen hinzufügen ('0'-Nein,'1'-Ja):"
CHANGE_CHECK_EXIST = "Vor dem Download überprüfen, ob die Datei existiert ('0'-Nein,'1'-Ja):"
CHANGE_ARTIST_BEFORE_TITLE = "Künstlername vor den Songtitel hinzufügen ('0'-Nein,'1'-Ja):"
CHANGE_INCLUDE_EP = "Singles und EPs beim Download von Alben eines Künstlers einbeziehen ('0'-Nein,'1'-Ja):"
CHANGE_ALBUMID_BEFORE_FOLDER = "ID vor Album-Ordner hinzufügen ('0'-Nein,'1'-Ja):"
CHANGE_SAVE_COVERS = "Cover speichern ('0'-Nein,'1'-Ja):"
CHANGE_ONLYM4A = "mp4 in m4a konvertieren ('0'-Nein, '1'-Ja):"
CHANGE_ADD_EXPLICIT_TAG = "Explicit Tag zum Dateiname hinzufügen ('0'-Nein, '1'-Ja):"
CHANGE_ADD_HYPHEN = "Im Dateinamen Bindestriche statt Leerzeichen verwenden ('0'-Nein, '1'-Ja):"
CHANGE_ADD_YEAR = "Jahr zu Album-Ordnernamen hinzufügen ('0'-Nein, '1'-Ja):"
CHANGE_USE_TRACK_NUM = "Titelnummer vor Dateinamen hinzufügen ('0'-Nein, '1'-Ja):"
CHANGE_CHECK_EXIST = "Vor dem Download überprüfen, ob die Datei existiert ('0'-Nein, '1'-Ja):"
CHANGE_ARTIST_BEFORE_TITLE = "Künstlername vor den Songtitel hinzufügen ('0'-Nein, '1'-Ja):"
CHANGE_INCLUDE_EP = "Singles und EPs beim Download von Alben eines Künstlers einbeziehen ('0'-Nein, '1'-Ja):"
CHANGE_ALBUMID_BEFORE_FOLDER = "ID vor Album-Ordner hinzufügen ('0'-Nein, '1'-Ja):"
CHANGE_SAVE_COVERS = "Cover speichern ('0'-Nein, '1'-Ja):"
CHANGE_LANGUAGE = "Sprache auswählen"
CHANGE_ALBUM_FOLDER_FORMAT = "Album-Ordnerformat('0' überspringen):"
CHANGE_TRACK_FILE_FORMAT = "Track-Dateiformat('0' überspringen):"
CHANGE_SHOW_PROGRESS = "Fortschritt anzeigen('0'-Nein,'1'-Ja):"
CHANGE_SHOW_TRACKINFO = "Show track info('0'-No,'1'-Yes):"
CHANGE_SAVE_ALBUM_INFO = "Save AlbumInfo.txt('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "Add lyrics('0'-No,'1'-Yes):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0' not modify):"
CHANGE_ADD_LRC_FILE = "Save timed lyrics .lrc file ('0'-No,'1'-Yes):"
CHANGE_ALBUM_FOLDER_FORMAT = "Album-Ordnerformat ('0' überspringen):"
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist Ordner-Format ('0'-nicht ändern, 'default'-für Standard):"
CHANGE_TRACK_FILE_FORMAT = "Track-Dateiformat ('0' überspringen):"
CHANGE_VIDEO_FILE_FORMAT = "Video-Dateiformat ('0'-nicht ändern, 'default'-für Standard):"
CHANGE_SHOW_PROGRESS = "Fortschritt anzeigen ('0'-Nein, '1'-Ja):"
CHANGE_SHOW_TRACKINFO = "Song-Informationen anzeigen ('0'-Nein, '1'-Ja):"
CHANGE_SAVE_ALBUM_INFO = "AlbumInfo.txt speichern ('0'-Nein, '1'-Ja):"
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "Songtexte hinzufügen ('0'-No, '1'-Yes):"
CHANGE_LYRICS_SERVER_PROXY = "Songtext Proxy-Server ('0'-not modify):"
CHANGE_ADD_LRC_FILE = "Songtexte mit Zeitcode speichern (.lrc Datei) ('0'-Nein, '1'-Ja):"
CHANGE_ADD_TYPE_FOLDER = "Unterordner für jede Kategorie erstellen, Z.B. Album/Video/Playlist('0'-Nein, '1'-Ja):"
CHANGE_MULITHREAD_DOWNLOAD = "Multi-Thread Download('0'-Nein, '1'-Ja):"
CHANGE_USE_DOWNLOAD_DELAY = "Downloads zeitverzögert starten ('0'-nein, '1'-ja):"
# {} are required in these strings
AUTH_START_LOGIN = "Starte Loginprozess..."
AUTH_LOGIN_CODE = "Dein Logincode ist {}"
AUTH_NEXT_STEP = "Gehe auf {} in den nächsten {} um das Setup abzuschließen."
AUTH_WAITING = "Auf Autorisierung warten..."
AUTH_WAITING = "Warte auf Autorisierung..."
AUTH_TIMEOUT = "Zeitüberschreitung der Operation."
MSG_VALID_ACCESSTOKEN = "AccessToken gültig für {}."
MSG_INVAILD_ACCESSTOKEN = "AccessToken abgelaufen. Versuche zu erneuern."
MSG_INVALID_ACCESSTOKEN = "AccessToken abgelaufen. Er muss erneuert werden."
MSG_PATH_ERR = "Ungültiger Pfad!"
MSG_INPUT_ERR = "Eingabefehler!"
+35 -22
View File
@@ -2,9 +2,9 @@
# -*- encoding: utf-8 -*-
'''
@File : hungarian.py
@Time : 2021/06/20
@Time : 2022/08/01
@Author : Shanahan
@Version : 1.0
@Version : 1.2
@Contact :
@Desc :
'''
@@ -25,19 +25,25 @@ class LangHungarian(object):
SETTING_ARTIST_BEFORE_TITLE = "Előadó neve a szám címe előtt"
SETTING_ALBUMID_BEFORE_FOLDER = "Azonosító (ID) az album-mappa előtt"
SETTING_INCLUDE_EP = "Tartalmazza a single&ep"
SETTING_SAVE_COVERS = "Borító mentése"
SETTING_SAVE_COVERS = "Borítókép mentése"
SETTING_LANGUAGE = "Nyelv"
SETTING_USE_PLAYLIST_FOLDER = "Lejátszási lista mappa használata"
SETTING_MULITHREAD_DOWNLOAD = "Többszálú letöltés"
SETTING_ALBUM_FOLDER_FORMAT = "Album mappa formátum"
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
SETTING_TRACK_FILE_FORMAT = "Track fájlformátum"
SETTING_VIDEO_FILE_FORMAT = "Videó fájlformátum"
SETTING_SHOW_PROGRESS = "Haladás megjelenítése"
SETTING_SHOW_TRACKIFNO = "Show Track Info"
SETTING_SHOW_TRACKINFO = "Track infók megjelenítése"
SETTING_SAVE_ALBUMINFO = "AlbumInfo.txt mentése"
SETTING_DOWNLOAD_VIDEOS = "Download videos"
SETTING_ADD_LYRICS = "Dalszöveg hozzáadása"
SETTING_LYRICS_SERVER_PROXY = "Dalszöveg kiszolgáló proxy"
SETTING_PATH = "Beállítások elérési útvonala"
SETTINGS_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_ADD_LRC_FILE = "Dalszövegek mentése (.lrc fájl)"
SETTING_PATH = "Beállítási útvonal"
SETTING_APIKEY = "APIKey támogatás"
SETTING_ADD_TYPE_FOLDER = "Mappa típus hozzáadása"
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
CHOICE = "VÁLASZTÁS"
FUNCTION = "FUNKCIÓ"
@@ -49,6 +55,7 @@ class LangHungarian(object):
CHOICE_SET_ACCESS_TOKEN = "AccessToken beállítása"
CHOICE_DOWNLOAD_BY_URL = "Letöltés URL vagy ID alapján"
CHOICE_LOGOUT = "Kijelentkezés"
CHOICE_APIKEY = "APIKey kiválasztása"
PRINT_ERR = "[HIBA]"
PRINT_INFO = "[INFÓ]"
@@ -57,11 +64,11 @@ class LangHungarian(object):
PRINT_ENTER_CHOICE = "Válasszon:"
PRINT_LATEST_VERSION = "Legújabb verzió:"
# PRINT_USERNAME = "felhasználónév:"
# PRINT_PASSWORD = "jelszó
# PRINT_PASSWORD = "jelszó:"
CHANGE_START_SETTINGS = "Beállítások indítása('0'- Vissza, '1'-Igen):"
CHANGE_DOWNLOAD_PATH = "Letöltési útvonal('0' nincs módosítás):"
CHANGE_AUDIO_QUALITY = "Audió minőség('0'-Normal,'1'-High,'2'-HiFi,'3'-Master):"
CHANGE_AUDIO_QUALITY = "Audió minőség('0'-Normal,'1'-High,'2'-HiFi,'3'-Master,'4'-Max):"
CHANGE_VIDEO_QUALITY = "Videó minőség(1080, 720, 480, 360):"
CHANGE_ONLYM4A = "mp4 átalakítása m4a-ra('0'-Nem,'1'-Igen):"
CHANGE_ADD_EXPLICIT_TAG = "Explicit tag hozzáadása a fájlnevekhez('0'-Nem,'1'-Igen):"
@@ -70,18 +77,24 @@ class LangHungarian(object):
CHANGE_USE_TRACK_NUM = "Track szám hozzáadása a fájlnevek előtt('0'-Nem,'1'-Igen):"
CHANGE_CHECK_EXIST = "Létező fájl ellenőrzése letöltés előtt('0'-Nem,'1'-Igen):"
CHANGE_ARTIST_BEFORE_TITLE = "Előadó hozzáadása a szám címe előtt('0'-Nem,'1'-Igen):"
CHANGE_INCLUDE_EP = "A kislemezek és EP-k letöltése('0'-nem, '1'-igen):"
CHANGE_INCLUDE_EP = "A kislemezek és EP-k letöltése('0'-Nem, '1'-Igen):"
CHANGE_ALBUMID_BEFORE_FOLDER = "Azonosító (ID) az album mappa előtt('0'-Nem,'1'-Igen):"
CHANGE_SAVE_COVERS = "Borító mentése('0'-nem, '1'-igen):"
CHANGE_SAVE_COVERS = "Borító mentése('0'-Nem, '1'-Igen):"
CHANGE_LANGUAGE = "Nyelv kiválasztása"
CHANGE_ALBUM_FOLDER_FORMAT = "Album mappa formátum('0' nincs módosítás,'default' az alapértelmezett beállításhoz):"
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
CHANGE_TRACK_FILE_FORMAT = "Track fájl neve('0' nincs módosítás,'default' az alapértelmezett beállításhoz):"
CHANGE_SHOW_PROGRESS = "Haladás megjelenítése('0'-nem, '1'-igen):"
CHANGE_SHOW_TRACKINFO = "Show track info('0'-No,'1'-Yes):"
CHANGE_SAVE_ALBUM_INFO = "AlbumInfo.txt mentése('0'-nem, '1'-igen):"
CHANGE_ADD_LYRICS = "Dalszöveg hozzáadása('0'-nem,'1'-igen):"
CHANGE_LYRICS_SERVER_PROXY = "Dalszöveg kiszolgáló prox('0' nincs módosítás):"
CHANGE_ADD_LRC_FILE = "Save timed lyrics .lrc file ('0'-No,'1'-Yes):"
CHANGE_VIDEO_FILE_FORMAT = "Video file format('0'-nincs módosítás,'default' az alapértelmezett beállításhoz):"
CHANGE_SHOW_PROGRESS = "Haladás megjelenítése('0'-Nem, '1'-Igen):"
CHANGE_SHOW_TRACKINFO = "Track infók megjelenítése('0'-Nem,'1'-Igen):"
CHANGE_SAVE_ALBUM_INFO = "AlbumInfo.txt mentése('0'-Nem, '1'-Igen):"
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "Dalszöveg hozzáadása('0'-Nem,'1'-Igen):"
CHANGE_LYRICS_SERVER_PROXY = "Dalszöveg kiszolgáló proxy('0' nincs módosítás):"
CHANGE_ADD_LRC_FILE = "Dalszöveg mentése időbélyeggel .lrc fájl('0'-Nem,'1'-Igen):"
CHANGE_ADD_TYPE_FOLDER = "Mappa típus hozzáadása, pl. Album/Video/Playlist('0'-Nem,'1'-Igen):"
CHANGE_MULITHREAD_DOWNLOAD = "Többszálas letöltés('0'-Nem,'1'-Igen):"
CHANGE_USE_DOWNLOAD_DELAY = "Use Download Delay('0'-No,'1'-Yes):"
# {} are required in these strings
AUTH_START_LOGIN = "Bejelentkezési folyamat elindítása..."
@@ -91,15 +104,15 @@ class LangHungarian(object):
AUTH_TIMEOUT = "A művelet leállt."
MSG_VALID_ACCESSTOKEN = "AccessToken érvényessége {}."
MSG_INVAILD_ACCESSTOKEN = "Lejárt AccessToken. Megpróbálom frissíteni."
MSG_INVALID_ACCESSTOKEN = "Lejárt AccessToken. Megpróbálom frissíteni."
MSG_PATH_ERR = "Az útvonal hibás!"
MSG_INPUT_ERR = "Beviteli hiba!"
MODEL_ALBUM_PROPERTY = "ALBUM-TULAJDONSÁGOK"
MODEL_TRACK_PROPERTY = "TRACK-TULAJDONSÁGOK"
MODEL_VIDEO_PROPERTY = "VIDEO-TULAJDONSÁGOK"
MODEL_ARTIST_PROPERTY = "ELŐADÓ-TULAJDONSÁGOK"
MODEL_PLAYLIST_PROPERTY = "LEJÁTSZÁSI LISTA-TULAJDONSÁGOK"
MODEL_ALBUM_PROPERTY = "ALBUM-INFÓ"
MODEL_TRACK_PROPERTY = "TRACK-INFÓ"
MODEL_VIDEO_PROPERTY = "VIDEO-INFÓ"
MODEL_ARTIST_PROPERTY = "ELŐADÓ-INFÓ"
MODEL_PLAYLIST_PROPERTY = "LEJÁTSZÁSI LISTA-INFÓ"
MODEL_TITLE = 'Cím'
MODEL_TRACK_NUMBER = 'Track száma'
+20 -7
View File
@@ -30,14 +30,20 @@ class LangItalian(object):
SETTING_USE_PLAYLIST_FOLDER = "Use playlist folder"
SETTING_MULITHREAD_DOWNLOAD = "Multi thread download"
SETTING_ALBUM_FOLDER_FORMAT = "Album folder format"
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
SETTING_TRACK_FILE_FORMAT = "Track file format"
SETTING_VIDEO_FILE_FORMAT = "Video file format"
SETTING_SHOW_PROGRESS = "Show progress"
SETTING_SHOW_TRACKIFNO = "Show Track Info"
SETTING_SHOW_TRACKINFO = "Show Track Info"
SETTING_SAVE_ALBUMINFO = "Save AlbumInfo.txt"
SETTING_DOWNLOAD_VIDEOS = "Download videos"
SETTING_ADD_LYRICS = "Add lyrics"
SETTING_LYRICS_SERVER_PROXY = "Lyrics server proxy"
SETTING_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_PATH = "Settings path"
SETTINGS_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_APIKEY = "APIKey support"
SETTING_ADD_TYPE_FOLDER = "Add Type-Folder"
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
CHOICE = "SCELTA"
FUNCTION = "FUNZIONE"
@@ -49,6 +55,7 @@ class LangItalian(object):
CHOICE_SET_ACCESS_TOKEN = "Imposta AccessToken"
CHOICE_DOWNLOAD_BY_URL = "Scarica per URL o Id"
CHOICE_LOGOUT = "Logout"
CHOICE_APIKEY = "Select APIKey"
PRINT_ERR = "[ERR]"
PRINT_INFO = "[INFO]"
@@ -61,7 +68,7 @@ class LangItalian(object):
CHANGE_START_SETTINGS = "Impostazioni all'avvio ('0'-Ritorna,'1'-Sì):"
CHANGE_DOWNLOAD_PATH = "Percorso Download ('0' non modificare):"
CHANGE_AUDIO_QUALITY = "Qualità Audio ('0'-Normale, '1'-Alta, '2'-HiFi, '3'-Master):"
CHANGE_AUDIO_QUALITY = "Qualità Audio ('0'-Normale, '1'-Alta, '2'-HiFi, '3'-Master,'4'-Max):"
CHANGE_VIDEO_QUALITY = "Qualità Video (1080, 720, 480, 360):"
CHANGE_ONLYM4A = "Convertire mp4 in m4a ('0'-No,'1'-):"
CHANGE_ADD_EXPLICIT_TAG = "Aggiungi tag 'Contenuto Esplicito' ai nomi dei file ('0'-No,'1'-Sì):"
@@ -74,14 +81,20 @@ class LangItalian(object):
CHANGE_ALBUMID_BEFORE_FOLDER = "Aggiungere ID prima del nome della cartella per l'album ('0'-No,'1'-Sì):"
CHANGE_SAVE_COVERS = "Salve copertine ('0'-No,'1'-Sì):"
CHANGE_LANGUAGE = "Selezionare lingua"
CHANGE_ALBUM_FOLDER_FORMAT = "Album folder format('0' not modify):"
CHANGE_TRACK_FILE_FORMAT = "Track file format('0' not modify):"
CHANGE_ALBUM_FOLDER_FORMAT = "Album folder format('0' not modify,'default'-to set default):"
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
CHANGE_TRACK_FILE_FORMAT = "Track file format('0' not modify,'default'-to set default):"
CHANGE_VIDEO_FILE_FORMAT = "Video file format('0'-not modify,'default'-to set default):"
CHANGE_SHOW_PROGRESS = "Show progress('0'-No,'1'-Yes):"
CHANGE_SHOW_TRACKINFO = "Show track info('0'-No,'1'-Yes):"
CHANGE_SAVE_ALBUM_INFO = "Save AlbumInfo.txt('0'-No,'1'-Yes):"
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "Add lyrics('0'-No,'1'-Yes):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0' not modify):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0'-not modify):"
CHANGE_ADD_LRC_FILE = "Save timed lyrics .lrc file ('0'-No,'1'-Yes):"
CHANGE_ADD_TYPE_FOLDER = "Add Type-Folder,eg Album/Video/Playlist('0'-No,'1'-Yes):"
CHANGE_MULITHREAD_DOWNLOAD = "Multi thread download('0'-No,'1'-Yes):"
CHANGE_USE_DOWNLOAD_DELAY = "Use Download Delay('0'-No,'1'-Yes):"
# {} are required in these strings
AUTH_START_LOGIN = "Starting login process..."
@@ -91,7 +104,7 @@ class LangItalian(object):
AUTH_TIMEOUT = "Operation timed out."
MSG_VALID_ACCESSTOKEN = "AccessToken good for {}."
MSG_INVAILD_ACCESSTOKEN = "Expired AccessToken. Attempting to refresh it."
MSG_INVALID_ACCESSTOKEN = "Expired AccessToken. Attempting to refresh it."
MSG_PATH_ERR = "Percorso errato!"
MSG_INPUT_ERR = "Inserimento errato!"
+126
View File
@@ -0,0 +1,126 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : japanese.py
@Time : 2021/11/30
@Author : jee019
@Version : 1.0
@Contact : qwer010910@gmail.com
@Desc :
'''
class LangJapanese(object):
SETTING = "設定"
VALUE = ""
SETTING_DOWNLOAD_PATH = "ダウンロードパス"
SETTING_ONLY_M4A = "mp4をm4aに変換する"
SETTING_ADD_EXPLICIT_TAG = "explicitタグ付けする"
SETTING_ADD_HYPHEN = "ハイフンを追加"
SETTING_ADD_YEAR = "Add year before album-folder"
SETTING_USE_TRACK_NUM = "ユーザートラック番号を追加"
SETTING_AUDIO_QUALITY = "オーディオ品質"
SETTING_VIDEO_QUALITY = "ビデオ品質"
SETTING_CHECK_EXIST = "Check exist"
SETTING_ARTIST_BEFORE_TITLE = "ArtistName before track-title"
SETTING_ALBUMID_BEFORE_FOLDER = "Id before album-folder"
SETTING_INCLUDE_EP = "含む singles & EPs"
SETTING_SAVE_COVERS = "カバーを保存"
SETTING_LANGUAGE = "言語"
SETTING_USE_PLAYLIST_FOLDER = "Use playlist folder"
SETTING_MULITHREAD_DOWNLOAD = "Multi thread download"
SETTING_ALBUM_FOLDER_FORMAT = "Album folder format"
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
SETTING_TRACK_FILE_FORMAT = "Track file format"
SETTING_VIDEO_FILE_FORMAT = "Video file format"
SETTING_SHOW_PROGRESS = "Show progress"
SETTING_SHOW_TRACKINFO = "Show Track Info"
SETTING_SAVE_ALBUMINFO = "Save AlbumInfo.txt"
SETTING_DOWNLOAD_VIDEOS = "Download videos"
SETTING_ADD_LYRICS = "歌詞を追加"
SETTING_LYRICS_SERVER_PROXY = "Lyrics server proxy"
SETTING_ADD_LRC_FILE = "Save timed lyrics (.lrc file)"
SETTING_PATH = "設定パス"
SETTING_APIKEY = "APIKey support"
SETTING_ADD_TYPE_FOLDER = "Add Type-Folder"
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
CHOICE = "選択"
FUNCTION = "関数"
CHOICE_ENTER = "エンター"
CHOICE_ENTER_URLID = "エンター 'Url/ID':"
CHOICE_EXIT = "エグジット"
CHOICE_LOGIN = "AccessTokenを確認してください"
CHOICE_SETTINGS = "セッティング"
CHOICE_SET_ACCESS_TOKEN = "AccessTokenを設定する"
CHOICE_DOWNLOAD_BY_URL = "UrlまたはIDでダウンロード"
CHOICE_LOGOUT = "ログアウト"
CHOICE_APIKEY = "Select APIKey"
PRINT_ERR = "[エラー]"
PRINT_INFO = "[情報]"
PRINT_SUCCESS = "[サクセス]"
PRINT_ENTER_CHOICE = "エンター 選択:"
PRINT_LATEST_VERSION = "最新バージョン:"
# PRINT_USERNAME = "ユーザー名:"
# PRINT_PASSWORD = "パスワード:"
CHANGE_START_SETTINGS = "設定を開始('0'-戻る,'1'-はい):"
CHANGE_DOWNLOAD_PATH = "ダウンロードパス('0'-変更しない):"
CHANGE_AUDIO_QUALITY = "オーディオ品質('0'-Normal,'1'-High,'2'-HiFi,'3'-Master,'4'-Max):"
CHANGE_VIDEO_QUALITY = "ビデオ品質(1080, 720, 480, 360):"
CHANGE_ONLYM4A = "mp4をm4aに変換する('0'-いいえ,'1'-はい):"
CHANGE_ADD_EXPLICIT_TAG = "Add explicit tag to file names('0'-いいえ,'1'-はい):"
CHANGE_ADD_HYPHEN = "Use hyphens instead of spaces in file names('0'-いいえ,'1'-はい):"
CHANGE_ADD_YEAR = "Add year to album folder names('0'-いいえ,'1'-はい):"
CHANGE_USE_TRACK_NUM = "Add track number before file names('0'-いいえ,'1'-はい):"
CHANGE_CHECK_EXIST = "Check exist file before download track('0'-いいえ,'1'-はい):"
CHANGE_ARTIST_BEFORE_TITLE = "Add artistName before track title('0'-いいえ,'1'-はい):"
CHANGE_INCLUDE_EP = "Include singles and EPs when downloading an artist's albums('0'-いいえ,'1'-はい):"
CHANGE_ALBUMID_BEFORE_FOLDER = "Add id before album folder('0'-いいえ,'1'-はい):"
CHANGE_SAVE_COVERS = "カバーを保存('0'-いいえ,'1'-はい):"
CHANGE_LANGUAGE = "言語を選択する"
CHANGE_ALBUM_FOLDER_FORMAT = "Album folder format('0'-変更しない,'default'-デフォルトを設定するには):"
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
CHANGE_TRACK_FILE_FORMAT = "Track file format('0'-変更しない,'default'-デフォルトを設定するには):"
CHANGE_VIDEO_FILE_FORMAT = "Video file format('0'-not modify,'default'-to set default):"
CHANGE_SHOW_PROGRESS = "Show progress('0'-いいえ,'1'-はい):"
CHANGE_SHOW_TRACKINFO = "Show track info('0'-いいえ,'1'-はい):"
CHANGE_SAVE_ALBUM_INFO = "Save AlbumInfo.txt('0'-いいえ,'1'-はい):"
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "歌詞を追加('0'-いいえ,'1'-はい):"
CHANGE_LYRICS_SERVER_PROXY = "Lyrics server proxy('0'-変更しない):"
CHANGE_ADD_LRC_FILE = "Save timed lyrics .lrc file ('0'-いいえ,'1'-はい):"
CHANGE_ADD_TYPE_FOLDER = "Add Type-Folder,eg Album/Video/Playlist('0'-No,'1'-Yes):"
CHANGE_MULITHREAD_DOWNLOAD = "Multi thread download('0'-No,'1'-Yes):"
CHANGE_USE_DOWNLOAD_DELAY = "Use Download Delay('0'-No,'1'-Yes):"
# {} are required in these strings
AUTH_START_LOGIN = "Starting login process..."
AUTH_LOGIN_CODE = "Your login code is {}"
AUTH_NEXT_STEP = "Go to {} within the next {} to complete setup."
AUTH_WAITING = "Waiting for authorization..."
AUTH_TIMEOUT = "Operation timed out."
MSG_VALID_ACCESSTOKEN = "AccessToken good for {}."
MSG_INVALID_ACCESSTOKEN = "Expired AccessToken. Attempting to refresh it."
MSG_PATH_ERR = "パスはエラーです!"
MSG_INPUT_ERR = "入力エラー!"
MODEL_ALBUM_PROPERTY = "アルバム-情報"
MODEL_TRACK_PROPERTY = "トラック-情報"
MODEL_VIDEO_PROPERTY = "ビデオ-情報"
MODEL_ARTIST_PROPERTY = "アーティスト-情報"
MODEL_PLAYLIST_PROPERTY = "プレイリスト-情報"
MODEL_TITLE = '題名'
MODEL_TRACK_NUMBER = 'トラック番号'
MODEL_VIDEO_NUMBER = 'ビデオ番号'
MODEL_RELEASE_DATE = '発売日'
MODEL_VERSION = 'バージョン'
MODEL_EXPLICIT = 'Explicit'
MODEL_ALBUM = 'アルバム'
MODEL_ID = 'ID'
MODEL_NAME = '名前'
MODEL_TYPE = 'タイプ'
+26 -13
View File
@@ -2,9 +2,9 @@
# -*- encoding: utf-8 -*-
'''
@File : korean.py
@Time : 2021/11/11
@Time : 2021/11/24
@Author : jee019
@Version : 1.0
@Version : 1.1
@Contact : qwer010910@gmail.com
@Desc :
'''
@@ -30,14 +30,20 @@ class LangKorean(object):
SETTING_USE_PLAYLIST_FOLDER = "재생목록 폴더 사용"
SETTING_MULITHREAD_DOWNLOAD = "다중 스레드 다운로드"
SETTING_ALBUM_FOLDER_FORMAT = "앨범 폴더 형식"
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
SETTING_TRACK_FILE_FORMAT = "트랙 파일 형식"
SETTING_VIDEO_FILE_FORMAT = "Video file format"
SETTING_SHOW_PROGRESS = "진행 상태 표시"
SETTING_SHOW_TRACKIFNO = "트랙 정보 표시"
SETTING_SHOW_TRACKINFO = "트랙 정보 표시"
SETTING_SAVE_ALBUMINFO = "AlbumInfo.txt 저장"
SETTING_DOWNLOAD_VIDEOS = "Download videos"
SETTING_ADD_LYRICS = "가사 추가"
SETTING_LYRICS_SERVER_PROXY = "가사 서버 프록시"
SETTINGS_ADD_LRC_FILE = "맞춤 가사 저장 (.lrc 파일)"
SETTING_ADD_LRC_FILE = "timed 가사 저장 (.lrc 파일)"
SETTING_PATH = "설정 경로"
SETTING_APIKEY = "APIKey support"
SETTING_ADD_TYPE_FOLDER = "Add Type-Folder"
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
CHOICE = "선택"
FUNCTION = "기능"
@@ -47,8 +53,9 @@ class LangKorean(object):
CHOICE_LOGIN = "액세스 토큰 확인"
CHOICE_SETTINGS = "설정"
CHOICE_SET_ACCESS_TOKEN = "액세스 토큰 설정"
CHOICE_DOWNLOAD_BY_URL = "url 또는 id로 다운로드"
CHOICE_DOWNLOAD_BY_URL = "Url 또는 id로 다운로드"
CHOICE_LOGOUT = "로그아웃"
CHOICE_APIKEY = "Select APIKey"
PRINT_ERR = "[에러]"
PRINT_INFO = "[정보]"
@@ -60,8 +67,8 @@ class LangKorean(object):
# PRINT_PASSWORD = "비밀번호:"
CHANGE_START_SETTINGS = "설정 시작('0'-뒤로가기,'1'-예):"
CHANGE_DOWNLOAD_PATH = "다운로드 경로('0' 변경 안 함):"
CHANGE_AUDIO_QUALITY = "음질('0'-보통,'1'-높음,'2'-HiFi,'3'-Master):"
CHANGE_DOWNLOAD_PATH = "다운로드 경로('0'-변경 안 함):"
CHANGE_AUDIO_QUALITY = "음질('0'-보통,'1'-높음,'2'-HiFi,'3'-Master,'4'-Max):"
CHANGE_VIDEO_QUALITY = "영상 화질(1080, 720, 480, 360):"
CHANGE_ONLYM4A = "mp4를 m4a로 변환('0'-아니요,'1'-예):"
CHANGE_ADD_EXPLICIT_TAG = "파일 이름에 explicit 태그 추가('0'-아니요,'1'-예):"
@@ -74,14 +81,20 @@ class LangKorean(object):
CHANGE_ALBUMID_BEFORE_FOLDER = "앨범 폴더 앞에 ID 추가('0'-아니요,'1'-예):"
CHANGE_SAVE_COVERS = "커버 저장('0'-아니요,'1'-예):"
CHANGE_LANGUAGE = "언어 선택"
CHANGE_ALBUM_FOLDER_FORMAT = "앨범 폴더 형식('0' 변경 안 함,'default' 기본 설정):"
CHANGE_TRACK_FILE_FORMAT = "트랙 파일 형식('0' 변경 안 함,'default' 기본 설정):"
CHANGE_ALBUM_FOLDER_FORMAT = "앨범 폴더 형식('0'-변경 안 함,'default'-기본 설정):"
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
CHANGE_TRACK_FILE_FORMAT = "트랙 파일 형식('0'-변경 안 함,'default'-기본 설정):"
CHANGE_VIDEO_FILE_FORMAT = "Video file format('0'-not modify,'default'-to set default):"
CHANGE_SHOW_PROGRESS = "진행 상태 표시('0'-아니요,'1'-예):"
CHANGE_SHOW_TRACKINFO = "트랙 정보 표시('0'-아니요,'1'-예):"
CHANGE_SAVE_ALBUM_INFO = "AlbumInfo.txt 저장('0'-아니요,'1'-예):"
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
CHANGE_ADD_LYRICS = "가사 추가('0'-아니요,'1'-예):"
CHANGE_LYRICS_SERVER_PROXY = "가사 서버 프록시('0' 변경 안 함):"
CHANGE_ADD_LRC_FILE = "맞춤 가사 .lrc 파일 저장 ('0'-아니요,'1'-예):"
CHANGE_LYRICS_SERVER_PROXY = "가사 서버 프록시('0'-변경 안 함):"
CHANGE_ADD_LRC_FILE = "timed 가사 .lrc 파일 저장 ('0'-아니요,'1'-예):"
CHANGE_ADD_TYPE_FOLDER = "Add Type-Folder,eg Album/Video/Playlist('0'-No,'1'-Yes):"
CHANGE_MULITHREAD_DOWNLOAD = "Multi thread download('0'-No,'1'-Yes):"
CHANGE_USE_DOWNLOAD_DELAY = "Use Download Delay('0'-No,'1'-Yes):"
# {} are required in these strings
AUTH_START_LOGIN = "로그인 중..."
@@ -90,8 +103,8 @@ class LangKorean(object):
AUTH_WAITING = "승인 대기 중..."
AUTH_TIMEOUT = "작업 시간 초과"
MSG_VALID_ACCESSTOKEN = "{}에 대해 액세스토큰이 유효합니다."
MSG_INVAILD_ACCESSTOKEN = "만료된 액세스 토큰입니다. 새로 고침 중입니다."
MSG_VALID_ACCESSTOKEN = "{}에 대해 액세스 토큰이 유효합니다."
MSG_INVALID_ACCESSTOKEN = "만료된 액세스 토큰입니다. 새로 고침 중입니다."
MSG_PATH_ERR = "경로 오류!"
MSG_INPUT_ERR = "입력 오류!"
+82 -123
View File
@@ -6,131 +6,90 @@
@Author : Yaronzz
@Version : 1.0
@Contact : yaronhuang@foxmail.com
@Desc :
@Desc :
'''
from tidal_dl.lang.arabic import LangArabic
from tidal_dl.lang.chinese import LangChinese
from tidal_dl.lang.croatian import LangCroatian
from tidal_dl.lang.czech import LangCzech
from tidal_dl.lang.danish import LangDanish
from tidal_dl.lang.english import LangEnglish
from tidal_dl.lang.filipino import LangFilipino
from tidal_dl.lang.french import LangFrench
from tidal_dl.lang.german import LangGerman
from tidal_dl.lang.hungarian import LangHungarian
from tidal_dl.lang.italian import LangItalian
from tidal_dl.lang.portuguese import LangPortuguese
from tidal_dl.lang.russian import LangRussian
from tidal_dl.lang.spanish import LangSpanish
from tidal_dl.lang.turkish import LangTurkish
from tidal_dl.lang.ukrainian import LangUkrainian
from tidal_dl.lang.vietnamese import LangVietnamese
from tidal_dl.lang.korean import LangKorean
from lang.arabic import LangArabic
from lang.chinese import LangChinese
from lang.croatian import LangCroatian
from lang.czech import LangCzech
from lang.danish import LangDanish
from lang.dutch import LangDutch
from lang.english import LangEnglish
from lang.filipino import LangFilipino
from lang.french import LangFrench
from lang.german import LangGerman
from lang.hungarian import LangHungarian
from lang.italian import LangItalian
from lang.norwegian import LangNorwegian
from lang.polish import LangPolish
from lang.portuguese import LangPortuguese
from lang.russian import LangRussian
from lang.spanish import LangSpanish
from lang.turkish import LangTurkish
from lang.ukrainian import LangUkrainian
from lang.vietnamese import LangVietnamese
from lang.korean import LangKorean
from lang.japanese import LangJapanese
LANG = None
_ALL_LANGUAGE_ = [
['English', LangEnglish()],
['中文', LangChinese()],
['Turkish', LangTurkish()],
['Italian', LangItalian()],
['Czech', LangCzech()],
['Arabic', LangArabic()],
['Russian', LangRussian()],
['Filipino', LangFilipino()],
['Croatian', LangCroatian()],
['Spanish', LangSpanish()],
['Portuguese', LangPortuguese()],
['Ukrainian', LangUkrainian()],
['Vietnamese', LangVietnamese()],
['French', LangFrench()],
['German', LangGerman()],
['Danish', LangDanish()],
['Hungarian', LangHungarian()],
['Korean', LangKorean()],
['Japanese', LangJapanese()],
['Dutch', LangDutch()],
['Polish', LangPolish()],
['Norwegian', LangNorwegian()],
]
class Language(object):
def __init__(self) -> None:
self.select = LangEnglish()
def __toInt__(self, str):
try:
return int(str)
except:
return 0
def setLang(self, index):
index = self.__toInt__(index)
if index >= 0 and index < len(_ALL_LANGUAGE_):
self.select = _ALL_LANGUAGE_[index][1]
else:
self.select = LangEnglish()
def getLangName(self, index):
index = self.__toInt__(index)
if index >= 0 and index < len(_ALL_LANGUAGE_):
return _ALL_LANGUAGE_[index][0]
return ""
def getLangChoicePrint(self):
array = []
index = 0
while True:
name = self.getLangName(index)
if name == "":
break
array.append('\'' + str(index) + '\'-' + name)
index += 1
return ','.join(array)
def initLang(index): # 初始化
global LANG
return setLang(index)
def setLang(index):
global LANG
if str(index) == '0':
LANG = LangEnglish()
elif str(index) == '1':
LANG = LangChinese()
elif str(index) == '2':
LANG = LangTurkish()
elif str(index) == '3':
LANG = LangItalian()
elif str(index) == '4':
LANG = LangCzech()
elif str(index) == '5':
LANG = LangArabic()
elif str(index) == '6':
LANG = LangRussian()
elif str(index) == '7':
LANG = LangFilipino()
elif str(index) == '8':
LANG = LangCroatian()
elif str(index) == '9':
LANG = LangSpanish()
elif str(index) == '10':
LANG = LangPortuguese()
elif str(index) == '11':
LANG = LangUkrainian()
elif str(index) == '12':
LANG = LangVietnamese()
elif str(index) == '13':
LANG = LangFrench()
elif str(index) == '14':
LANG = LangGerman()
elif str(index) == '15':
LANG = LangDanish()
elif str(index) == '16':
LANG = LangHungarian()
elif str(index) == '17':
LANG = LangKorean()
else:
LANG = LangEnglish()
return LANG
def getLang():
global LANG
return LANG
def getLangName(index):
if str(index) == '0':
return "English"
if str(index) == '1':
return "中文"
if str(index) == '2':
return "Turkish"
if str(index) == '3':
return "Italian"
if str(index) == '4':
return "Czech"
if str(index) == '5':
return "Arabic"
if str(index) == '6':
return "Russian"
if str(index) == '7':
return "Filipino"
if str(index) == '8':
return "Croatian"
if str(index) == '9':
return "Spanish"
if str(index) == '10':
return "Portuguese"
if str(index) == '11':
return "Ukrainian"
if str(index) == '12':
return "Vietnamese"
if str(index) == '13':
return "French"
if str(index) == '14':
return "German"
if str(index) == '15':
return "Danish"
if str(index) == '16':
return "Hungarian"
if str(index) == '17':
return "Korean"
return ""
def getLangChoicePrint():
array = []
index = 0
while True:
name = getLangName(index)
if name == "":
break
array.append('\'' + str(index) + '\'-' + name)
index += 1
return ','.join(array)
LANG = Language()

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