mirror of
https://github.com/yaronzz/Tidal-Media-Downloader.git
synced 2026-06-13 12:15:12 +03:00
Compare commits
457 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f4854f4b74 | |||
| 8352f0f6e2 | |||
| a8da5c0ff3 | |||
| df7c444487 | |||
| d88dca4da6 | |||
| 88b5b61328 | |||
| 56c9cf5695 | |||
| 379eca8458 | |||
| 7d6f9fc6e1 | |||
| 87eabab36f | |||
| 288c75bcc7 | |||
| 62d83b5975 | |||
| 251af9e745 | |||
| 0751c37b35 | |||
| 4f32b14441 | |||
| 97928ef207 | |||
| 9edd5967f0 | |||
| 8449b85d81 | |||
| 2f4ad82421 | |||
| 513be57c3d | |||
| 3eb11252c2 | |||
| b972f7cda8 | |||
| b1b643109c | |||
| c15ad63542 | |||
| 09321db35e | |||
| 132e516250 | |||
| a771c598ae | |||
| db76e84123 | |||
| 7eb4419177 | |||
| df3c405667 | |||
| 951fd102ad | |||
| 252076f6dd | |||
| 11828a0e8e | |||
| 93f363f405 | |||
| 12a96d8a46 | |||
| 238b2da4b3 | |||
| 76313d68c9 | |||
| 4e8751ceb1 | |||
| 2dfcbad8f0 | |||
| 07d18ce2d6 | |||
| 7fdd307176 | |||
| 11805382cc | |||
| 044a847e78 | |||
| 6e49253e99 | |||
| 0c83717469 | |||
| 7f1afb27f1 | |||
| 18efb49213 | |||
| a275275cb6 | |||
| 7e5b6d22c4 | |||
| 96742046ba | |||
| 3199dcedc6 | |||
| 2cf59b3195 | |||
| be84a3631a | |||
| 9ce35af72f | |||
| 9d904a0fea | |||
| 5e05afd775 | |||
| dece506d58 | |||
| c2cc170988 | |||
| 3cab9ea295 | |||
| 5cf094d227 | |||
| 2e1e15ed3f | |||
| 7434470216 | |||
| 2ce2a310ae | |||
| dfc7af7796 | |||
| 63bf063dd3 | |||
| 3e8a3436b4 | |||
| e08e5efc88 | |||
| 7f3758e18c | |||
| 3e2d74a37f | |||
| 69ccd65025 | |||
| 81b82e6c29 | |||
| 346befda6d | |||
| 450102bfea | |||
| a966b3d93d | |||
| 55df515256 | |||
| 242747719a | |||
| e3c5886a02 | |||
| 33c49b83db | |||
| ed13b9b92d | |||
| e45f649e46 | |||
| 0172301769 | |||
| a7aa38e563 | |||
| fd97a2b966 | |||
| e1ee47b93c | |||
| 61b9dd3af8 | |||
| 628a42b058 | |||
| 2c392f0e22 | |||
| dc57d4d01d | |||
| 8ed83b1672 | |||
| 3099820956 | |||
| d643de43e9 | |||
| 39db4730c5 | |||
| 937aa7ca8f | |||
| 84b9f6f6bc | |||
| b1ebd6f0b2 | |||
| e1562ba30e | |||
| 8876be13b6 | |||
| 30a6c8c55a | |||
| eb01de7f3a | |||
| e652556de2 | |||
| 00ef2f906f | |||
| aba9493201 | |||
| c78a56fff0 | |||
| 56bf0f9510 | |||
| 2ebf80869c | |||
| bb5be5e5fb | |||
| 5c2a13d4d1 | |||
| c61be4bbf3 | |||
| a969583d79 | |||
| 9f9a4f9aef | |||
| 3b3af6a174 | |||
| 166961297e | |||
| 1f5343569f | |||
| 9e9d47f470 | |||
| 6870a8c37f | |||
| 4d368dd04d | |||
| 64b98ee117 | |||
| 5ec77efb19 | |||
| 65da2f7272 | |||
| a5fb92db92 | |||
| 81e244f230 | |||
| 6a1b931340 | |||
| 8a21b01c1d | |||
| 96f46c2b59 | |||
| ffe335c17e | |||
| 79b537c186 | |||
| a806785609 | |||
| 06ff60ca74 | |||
| b34013129e | |||
| f1a5b1d764 | |||
| d52980506c | |||
| 34bab40d3d | |||
| 747d06c7b4 | |||
| 41573b7b39 | |||
| d7e078db2e | |||
| 363a854428 | |||
| ad00099c9d | |||
| 6676a380e1 | |||
| bab13ff718 | |||
| 9707c5c276 | |||
| 48206d675a | |||
| f877c184bb | |||
| 59b360b285 | |||
| 1a09571788 | |||
| 2484a8d4d8 | |||
| 5e73ad35fa | |||
| 8503a622b0 | |||
| ab479300ea | |||
| 96fb847479 | |||
| 5484669333 | |||
| e366edbbea | |||
| e8ef25183d | |||
| c94c5283a7 | |||
| 77803c0b41 | |||
| b5bd4af56d | |||
| 0a28baad64 | |||
| 6a1cd1d1d1 | |||
| 25e72aa45e | |||
| 90f869fcdb | |||
| 72a2cb804a | |||
| 752fb9e719 | |||
| ac745e1434 | |||
| cbb4480d1e | |||
| a410370f45 | |||
| b8c4333d4e | |||
| 7e165f6c17 | |||
| c9ae7bfebd | |||
| 1d5b8cd8f6 | |||
| d41c8ddcae | |||
| 3d4b143c74 | |||
| 5892525593 | |||
| ff0e794b8c | |||
| 5f42afa31a | |||
| 2a56bee611 | |||
| 685b7cb1f8 | |||
| b0df00c0a3 | |||
| 30917d1b0f | |||
| 3848c4cf89 | |||
| 753b6f6f76 | |||
| d6739dc63e | |||
| 4e14fb0501 | |||
| 397ad9f823 | |||
| d2218c58c1 | |||
| 7627c2a0f7 | |||
| 69a7ff6813 | |||
| 133def9722 | |||
| 1b3afaabd0 | |||
| 9cb690378b | |||
| dd4b7254d9 | |||
| 394506e40d | |||
| 6399cab7c4 | |||
| ba1a559a4b | |||
| 41d7e30df5 | |||
| 94139c9f79 | |||
| 5d4f8fb314 | |||
| beae239007 | |||
| f20c84eb6e | |||
| 588482707a | |||
| 2ebb283119 | |||
| 3bfa300fad | |||
| 8ca30f65f3 | |||
| fa6a9fbbf8 | |||
| 8af25e0600 | |||
| 944b98c4b4 | |||
| 8254a61389 | |||
| d016c433ff | |||
| 5e0b4303fd | |||
| dc1ba689c4 | |||
| fc96331c1c | |||
| 6cc1805c48 | |||
| fa05a63adf | |||
| de26068faf | |||
| 273fef3526 | |||
| 66b24c90e8 | |||
| 07e20b0f3d | |||
| 133dd93dda | |||
| 4bbd54a3b0 | |||
| 49714129b1 | |||
| 6fd2ec4a48 | |||
| f9f510fca1 | |||
| d65d474462 | |||
| d8db1a4136 | |||
| 953edfc174 | |||
| 580c707369 | |||
| b56973e7b3 | |||
| 17ad5aed6e | |||
| e84185febb | |||
| ec9a4f2d90 | |||
| c0088b04ce | |||
| ae3347fc70 | |||
| ffa342d69e | |||
| 7676a7000d | |||
| 38ea6c307f | |||
| 2fc3140d26 | |||
| 97efe6ba99 | |||
| 27cca38398 | |||
| ece21c126f | |||
| d035a7e01c | |||
| 859503f518 | |||
| 3cce1077b8 | |||
| da9a50829e | |||
| 67f8337a7d | |||
| 79df599882 | |||
| 5ca25ac55d | |||
| a2eb174b68 | |||
| aedfa6cfda | |||
| 5b403f7342 | |||
| 2f9b972157 | |||
| a7e49ed0c3 | |||
| eafae6a2f7 | |||
| 93af46ca6d | |||
| a71586b100 | |||
| 0f2a829405 | |||
| f4a40ea1bd | |||
| a90cc7f0d3 | |||
| 2b166bddd3 | |||
| 81312d979e | |||
| 37c10f6887 | |||
| 8bce18d142 | |||
| d0d854c88c | |||
| 6487568646 | |||
| 23f8f1a75c | |||
| eacd1d09b6 | |||
| 9d903f6f15 | |||
| 44eeeb89f1 | |||
| f4d8a89336 | |||
| af6f9706fb | |||
| ac2671cdf0 | |||
| 67aec8be03 | |||
| b23b292749 | |||
| e38a3c4b50 | |||
| 99e2039e1e | |||
| 96a2c10548 | |||
| 7392b24c0b | |||
| b9a919ca55 | |||
| 158ea422e9 | |||
| 72dffe5822 | |||
| 13d2e70a43 | |||
| 33673d612e | |||
| 6aeac3ddb5 | |||
| 75ca800dce | |||
| cae74e8ebd | |||
| ca3f544fc6 | |||
| 2ace7ce319 | |||
| 659f0a1fa6 | |||
| 8e26911fd4 | |||
| 7a2267eb7b | |||
| 3127d281fa | |||
| fdac054187 | |||
| fc2e899cdc | |||
| 2b1f9198a5 | |||
| eb8b0ee57d | |||
| 23638ecc80 | |||
| 1e2423f7a1 | |||
| c245903066 | |||
| 927554a56c | |||
| 0f43ca96b1 | |||
| 42db8237e7 | |||
| f165976c8b | |||
| 75f840c6f8 | |||
| 537eeebc04 | |||
| 5dc30f430e | |||
| f5de0125a4 | |||
| 026ddac8a5 | |||
| 05b900ec4c | |||
| 7453dab3e2 | |||
| 2c7f5b479f | |||
| a7d47ca728 | |||
| dc4d3565b9 | |||
| 6f8d2b0949 | |||
| 3774497c09 | |||
| cfc7809327 | |||
| fcfdb11b1e | |||
| eccedb9a45 | |||
| 71d1c32114 | |||
| 73e3d20f0b | |||
| 4e9532d51e | |||
| 4754ac264b | |||
| 4028f69875 | |||
| 521881fc44 | |||
| fa8958af57 | |||
| e7d9f8223e | |||
| 7efbf57fd2 | |||
| 68fe880d77 | |||
| 42ba56f9fc | |||
| 5602fab50f | |||
| 2a87764019 | |||
| 50f0b234d0 | |||
| 3a11633ad9 | |||
| b1bb8191f0 | |||
| c89e39c4e6 | |||
| 63e9ace797 | |||
| 5f9a985fca | |||
| e6cf8dbba1 | |||
| 8f14c87f5f | |||
| f262ebf0a3 | |||
| 1ab94e4659 | |||
| 00fc75342e | |||
| 6d69c29aa3 | |||
| a76bd2f564 | |||
| f2b088a4b3 | |||
| 08670be579 | |||
| 91f61b04a7 | |||
| bc16c5df9c | |||
| 5bfd9c4ce3 | |||
| a902152600 | |||
| 72ae968746 | |||
| a73a7a0923 | |||
| d08601e2fd | |||
| 7bba146e0b | |||
| 581650d68f | |||
| 43e93d9e0c | |||
| 784aa84ff0 | |||
| 3b17785566 | |||
| ed48ab74d6 | |||
| 7e9f1b044a | |||
| bd449293a1 | |||
| cfa31bcc4d | |||
| 8519ca0b58 | |||
| 29ce61abc8 | |||
| 3ec758076c | |||
| ff34c0966b | |||
| da82076632 | |||
| 4f74d65554 | |||
| ea458c95c0 | |||
| 4e865733f8 | |||
| 002b4a7c27 | |||
| 9d4745fd14 | |||
| 598bce5567 | |||
| 51fbf37693 | |||
| f127f6dde7 | |||
| 03a844b4ce | |||
| 888fa440f5 | |||
| 8456625dfe | |||
| 77e8e1b480 | |||
| 12f32d9adb | |||
| 434270bdbb | |||
| aee587d5be | |||
| 7658cd27f3 | |||
| 9028af6636 | |||
| 2d8f3f0b62 | |||
| 65c92caf14 | |||
| f274b31c74 | |||
| a6e27f1b3c | |||
| e8ffdd08b7 | |||
| ae3611b69a | |||
| 6ca02a5e31 | |||
| 3d4a0fb749 | |||
| c6b8487bb9 | |||
| e2be8da456 | |||
| fabb23c313 | |||
| 0df6b9c5a9 | |||
| 74045121f7 | |||
| 97dcdcd5ff | |||
| 54513b8dd5 | |||
| 31e1fb7470 | |||
| 72f15692cd | |||
| f88da7dfbc | |||
| c522744752 | |||
| af31d06612 | |||
| 1b09ff98ce | |||
| efebe46537 | |||
| f564c3147f | |||
| 7bbd0d0fcf | |||
| c282481c86 | |||
| bb0de655ed | |||
| 5a007d4ef3 | |||
| f63549e063 | |||
| 9951c0a200 | |||
| 7b56f5065f | |||
| 6ada0fb36f | |||
| 0ab3b1d6f4 | |||
| e1375ae827 | |||
| ca0352ef61 | |||
| 86465503b5 | |||
| b2f1d005cd | |||
| f87802ebdf | |||
| b551f35337 | |||
| 08cb252f12 | |||
| f6e44d4a34 | |||
| b069b8854d | |||
| 2ba8765e77 | |||
| 7fb7e52ab3 | |||
| 973d06b02a | |||
| 44e670f87d | |||
| 3a7b81c6d0 | |||
| 1578625fb6 | |||
| d834b00353 | |||
| c8bbe83265 | |||
| 449f4fde39 | |||
| 75c275dd31 | |||
| dc56206c87 | |||
| f1df4fe92d | |||
| 49b6d429ad | |||
| 2315daac2c | |||
| 21b3e1340d | |||
| 99df194302 | |||
| b643649848 | |||
| 5066ef7932 | |||
| ca7428c06d | |||
| 8cb8395076 | |||
| e59a5d1b8e | |||
| 926a147e25 | |||
| aaf4310d63 | |||
| 6915c658ff | |||
| afcb915d09 | |||
| 5418403887 | |||
| 4a309daf48 | |||
| 7b06951119 | |||
| b619e2d178 | |||
| 05646cfdf3 | |||
| 1ea18455f9 | |||
| 39dab5b134 | |||
| 2608174dfa | |||
| 93368cc4ac | |||
| 273fc96e10 | |||
| 0381dbb4fa |
+3
-3
@@ -1,3 +1,3 @@
|
||||
*.xaml linguist-language=csharp
|
||||
*.cs linguist-language=csharp
|
||||
*.py linguist-language=python
|
||||
*.py linguist-language=python
|
||||
*.xaml linguist-language=csharp
|
||||
*.cs linguist-language=csharp
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
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: 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
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
|
||||
custom: ['https://www.buymeacoffee.com/yaronzz']
|
||||
@@ -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
|
||||
@@ -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**
|
||||
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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**
|
||||
@@ -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
|
||||
@@ -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/*
|
||||
|
||||
|
||||
|
||||
+180
-66
@@ -1,66 +1,180 @@
|
||||
/Dll/AIGS.vshost.exe
|
||||
/Dll/AIGS.vshost.exe.manifest
|
||||
/Dll/AIGS.pdb
|
||||
/TIDALDL-PY/tidal-dl.ini
|
||||
/TIDALDL-PY/tidal_dl.egg-info
|
||||
/TIDALDL-PY/build
|
||||
/TIDALDL-PY/dist
|
||||
/TIDALDL-PY/__main__.spec
|
||||
/TIDALDL-PY/tidal_dl/__pycache__
|
||||
/TIDALDL-PY/exe/Track
|
||||
/TIDALDL-PY/exe/Video
|
||||
/TIDALDL-PY/exe/tidal-dl.ini
|
||||
/TIDALDL-PY/exe/Album
|
||||
/TIDALDL-PY/exe/Playlist
|
||||
/TIDALDL-UI/obj
|
||||
/TIDALDL-UI/bin/Release
|
||||
/TIDALDL-UI/bin/Debug/Tidal-Media-Downloader.pdb
|
||||
/TIDALDL-UI/bin/Debug/AIGS.pdb
|
||||
/TIDALDL-UI/bin/Debug/MaterialDesignThemes.Wpf.pdb
|
||||
/TIDALDL-UI/bin/Debug/MaterialDesignThemes.Wpf.xml
|
||||
/TIDALDL-UI/bin/Debug/Tidal-dl.ini
|
||||
/TIDALDL-UI/bin/Debug/Tidal-Media-Downloader.exe.config
|
||||
/TIDALDL-CMD-1
|
||||
/TIDALDL-UI-1
|
||||
/trunk
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/MaterialDesignThemes.Wpf.xml
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/policy.2.0.taglib-sharp.config
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/Stylet.xml
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-dl.ini
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-downloader.exe.config
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-downloader.pdb
|
||||
/TIDALDL-UI/TIDALDL-UI/obj
|
||||
/TIDALDL-UI/TIDALDL-UI.v12.suo
|
||||
/TIDALDL-UI/.vs
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-ui-dl.exe.config
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-ui-dl.pdb
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.application
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.exe.config
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.exe.manifest
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.pdb
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.vshost.application
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.vshost.exe
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.vshost.exe.config
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.vshost.exe.manifest
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/tidal-dl.ini
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/tidal-gui.application
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/tidal-gui.exe.config
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/tidal-gui.exe.manifest
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/tidal-gui.pdb
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/app.publish
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/MaterialDesignThemes.Wpf.xml
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/policy.2.0.taglib-sharp.config
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/Stylet.xml
|
||||
/TIDALDL-PY/.vscode
|
||||
/TIDALDL-UI/packages/Costura.Fody.3.3.0
|
||||
/TIDALDL-UI/packages/Fody.3.3.5
|
||||
/TIDALDL-UI/packages/MaterialDesignColors.1.1.3
|
||||
/TIDALDL-UI/packages/MaterialDesignThemes.2.5.1
|
||||
/TIDALDL-UI/packages/PropertyChanged.Fody.2.6.0
|
||||
/TIDALDL-UI/packages/Stylet.1.1.22
|
||||
/TIDALDL-UI/packages/Stylet.Start.1.1.22
|
||||
/TIDALDL-UI/packages/taglib.2.1.0.0
|
||||
/TIDALDL-UI/TIDALDL-UI/bin
|
||||
TIDALDL-PY/__pycache__/setup.cpython-37.pyc
|
||||
.gitignore
|
||||
.gitignore
|
||||
/Dll/AIGS.vshost.exe
|
||||
/Dll/AIGS.vshost.exe.manifest
|
||||
/Dll/AIGS.pdb
|
||||
/TIDALDL-PY/tidal-dl.ini
|
||||
/TIDALDL-PY/tidal_dl.egg-info
|
||||
/TIDALDL-PY/build
|
||||
/TIDALDL-PY/dist
|
||||
/TIDALDL-PY/__main__.spec
|
||||
/TIDALDL-PY/tidal_dl/__pycache__
|
||||
/TIDALDL-PY/exe/Track
|
||||
/TIDALDL-PY/exe/Video
|
||||
/TIDALDL-PY/exe/tidal-dl.ini
|
||||
/TIDALDL-PY/exe/Album
|
||||
/TIDALDL-PY/exe/Playlist
|
||||
/TIDALDL-UI/obj
|
||||
/TIDALDL-UI/bin/Release
|
||||
/TIDALDL-UI/bin/Debug/Tidal-Media-Downloader.pdb
|
||||
/TIDALDL-UI/bin/Debug/AIGS.pdb
|
||||
/TIDALDL-UI/bin/Debug/MaterialDesignThemes.Wpf.pdb
|
||||
/TIDALDL-UI/bin/Debug/MaterialDesignThemes.Wpf.xml
|
||||
/TIDALDL-UI/bin/Debug/Tidal-dl.ini
|
||||
/TIDALDL-UI/bin/Debug/Tidal-Media-Downloader.exe.config
|
||||
/TIDALDL-CMD-1
|
||||
/TIDALDL-UI-1
|
||||
/trunk
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/MaterialDesignThemes.Wpf.xml
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/policy.2.0.taglib-sharp.config
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/Stylet.xml
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-dl.ini
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-downloader.exe.config
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-downloader.pdb
|
||||
/TIDALDL-UI/TIDALDL-UI/obj
|
||||
/TIDALDL-UI/TIDALDL-UI.v12.suo
|
||||
/TIDALDL-UI/.vs
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-ui-dl.exe.config
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-ui-dl.pdb
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.application
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.exe.config
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.exe.manifest
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.pdb
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.vshost.application
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.vshost.exe
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.vshost.exe.config
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Debug/tidal-gui.vshost.exe.manifest
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/tidal-dl.ini
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/tidal-gui.application
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/tidal-gui.exe.config
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/tidal-gui.exe.manifest
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/tidal-gui.pdb
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/app.publish
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/MaterialDesignThemes.Wpf.xml
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/policy.2.0.taglib-sharp.config
|
||||
/TIDALDL-UI/TIDALDL-UI/bin/Release/Stylet.xml
|
||||
/TIDALDL-PY/.vscode
|
||||
/TIDALDL-UI/packages/Costura.Fody.3.3.0
|
||||
/TIDALDL-UI/packages/Fody.3.3.5
|
||||
/TIDALDL-UI/packages/MaterialDesignColors.1.1.3
|
||||
/TIDALDL-UI/packages/MaterialDesignThemes.2.5.1
|
||||
/TIDALDL-UI/packages/PropertyChanged.Fody.2.6.0
|
||||
/TIDALDL-UI/packages/Stylet.1.1.22
|
||||
/TIDALDL-UI/packages/Stylet.Start.1.1.22
|
||||
/TIDALDL-UI/packages/taglib.2.1.0.0
|
||||
/TIDALDL-UI/TIDALDL-UI/bin
|
||||
TIDALDL-PY/__pycache__/setup.cpython-37.pyc
|
||||
.gitignore
|
||||
.gitignore
|
||||
/TIDALDL-PY/settings.json
|
||||
/TIDALDL-PY/usersettings.json
|
||||
/TIDALDL-PY/__init__.spec
|
||||
TIDALDL-PY/tidal_dl/lang/__pycache__/__init__.cpython-37.pyc
|
||||
TIDALDL-PY/tidal_dl/lang/__pycache__/arabic.cpython-37.pyc
|
||||
TIDALDL-PY/tidal_dl/lang/__pycache__/chinese.cpython-37.pyc
|
||||
TIDALDL-PY/tidal_dl/lang/__pycache__/czech.cpython-37.pyc
|
||||
TIDALDL-PY/tidal_dl/lang/__pycache__/english.cpython-37.pyc
|
||||
TIDALDL-PY/tidal_dl/lang/__pycache__/filipino.cpython-37.pyc
|
||||
TIDALDL-PY/tidal_dl/lang/__pycache__/italian.cpython-37.pyc
|
||||
TIDALDL-PY/tidal_dl/lang/__pycache__/language.cpython-37.pyc
|
||||
TIDALDL-PY/tidal_dl/lang/__pycache__/russian.cpython-37.pyc
|
||||
TIDALDL-PY/tidal_dl/lang/__pycache__/turkish.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/__init__.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/__main__.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/cmdHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/configHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/convertHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/ffmpegHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/fileHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/httpHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/logHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/m3u8Helper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/mathHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/netHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/pathHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/pipHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/progressHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/serverHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/stringHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/systemHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/tagHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/threadHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/updateHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/versionHelper.cpython-37.pyc
|
||||
TIDALDL-PY-原/build/__main__/aigpy-2020.7.3.0-py3.7.egg/aigpy/__pycache__/zipHelper.cpython-37.pyc
|
||||
/TIDALDL-PY-原
|
||||
/TIDALDL-UI-原
|
||||
/TIDALDL-PY/download
|
||||
TIDALDL-PY/tidal_dl/lang/__pycache__/croatian.cpython-37.pyc
|
||||
TIDALDL-PY/tidal_dl/lang/__pycache__/spanish.cpython-37.pyc
|
||||
TIDALDL-PY/tidal_dl_test.egg-info/dependency_links.txt
|
||||
TIDALDL-PY/tidal_dl_test.egg-info/entry_points.txt
|
||||
TIDALDL-PY/tidal_dl_test.egg-info/PKG-INFO
|
||||
TIDALDL-PY/tidal_dl_test.egg-info/requires.txt
|
||||
TIDALDL-PY/tidal_dl_test.egg-info/SOURCES.txt
|
||||
TIDALDL-PY/tidal_dl_test.egg-info/top_level.txt
|
||||
TIDALDL-PY/downloadd/Album/Capital Cities/[E] Solarize/01 - Space.flac.part
|
||||
TIDALDL-PY/downloadd/Album/Capital Cities/[E] Solarize/cover.jpg
|
||||
TIDALDL-PY/downloadd/Album/Capital Cities/[E] Solarize/01 - Space.flac.part
|
||||
TIDALDL-PY/downloadd/Album/Capital Cities/[E] Solarize/cover.jpg
|
||||
TIDALDL-PY/tidal_dl/lang/__pycache__/ukrainian.cpython-37.pyc
|
||||
/TIDALDL-PY/tidal_dl/lang/__pycache__
|
||||
/旧版备份
|
||||
/usersettings.json
|
||||
/settings.json
|
||||
/download
|
||||
download/Album/Ed Sheeran/÷ (Deluxe)/05 - Perfect.flac
|
||||
download/Album/Ed Sheeran/÷ (Deluxe)/cover.jpg
|
||||
download/Album/Ed Sheeran/÷ (Deluxe)/Tmp0/1.part
|
||||
download/Album/Ed Sheeran/÷ (Deluxe)/Tmp0/5.part
|
||||
download/Album/Ed Sheeran/÷ (Deluxe)/Tmp0/9.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/0.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/1.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/3.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/4.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/5.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/6.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/7.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/9.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/10.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/11.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/12.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/13.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/14.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/15.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/16.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/17.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/18.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/19.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/20.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/21.part
|
||||
download/Playlist/Boy Bands- K-Pop Kings/Tmp0/22.part
|
||||
/TIDALDL-GUI
|
||||
/.vscode/.env
|
||||
/.vscode/settings.json
|
||||
/TIDALDL-PY/test/track.json
|
||||
/TIDALDL-PY/test/video.json
|
||||
/__init__.spec
|
||||
/test.py
|
||||
/TIDALDL-GUI-CROSS/MANIFEST.in
|
||||
/TIDALDL-GUI-CROSS/__init__.spec
|
||||
/TIDALDL-GUI-CROSS/workspace.code-workspace
|
||||
/TIDALDL-GUI-CROSS/.idea
|
||||
/TIDALDL-GUI-CROSS/tidal_gui/__pycache__
|
||||
/TIDALDL-GUI-CROSS/tidal_gui/.tidal-dl.log
|
||||
.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
|
||||
|
||||
Vendored
+68
@@ -0,0 +1,68 @@
|
||||
{
|
||||
// 使用 IntelliSense 了解相关属性。
|
||||
// 悬停以查看现有属性的描述。
|
||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
|
||||
{
|
||||
"name": "Python: current",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${file}",
|
||||
"console": "integratedTerminal",
|
||||
// "python": "python3",
|
||||
"env": {
|
||||
"PYTHONPATH": "${workspaceRoot}/TIDALDL-PY/tidal_dl/"
|
||||
},
|
||||
"justMyCode": false
|
||||
},
|
||||
{
|
||||
"name": "Python: common line",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/TIDALDL-PY/tidal_dl/__init__.py",
|
||||
"console": "integratedTerminal",
|
||||
// "python": "python3",
|
||||
"env": {
|
||||
"PYTHONPATH": "${workspaceRoot}/TIDALDL-PY/tidal_dl/"
|
||||
},
|
||||
"args": [
|
||||
"--link",
|
||||
"https://tidal.com/browse/track/70973230",
|
||||
"-o",
|
||||
"e:\\test",
|
||||
"-q",
|
||||
"0",
|
||||
"-g"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Python: main",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/TIDALDL-PY/tidal_dl/__init__.py",
|
||||
"console": "integratedTerminal",
|
||||
// "python": "python3",
|
||||
"env": {
|
||||
"PYTHONPATH": "${workspaceRoot}/TIDALDL-PY/tidal_dl/"
|
||||
},
|
||||
"justMyCode": false
|
||||
|
||||
},
|
||||
{
|
||||
"name": "Python: gui",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/TIDALDL-PY/tidal_gui/__init__.py",
|
||||
"console": "integratedTerminal",
|
||||
// "python": "python3",
|
||||
"env": {
|
||||
"PYTHONPATH": "${workspaceRoot}/TIDALDL-PY/tidal_dl/"
|
||||
},
|
||||
"justMyCode": false
|
||||
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"token":"MbjR4DLXz1ghC4rV",
|
||||
"token_phone": "pl4Vc0hemlAXD0mN",
|
||||
"//token_phone" : "hZ9wuySZCmpLLiui"
|
||||
}
|
||||
|
||||
@@ -1,201 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
@@ -1,80 +1,156 @@
|
||||
<div align="center">
|
||||
<h1>Tidal-Media-Downloader</h1>
|
||||
<a href="https://github.com/yaronzz/Tidal-Media-Downloader/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/github/license/yaronzz/Tidal-Media-Downloader.svg?style=flat-square" alt="">
|
||||
</a>
|
||||
<a href="https://github.com/yaronzz/Tidal-Media-Downloader/releases">
|
||||
<img src="https://img.shields.io/github/v/release/yaronzz/Tidal-Media-Downloader.svg?style=flat-square" alt="">
|
||||
</a>
|
||||
<a href="https://www.python.org/">
|
||||
<img src="https://img.shields.io/github/issues/yaronzz/Tidal-Media-Downloader.svg?style=flat-square" alt="">
|
||||
</a>
|
||||
<a href="https://github.com/yaronzz/Tidal-Media-Downloader">
|
||||
<img src="https://img.shields.io/github/downloads/yaronzz/Tidal-Media-Downloader/total?label=tidal-gui%20download" alt="">
|
||||
</a>
|
||||
<a href="https://pypi.org/project/tidal-dl/">
|
||||
<img src="https://img.shields.io/pypi/dm/tidal-dl?label=tidal-dl%20download" 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.
|
||||
<br>
|
||||
<a href="https://github.com/yaronzz/Tidal-Media-Downloader/releases">Download</a> |
|
||||
<a href="https://yaronzz.top/post/tidal_dl_installation/">Documentation</a> |
|
||||
<a href="https://yaronzz.top/post/tidal_dl_installation_chn/">中文文档</a> |
|
||||
<a href="https://t.me/Tidal_Media_Downloader">Channel</a>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
----
|
||||
<a href="https://www.buymeacoffee.com/yaronzz" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" style="height: 51px !important;width: 217px !important;" ></a>
|
||||
|
||||
### **Installation**
|
||||
- Windows: [tidal-gui.exe](https://github.com/yaronzz/Tidal-Media-Downloader/releases)
|
||||
|
||||
- Windows\Linux\MacOs:
|
||||
``` python
|
||||
root:~# pip3 install tidal-dl --upgrade
|
||||
root:~# tidal-dl
|
||||
```
|
||||
|
||||
- Android: [Install](https://yaronzz.top/post/tidal_dl_installation/#Install)
|
||||
|
||||
- Detailed description: [Documentation](https://yaronzz.top/post/tidal_dl_installation/)
|
||||
|
||||
### **Requirement**
|
||||
- [FFmpeg](http://ffmpeg.org/) : Convert video
|
||||
|
||||
### **Telegram**
|
||||
- [Group](https://t.me/tidal_group) : Feed back
|
||||
- [Channel](https://t.me/Tidal_Media_Downloader) : Notify the new version
|
||||
|
||||
### **Features**
|
||||
1. Download single video\track\album\playlist
|
||||
2. Download favorite tracks\artist-albums
|
||||
3. Add metadate
|
||||
4. Multiple downloads
|
||||
5. Selectable video resolution and track quality
|
||||
|
||||
### **Screenshots**
|
||||

|
||||

|
||||
|
||||
### **Libraries and reference**
|
||||
- [AIGS](https://github.com/yaronzz/AIGS)
|
||||
- [AIGPY](https://github.com/yaronzz/AIGPY)
|
||||
- [Stylet](https://github.com/canton7/Stylet)
|
||||
- [PropertyChanged.Fody](https://github.com/Fody/PropertyChanged)
|
||||
- [MaterialDesignInXamlToolkit](https://github.com/ButchersBoy/MaterialDesignInXamlToolkit)
|
||||
- [Taglib-sharp](https://github.com/mono/taglib-sharp)
|
||||
- [python-tidal](https://github.com/tamland/python-tidal)
|
||||
- [RedSea](https://github.com/redsudo/RedSea)
|
||||
|
||||
### **Support**
|
||||
If you really like my projects and want to support me, you can star this project.
|
||||
|
||||
### **Disclaimer**
|
||||
- Private use only.
|
||||
- Need a Tidal-HIFI subscription.
|
||||
- You should not use this method to distribute or pirate music.
|
||||
- It may be illegal to use this in your country, so be informed.
|
||||
<br>
|
||||
<a href="https://github.com/yaronzz/Tidal-Media-Downloader-PRO">[GUI-REPOSITORY]</a>
|
||||
<br>
|
||||
|
||||

|
||||
|
||||
|
||||
<div align="center">
|
||||
<h1>Tidal-Media-Downloader</h1>
|
||||
<a href="https://github.com/yaronzz/Tidal-Media-Downloader/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/github/license/yaronzz/Tidal-Media-Downloader.svg?style=flat-square" alt="">
|
||||
</a>
|
||||
<a href="https://github.com/yaronzz/Tidal-Media-Downloader/releases">
|
||||
<img src="https://img.shields.io/github/v/release/yaronzz/Tidal-Media-Downloader.svg?style=flat-square" alt="">
|
||||
</a>
|
||||
<a href="https://www.python.org/">
|
||||
<img src="https://img.shields.io/github/issues/yaronzz/Tidal-Media-Downloader.svg?style=flat-square" alt="">
|
||||
</a>
|
||||
<a href="https://github.com/yaronzz/Tidal-Media-Downloader">
|
||||
<img src="https://img.shields.io/github/downloads/yaronzz/Tidal-Media-Downloader/total?label=tidal-gui%20download" alt="">
|
||||
</a>
|
||||
<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://doc.yaronzz.com/post/tidal_dl_installation/">Documentation</a> |
|
||||
<a href="https://doc.yaronzz.com/post/tidal_dl_installation_chn/">中文文档</a> |
|
||||
<br>
|
||||
</p>
|
||||
|
||||
## 📺 Installation
|
||||
|
||||
```shell
|
||||
pip3 install tidal-dl --upgrade
|
||||
```
|
||||
|
||||
| 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
|
||||
|
||||
- Add metadata to songs
|
||||
|
||||
- Selectable video resolution and track quality
|
||||
|
||||
## 💽 User Interface
|
||||
|
||||
<img src="https://i.loli.net/2020/08/19/gqW6zHI1SrKlomC.png" alt="image" style="zoom: 50%;" />
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Settings - Possible Tags
|
||||
|
||||
### Album
|
||||
|
||||
| Tag | Example value |
|
||||
| ----------------- | ------------------------------------ |
|
||||
| {ArtistName} | The Beatles |
|
||||
| {AlbumArtistName} | The Beatles |
|
||||
| {Flag} | M/A/E (Master/Dolby Atmos/Explicit) |
|
||||
| {AlbumID} | 55163243 |
|
||||
| {AlbumYear} | 1963 |
|
||||
| {AlbumTitle} | Please Please Me (Remastered) |
|
||||
| {AudioQuality} | LOSSLESS |
|
||||
| {DurationSeconds} | 1919 |
|
||||
| {Duration} | 31:59 |
|
||||
| {NumberOfTracks} | 14 |
|
||||
| {NumberOfVideos} | 0 |
|
||||
| {NumberOfVolumes} | 1 |
|
||||
| {ReleaseDate} | 1963-03-22 |
|
||||
| {RecordType} | ALBUM |
|
||||
| {None} | |
|
||||
|
||||
### Track
|
||||
|
||||
| Tag | Example Value |
|
||||
| ----------------- | ------------------------------------------ |
|
||||
| {TrackNumber} | 01 |
|
||||
| {ArtistName} | The Beatles |
|
||||
| {ArtistsName} | The Beatles |
|
||||
| {TrackTitle} | I Saw Her Standing There (Remastered 2009) |
|
||||
| {ExplicitFlag} | (*Explicit*) |
|
||||
| {AlbumYear} | 1963 |
|
||||
| {AlbumTitle} | Please Please Me (Remastered) |
|
||||
| {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
|
||||
|
||||
If you really like my projects and want to support me, you can buy me a coffee and star this project.
|
||||
|
||||
<a href="https://www.buymeacoffee.com/yaronzz" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/arial-orange.png" alt="Buy Me A Coffee" style="height: 51px !important;width: 217px !important;" ></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
|
||||
|
||||
- [aigpy](https://github.com/yaronzz/AIGPY)
|
||||
- [python-tidal](https://github.com/tamland/python-tidal)
|
||||
- [redsea](https://github.com/redsudo/RedSea)
|
||||
- [tidal-wiki](https://github.com/Fokka-Engineering/TIDAL/wiki)
|
||||
|
||||
## 📜 Disclaimer
|
||||
- Private use only.
|
||||
- Need a Tidal-HIFI subscription.
|
||||
- You should not use this method to distribute or pirate music.
|
||||
- It may be illegal to use this in your country, so be informed.
|
||||
|
||||
## Developing
|
||||
|
||||
```shell
|
||||
pip3 uninstall tidal-dl
|
||||
pip3 install -r requirements.txt --user
|
||||
python3 setup.py install
|
||||
```
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
[album]
|
||||
90521280
|
||||
|
||||
[artist]
|
||||
10954264
|
||||
|
||||
[track]
|
||||
66214149
|
||||
90521281
|
||||
|
||||
[video]
|
||||
92418079
|
||||
|
||||
[url]
|
||||
https://tidal.com/album/71121869
|
||||
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
include tidal_gui/resource/themeDefault.qss
|
||||
include tidal_gui/resource/svg/*.svg
|
||||
include tidal_gui/resource/svg/*/*.svg
|
||||
@@ -1,6 +0,0 @@
|
||||
brew install python3
|
||||
curl -O http://python-distribute.org/distribute_setup.py
|
||||
python3 distribute_setup.py
|
||||
curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py
|
||||
python3 get-pip.py
|
||||
pip3 install --upgrade tidal-dl
|
||||
@@ -1,6 +1,12 @@
|
||||
aigpy==2020.5.4.0
|
||||
requests==2.21.0
|
||||
ffmpeg==1.4
|
||||
futures
|
||||
pycryptodome==3.7.0
|
||||
pydub==0.23.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
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
from setuptools import setup, find_packages
|
||||
setup(
|
||||
name = 'tidal-gui',
|
||||
version = '2022.01.18.3',
|
||||
license = "Apache2",
|
||||
description = "Tidal Music Downloader-GUI.",
|
||||
|
||||
author = 'YaronH',
|
||||
author_email = "yaronhuang@foxmail.com",
|
||||
|
||||
packages=find_packages(exclude=['tidal_dl*']),
|
||||
include_package_data = True,
|
||||
platforms = "any",
|
||||
install_requires=["tidal-dl"],
|
||||
entry_points={'console_scripts': [ 'tidal-gui = tidal_gui:main', ]}
|
||||
)
|
||||
+23
-16
@@ -1,16 +1,23 @@
|
||||
from setuptools import setup, find_packages
|
||||
setup(
|
||||
name = 'tidal-dl',
|
||||
version="2020.5.19.0",
|
||||
license="Apache2",
|
||||
description = "Tidal Music Downloader.",
|
||||
|
||||
author = 'YaronH',
|
||||
author_email = "yaronhuang@qq.com",
|
||||
|
||||
packages = find_packages(),
|
||||
include_package_data = True,
|
||||
platforms = "any",
|
||||
install_requires=["aigpy>=2020.5.4.0", "requests", "ffmpeg", "pycryptodome", "pydub", ],
|
||||
entry_points={'console_scripts': [ 'tidal-dl = tidal_dl:main', ]}
|
||||
)
|
||||
from setuptools import setup, find_packages
|
||||
from tidal_dl.printf import VERSION
|
||||
|
||||
setup(
|
||||
name='tidal-dl',
|
||||
version=VERSION,
|
||||
license="Apache2",
|
||||
description="Tidal Music Downloader.",
|
||||
|
||||
author='YaronH',
|
||||
author_email="yaronhuang@foxmail.com",
|
||||
|
||||
packages=find_packages(exclude=['tidal_gui*']),
|
||||
include_package_data=False,
|
||||
platforms="any",
|
||||
install_requires=["aigpy>=2022.7.8.1",
|
||||
"requests>=2.22.0",
|
||||
"pycryptodome",
|
||||
"pydub",
|
||||
"prettytable",
|
||||
"lxml"],
|
||||
entry_points={'console_scripts': ['tidal-dl = tidal_dl:main', ]}
|
||||
)
|
||||
|
||||
+147
-279
@@ -1,294 +1,162 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#!/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 os
|
||||
import time
|
||||
import getopt
|
||||
import aigpy
|
||||
|
||||
from aigpy import pipHelper
|
||||
from aigpy import pathHelper
|
||||
from aigpy.cmdHelper import myinput, myinputInt
|
||||
from events import *
|
||||
from settings import *
|
||||
from gui import startGui
|
||||
from printf import Printf
|
||||
|
||||
from tidal_dl.tidal import TidalConfig
|
||||
from tidal_dl.tidal import TidalAccount, TidalToken
|
||||
from tidal_dl.download import Download
|
||||
from tidal_dl.printhelper import printMenu, printChoice2, printErr, printWarning, LOG
|
||||
|
||||
TIDAL_DL_VERSION = "2020.5.19.0"
|
||||
TIDAL_TOKEN = TidalToken()
|
||||
|
||||
def logInByTime():
|
||||
cf = TidalConfig()
|
||||
def mainCommand():
|
||||
try:
|
||||
Lasttime = float(cf.lastlogintime)
|
||||
Lastlocaltime = time.localtime(Lasttime)
|
||||
except:
|
||||
Lastlocaltime = None
|
||||
|
||||
Curtime = time.time()
|
||||
Curlocaltime = time.localtime(Curtime)
|
||||
if Lastlocaltime is not None:
|
||||
if Curlocaltime.tm_mon == Lastlocaltime.tm_mon and Curlocaltime.tm_mday == Lastlocaltime.tm_mday and Curlocaltime.tm_hour < Lastlocaltime.tm_hour + 3:
|
||||
return
|
||||
|
||||
if logIn(cf.username, cf.password) == False:
|
||||
while logIn("", "") == False:
|
||||
pass
|
||||
|
||||
def logIn(username="", password=""):
|
||||
if username == "" or password == "":
|
||||
print("----------------LogIn------------------")
|
||||
username = myinput("username:")
|
||||
password = myinput("password:")
|
||||
account = TidalAccount(username, password, TIDAL_TOKEN)
|
||||
account2 = TidalAccount(username, password, TIDAL_TOKEN, True)
|
||||
# if account.errmsg != "":
|
||||
# printErr(0, account.errmsg)
|
||||
# return False
|
||||
# if account2.errmsg != "":
|
||||
# printErr(0, account2.errmsg)
|
||||
# return False
|
||||
if account.errmsg != "" and account2.errmsg != "":
|
||||
printErr(0, account.errmsg)
|
||||
return False
|
||||
elif account.errmsg != "":
|
||||
account = account2
|
||||
elif account2.errmsg != "":
|
||||
account2 = account
|
||||
|
||||
cf = TidalConfig()
|
||||
cf.set_account(username, password, account.session_id, account.country_code, account.user_id, account2.session_id)
|
||||
|
||||
Curtime = time.time()
|
||||
cf.set_lastlogintime(str(Curtime))
|
||||
return True
|
||||
|
||||
|
||||
def showConfig():
|
||||
cf = TidalConfig()
|
||||
print("----------------Config------------------")
|
||||
print("Username : " + cf.username)
|
||||
print("Output directory : " + cf.outputdir)
|
||||
print("SessionID : " + cf.sessionid)
|
||||
print("Country Code : " + cf.countrycode)
|
||||
print("Sound Quality : " + cf.quality)
|
||||
print("Video Resolution : " + cf.resolution)
|
||||
print("Download Threads : " + cf.threadnum)
|
||||
print("Only M4a : " + cf.onlym4a)
|
||||
print("Show download progress : " + cf.showprogress + "(enable when threadnum=1)")
|
||||
print("Use hyphens : " + cf.addhyphen + "(between number and title)")
|
||||
print("Add year : " + cf.addyear + "(in album title)")
|
||||
print("Add explicit tag : " + cf.addexplicit)
|
||||
print("Playlist songs in artist folders : " + cf.plfile2arfolder + "(organized with artist folder)")
|
||||
print("Include singles : " + cf.includesingle + "(download artist album)")
|
||||
print("Save covers : " + cf.savephoto)
|
||||
print("Version : " + TIDAL_DL_VERSION)
|
||||
myinput("Enter to return.")
|
||||
|
||||
|
||||
def setting():
|
||||
cf = TidalConfig()
|
||||
print("----------------Settings----------------")
|
||||
print("Output directory :\t" + cf.outputdir)
|
||||
print("Sound Quality :\t" + cf.quality)
|
||||
print("Video Resolution :\t" + cf.resolution)
|
||||
print("Download Threads :\t" + cf.threadnum)
|
||||
print("Only M4a :\t" + cf.onlym4a)
|
||||
print("Show download progress :\t" + cf.showprogress + "(enable when threadnum=1)")
|
||||
print("Use hyphens :\t" + cf.addhyphen + "(between number and title)")
|
||||
print("Add year :\t" + cf.addyear + "(in album title)")
|
||||
print("Add explicit tag :\t" + cf.addexplicit)
|
||||
print("Playlist songs in artist folders :\t" + cf.plfile2arfolder + "(organized with artist folder)")
|
||||
print("Include singles :\t" + cf.includesingle + "(download artist album)")
|
||||
print("Save covers : " + cf.savephoto)
|
||||
while True:
|
||||
outputdir = myinput("Output directory(Enter '0' Unchanged):".ljust(12))
|
||||
if outputdir == '0':
|
||||
outputdir = cf.outputdir
|
||||
break
|
||||
if os.path.isdir(outputdir) == False:
|
||||
printErr(0, "Path is Err!")
|
||||
continue
|
||||
break
|
||||
while True:
|
||||
index = myinputInt("Download Quality(0-LOW,1-HIGH,2-LOSSLESS,3-HI_RES):".ljust(12), 999)
|
||||
if index > 3 or index < 0:
|
||||
printErr(0, "Quality Err!")
|
||||
continue
|
||||
if index == 0:
|
||||
quality = 'LOW'
|
||||
if index == 1:
|
||||
quality = 'HIGH'
|
||||
if index == 2:
|
||||
quality = 'LOSSLESS'
|
||||
if index == 3:
|
||||
quality = 'HI_RES'
|
||||
break
|
||||
while True:
|
||||
index = myinputInt("Video resolution(0-1080,1-720,2-480,3-360,4-240):".ljust(12), 99)
|
||||
if index > 4 or index < 0:
|
||||
printErr(0, "Resolution Err")
|
||||
continue
|
||||
if index == 0:
|
||||
resolution = '1080'
|
||||
if index == 1:
|
||||
resolution = '720'
|
||||
if index == 2:
|
||||
resolution = '480'
|
||||
if index == 3:
|
||||
resolution = '360'
|
||||
if index == 4:
|
||||
resolution = '240'
|
||||
break
|
||||
while True:
|
||||
threadnum = myinput("Number of download threads:".ljust(12))
|
||||
if cf.valid_threadnum(threadnum) == False:
|
||||
printErr(0, "ThreadNum Err")
|
||||
continue
|
||||
break
|
||||
|
||||
status = myinputInt("Convert Mp4 to M4a(0-No, 1-Yes):".ljust(12), 0)
|
||||
status2 = myinputInt("Show download progress (only available on single thread)(0-No, 1-Yes):".ljust(12), 0)
|
||||
status3 = myinputInt("Use hyphens instead of spaces in file names(0-No, 1-Yes):".ljust(12), 0)
|
||||
|
||||
while True:
|
||||
index = myinputInt("Add year to album folder names(0-No, 1-Before, 2-After):".ljust(12), 99)
|
||||
if index > 2 or index < 0:
|
||||
printErr(0, "Addyear input Err")
|
||||
continue
|
||||
if index == 0:
|
||||
addyear = 'No'
|
||||
if index == 1:
|
||||
addyear = 'Before'
|
||||
if index == 2:
|
||||
addyear = 'After'
|
||||
break
|
||||
|
||||
status5 = myinputInt("Download playlist songs in artist folder structure? (0-No,1-Yes):".ljust(12), 0)
|
||||
status6 = myinputInt("Add explicit tag to file names(0-No, 1-Yes):".ljust(12), 0)
|
||||
status7 = myinputInt("Include singles and EPs when downloading an artist's albums (0-No, 1-Yes):".ljust(12), 0)
|
||||
status8 = myinputInt("Save covers(0-No, 1-Yes):".ljust(12), 0)
|
||||
|
||||
cf.set_outputdir(outputdir)
|
||||
cf.set_quality(quality)
|
||||
cf.set_resolution(resolution)
|
||||
cf.set_threadnum(threadnum)
|
||||
cf.set_onlym4a(status)
|
||||
cf.set_showprogress(status2)
|
||||
cf.set_addhyphen(status3)
|
||||
cf.set_addyear(addyear)
|
||||
cf.set_plfile2arfolder(status5)
|
||||
cf.set_addexplicit(status6)
|
||||
cf.set_includesingle(status7)
|
||||
cf.set_savephoto(status8)
|
||||
|
||||
pathHelper.mkdirs(outputdir + "/Album/")
|
||||
pathHelper.mkdirs(outputdir + "/Playlist/")
|
||||
pathHelper.mkdirs(outputdir + "/Video/")
|
||||
pathHelper.mkdirs(outputdir + "/Favorite/")
|
||||
return
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
if byCommand() is True:
|
||||
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
|
||||
|
||||
print(LOG)
|
||||
cf = TidalConfig()
|
||||
if logIn(cf.username, cf.password) == False:
|
||||
while logIn("", "") == False:
|
||||
pass
|
||||
link = None
|
||||
showGui = False
|
||||
|
||||
cf = TidalConfig()
|
||||
onlineVer = pipHelper.getLastVersion('tidal-dl')
|
||||
print("====================Tidal-dl========================")
|
||||
print("Output directory : " + cf.outputdir)
|
||||
print("Sound Quality : " + cf.quality)
|
||||
print("Video Resolution : " + cf.resolution)
|
||||
print("Download Threads : " + cf.threadnum)
|
||||
print("Only M4a : " + cf.onlym4a)
|
||||
print("Show download progress : " + cf.showprogress + "(enable when threadnum=1)")
|
||||
print("Use hyphens : " + cf.addhyphen + "(between number and title)")
|
||||
print("Add year : " + cf.addyear + "(in album title)")
|
||||
print("Add explicit tag : " + cf.addexplicit)
|
||||
print("Playlist songs in artist folders : " + cf.plfile2arfolder + "(organized with artist folder)")
|
||||
print("Include singles : " + cf.includesingle + "(download artist album)")
|
||||
print("Save covers : " + cf.savephoto)
|
||||
print("Current Version : " + TIDAL_DL_VERSION)
|
||||
if onlineVer != None:
|
||||
print("Latest Version : " + onlineVer)
|
||||
print("====================================================")
|
||||
|
||||
dl = Download(cf.threadnum)
|
||||
if not dl.ffmpeg.enable:
|
||||
printWarning(0, "Couldn't find ffmpeg!\n")
|
||||
while True:
|
||||
printMenu()
|
||||
strchoice, choice = printChoice2("Enter Choice:", 99)
|
||||
if choice == 0:
|
||||
for opt, val in opts:
|
||||
if opt in ('-h', '--help'):
|
||||
Printf.usage()
|
||||
return
|
||||
elif choice == 1:
|
||||
logIn()
|
||||
cf = TidalConfig()
|
||||
dl = Download(cf.threadnum)
|
||||
elif choice == 2:
|
||||
setting()
|
||||
cf = TidalConfig()
|
||||
dl = Download(cf.threadnum)
|
||||
elif choice == 3:
|
||||
dl.downloadAlbum()
|
||||
elif choice == 4:
|
||||
dl.downloadTrack()
|
||||
elif choice == 5:
|
||||
dl.downloadPlaylist()
|
||||
elif choice == 6:
|
||||
dl.downloadVideo()
|
||||
elif choice == 7:
|
||||
dl.downloadFavorite()
|
||||
elif choice == 8:
|
||||
dl.downloadArtistAlbum(cf.includesingle == "True")
|
||||
elif choice == 9:
|
||||
showConfig()
|
||||
#Hidden Code For Developer [200-299]
|
||||
elif choice == 200:
|
||||
dl.downloadArtistAlbum(False)
|
||||
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:
|
||||
dl.downloadUrl(strchoice)
|
||||
dl.downloadByFile(strchoice)
|
||||
start(choice)
|
||||
|
||||
def byCommand():
|
||||
try:
|
||||
if len(sys.argv) != 2:
|
||||
return False
|
||||
logInByTime()
|
||||
cf = TidalConfig()
|
||||
dl = Download(cf.threadnum)
|
||||
dl.downloadUrl(sys.argv[1])
|
||||
return True
|
||||
except Exception as e:
|
||||
return False
|
||||
return False
|
||||
|
||||
def debug():
|
||||
# cf = TidalConfig()
|
||||
# while logIn(cf.username, cf.password) == False:
|
||||
# pass
|
||||
# add tag Credits,Info song and full tag (discnumber,irsc,composer,arrenger,publisher,replayGain,releasedate)
|
||||
# https://api.tidal.com/v1/albums/71121869/tracks?token=wdgaB1CilGA-S_s2&countryCode=TH
|
||||
print('\nThis is the debug version!!\n')
|
||||
# os.system("pip install aigpy --upgrade")
|
||||
# trackid = 70973230
|
||||
dl = Download(1)
|
||||
dl.downloadTrack("90521281")
|
||||
# dl.downloadAlbum("120929182", True)
|
||||
# dl.tool.getPlaylist("36ea71a8-445e-41a4-82ab-6628c581535d")
|
||||
# ss = dl.tool.getPlaylistArtworkUrl("36ea71a8-445e-41a4-82ab-6628c581535d")
|
||||
# ss = dl.tool.getPlaylistArtworkUrl("36ea71a8-445e-41a4-82ab-6628c581535d",480)
|
||||
# dl.downloadVideo(57261945) #1hours
|
||||
# tidal.com/browse/track/125155002 dubi
|
||||
# dl.downloadVideo(84094460)
|
||||
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
|
||||
|
||||
# if __name__ == '__main__':
|
||||
# main(sys.argv)
|
||||
# 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
|
||||
|
||||
|
||||
__all__ = ['debug', 'main', 'tidal', 'download']
|
||||
if __name__ == '__main__':
|
||||
# test()
|
||||
main()
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
sys.path.append('./')
|
||||
import tidal_dl
|
||||
if __name__ == '__main__':
|
||||
# tidal_dl.debug()
|
||||
tidal_dl.main(sys.argv)
|
||||
@@ -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
|
||||
@@ -1,31 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import re
|
||||
from aigpy import fileHelper
|
||||
|
||||
class CheckTool(object):
|
||||
def __init__(self):
|
||||
self.paths = []
|
||||
|
||||
def isInErr(self, index, errIndex):
|
||||
for i in errIndex:
|
||||
if i == index:
|
||||
return True
|
||||
return False
|
||||
def clear(self):
|
||||
self.paths = []
|
||||
def addPath(self, path):
|
||||
self.paths.append(path)
|
||||
def checkPaths(self):
|
||||
index = 0
|
||||
flag = False
|
||||
errIndex = []
|
||||
for path in self.paths:
|
||||
if fileHelper.getFileSize(path) <= 0:
|
||||
errIndex.append(index)
|
||||
flag = True
|
||||
index = index + 1
|
||||
return flag, errIndex
|
||||
|
||||
|
||||
|
||||
@@ -1,63 +1,63 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : decryption.py
|
||||
@Time : 2019/02/27
|
||||
@Author : Yaron Huang
|
||||
@Version : 1.0
|
||||
@Contact : yaronhuang@qq.com
|
||||
@Desc : HIGH Quality Track Dectyption;File From Project 'RedSea'
|
||||
'''
|
||||
import base64
|
||||
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util import Counter
|
||||
|
||||
|
||||
def decrypt_security_token(security_token):
|
||||
'''
|
||||
Decrypts security token into key and nonce pair
|
||||
|
||||
security_token should match the securityToken value from the web response
|
||||
'''
|
||||
|
||||
# Do not change this
|
||||
master_key = 'UIlTTEMmmLfGowo/UC60x2H45W6MdGgTRfo/umg4754='
|
||||
|
||||
# Decode the base64 strings to ascii strings
|
||||
master_key = base64.b64decode(master_key)
|
||||
security_token = base64.b64decode(security_token)
|
||||
|
||||
# Get the IV from the first 16 bytes of the securityToken
|
||||
iv = security_token[:16]
|
||||
encrypted_st = security_token[16:]
|
||||
|
||||
# Initialize decryptor
|
||||
decryptor = AES.new(master_key, AES.MODE_CBC, iv)
|
||||
|
||||
# Decrypt the security token
|
||||
decrypted_st = decryptor.decrypt(encrypted_st)
|
||||
|
||||
# Get the audio stream decryption key and nonce from the decrypted security token
|
||||
key = decrypted_st[:16]
|
||||
nonce = decrypted_st[16:24]
|
||||
|
||||
return key, nonce
|
||||
|
||||
|
||||
def decrypt_file(efile, dfile, key, nonce):
|
||||
'''
|
||||
Decrypts an encrypted MQA file given the file, key and nonce
|
||||
'''
|
||||
|
||||
# Initialize counter and file decryptor
|
||||
counter = Counter.new(64, prefix=nonce, initial_value=0)
|
||||
decryptor = AES.new(key, AES.MODE_CTR, counter=counter)
|
||||
|
||||
# Open and decrypt
|
||||
with open(efile, 'rb') as eflac:
|
||||
flac = decryptor.decrypt(eflac.read())
|
||||
|
||||
# Replace with decrypted file
|
||||
with open(dfile, 'wb') as dflac:
|
||||
dflac.write(flac)
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : decryption.py
|
||||
@Time : 2019/02/27
|
||||
@Author : Yaron Huang
|
||||
@Version : 1.0
|
||||
@Contact : yaronhuang@qq.com
|
||||
@Desc : HIGH Quality Track Decryption;File From Project 'RedSea'
|
||||
'''
|
||||
import base64
|
||||
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util import Counter
|
||||
|
||||
|
||||
def decrypt_security_token(security_token):
|
||||
'''
|
||||
Decrypts security token into key and nonce pair
|
||||
|
||||
security_token should match the securityToken value from the web response
|
||||
'''
|
||||
|
||||
# Do not change this
|
||||
master_key = 'UIlTTEMmmLfGowo/UC60x2H45W6MdGgTRfo/umg4754='
|
||||
|
||||
# Decode the base64 strings to ascii strings
|
||||
master_key = base64.b64decode(master_key)
|
||||
security_token = base64.b64decode(security_token)
|
||||
|
||||
# Get the IV from the first 16 bytes of the securityToken
|
||||
iv = security_token[:16]
|
||||
encrypted_st = security_token[16:]
|
||||
|
||||
# Initialize decryptor
|
||||
decryptor = AES.new(master_key, AES.MODE_CBC, iv)
|
||||
|
||||
# Decrypt the security token
|
||||
decrypted_st = decryptor.decrypt(encrypted_st)
|
||||
|
||||
# Get the audio stream decryption key and nonce from the decrypted security token
|
||||
key = decrypted_st[:16]
|
||||
nonce = decrypted_st[16:24]
|
||||
|
||||
return key, nonce
|
||||
|
||||
|
||||
def decrypt_file(efile, dfile, key, nonce):
|
||||
'''
|
||||
Decrypts an encrypted MQA file given the file, key and nonce
|
||||
'''
|
||||
|
||||
# Initialize counter and file decryptor
|
||||
counter = Counter.new(64, prefix=nonce, initial_value=0)
|
||||
decryptor = AES.new(key, AES.MODE_CTR, counter=counter)
|
||||
|
||||
# Open and decrypt
|
||||
with open(efile, 'rb') as eflac:
|
||||
flac = decryptor.decrypt(eflac.read())
|
||||
|
||||
# Replace with decrypted file
|
||||
with open(dfile, 'wb') as dflac:
|
||||
dflac.write(flac)
|
||||
|
||||
+222
-735
@@ -1,735 +1,222 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : download.py
|
||||
@Time : 2019/02/27
|
||||
@Author : Yaron Huang
|
||||
@Version : 1.0
|
||||
@Contact : yaronhuang@qq.com
|
||||
@Desc : Download Function
|
||||
'''
|
||||
import sys
|
||||
import os
|
||||
import codecs
|
||||
|
||||
from datetime import datetime
|
||||
from aigpy import pathHelper
|
||||
# from tidal_dl import netHelper
|
||||
from aigpy import netHelper
|
||||
from aigpy import fileHelper
|
||||
from aigpy import cmdHelper
|
||||
from aigpy import systemHelper
|
||||
|
||||
# from tidal_dl.ffmpegHelper import FFmpegTool
|
||||
from aigpy.ffmpegHelper import FFmpegTool
|
||||
from aigpy.cmdHelper import myinput, myinputInt
|
||||
from aigpy.threadHelper import ThreadTool
|
||||
from aigpy.progressHelper import ProgressTool
|
||||
|
||||
from tidal_dl.check import CheckTool
|
||||
from tidal_dl.tidal import TidalTool
|
||||
from tidal_dl.tidal import TidalConfig
|
||||
from tidal_dl.tidal import TidalAccount
|
||||
from tidal_dl.decryption import decrypt_security_token
|
||||
from tidal_dl.decryption import decrypt_file
|
||||
from tidal_dl.printhelper import printChoice, printErr, printSUCCESS
|
||||
|
||||
|
||||
class Download(object):
|
||||
def __init__(self, threadNum=3):
|
||||
self.config = TidalConfig()
|
||||
self.tool = TidalTool()
|
||||
self.thread = ThreadTool(int(threadNum))
|
||||
self.ffmpeg = FFmpegTool(mergerTimeout=45)
|
||||
self.progress = ProgressTool(100)
|
||||
self.check = CheckTool()
|
||||
|
||||
self.showpro = False
|
||||
if self.config.showprogress == 'True':
|
||||
self.showpro = True
|
||||
|
||||
pathHelper.mkdirs(self.config.outputdir + "/Album/")
|
||||
pathHelper.mkdirs(self.config.outputdir + "/Playlist/")
|
||||
pathHelper.mkdirs(self.config.outputdir + "/Video/")
|
||||
pathHelper.mkdirs(self.config.outputdir + "/Favorite/")
|
||||
|
||||
def __isNeedDownload(self, path, url):
|
||||
curSize = fileHelper.getFileSize(path)
|
||||
if curSize <= 0:
|
||||
return True
|
||||
netSize = netHelper.getFileSize(url)
|
||||
if curSize >= netSize:
|
||||
return False
|
||||
return True
|
||||
|
||||
# dowmload track thread
|
||||
def __thradfunc_dl(self, paraList):
|
||||
count = 1
|
||||
printRet = True
|
||||
pstr = paraList['title'] + "(Download Err!)"
|
||||
redownload = True
|
||||
needDl = True
|
||||
bIsSuccess = False
|
||||
albumInfo = None
|
||||
index = None
|
||||
coverpath = None
|
||||
|
||||
if 'redownload' in paraList:
|
||||
redownload = paraList['redownload']
|
||||
if 'retry' in paraList:
|
||||
count = count + paraList['retry']
|
||||
if 'show' in paraList:
|
||||
printRet = paraList['show']
|
||||
if 'album' in paraList:
|
||||
albumInfo = paraList['album']
|
||||
if 'index' in paraList:
|
||||
index = paraList['index']
|
||||
if 'coverpath' in paraList:
|
||||
coverpath = paraList['coverpath']
|
||||
|
||||
if redownload is False:
|
||||
needDl = self.__isNeedDownload(paraList['path'], paraList['url'])
|
||||
|
||||
# DEBUG
|
||||
# self.tool.setTrackMetadata(paraList['trackinfo'], paraList['path'], albumInfo, index, coverpath)
|
||||
showprogress = False
|
||||
if int(self.config.threadnum) <= 1 and self.showpro:
|
||||
showprogress = True
|
||||
|
||||
Contributors = self.tool.getTrackContributors(paraList['trackinfo']['id'])
|
||||
if needDl:
|
||||
try:
|
||||
while count > 0:
|
||||
count = count - 1
|
||||
check = netHelper.downloadFile(paraList['url'], paraList['path']+'.part', showprogress=showprogress, stimeout=20)
|
||||
if check is True:
|
||||
if paraList['key'] == '':
|
||||
# unencrypted -> just move into place
|
||||
os.replace(paraList['path']+'.part', paraList['path'])
|
||||
break
|
||||
else:
|
||||
# encrypted -> decrypt and remove encrypted file
|
||||
key, nonce = decrypt_security_token(paraList['key'])
|
||||
decrypt_file(paraList['path']+'.part', paraList['path'], key, nonce)
|
||||
os.remove(paraList['path']+'.part')
|
||||
break
|
||||
if check:
|
||||
bIsSuccess = True
|
||||
paraList['path'] = self.tool.covertMp4toM4a(paraList['path'])
|
||||
self.tool.setTrackMetadata(paraList['trackinfo'], paraList['path'],
|
||||
albumInfo, index, coverpath, Contributors)
|
||||
pstr = paraList['title']
|
||||
except Exception as e:
|
||||
printErr(14, str(e) + " while downloading " + paraList['url'])
|
||||
else:
|
||||
pstr = paraList['title']
|
||||
bIsSuccess = True
|
||||
|
||||
if printRet:
|
||||
if(bIsSuccess):
|
||||
printSUCCESS(14, pstr)
|
||||
else:
|
||||
printErr(14, pstr)
|
||||
return
|
||||
|
||||
# creat album output dir
|
||||
def __creatAlbumDir(self, albumInfo, quality='LOW'):
|
||||
# creat outputdir
|
||||
title = pathHelper.replaceLimitChar(albumInfo['title'], '-')
|
||||
author = pathHelper.replaceLimitChar(albumInfo['artist']['name'], '-')
|
||||
|
||||
# add year
|
||||
if self.config.addyear != 'No':
|
||||
if self.config.addyear == 'Before':
|
||||
title = '[' + str(datetime.strptime(albumInfo['releaseDate'], '%Y-%m-%d').year) + '] '+title
|
||||
elif self.config.addyear == 'After':
|
||||
title = title+' [' + str(datetime.strptime(albumInfo['releaseDate'], '%Y-%m-%d').year) + ']'
|
||||
else:
|
||||
title = title
|
||||
|
||||
# add quality[M] labels
|
||||
if 'audioQuality' in albumInfo and albumInfo['audioQuality'] == 'HI_RES' and quality == 'HI_RES':
|
||||
title = '[M] '+title
|
||||
|
||||
targetDir = self.config.outputdir + "/Album/" + author + '/' + title
|
||||
targetDir = os.path.abspath(targetDir)
|
||||
pathHelper.mkdirs(targetDir)
|
||||
|
||||
# creat volumes dir
|
||||
count = 1
|
||||
numOfVolumes = int(albumInfo['numberOfVolumes'])
|
||||
if numOfVolumes > 1:
|
||||
while count < numOfVolumes + 1:
|
||||
volumeDir = targetDir + "/Volume" + str(count)
|
||||
pathHelper.mkdirs(volumeDir)
|
||||
count = count + 1
|
||||
return targetDir
|
||||
|
||||
def _getSongExtension(self, downloadUrl):
|
||||
if downloadUrl.find('.flac?') != -1:
|
||||
return '.flac'
|
||||
if downloadUrl.find('.m4a?') != -1:
|
||||
return '.m4a'
|
||||
if downloadUrl.find('.mp4?') != -1:
|
||||
return '.mp4'
|
||||
return '.m4a'
|
||||
|
||||
def _IsExplicitString(self, IsExplicit):
|
||||
String = None
|
||||
if IsExplicit:
|
||||
String = 'Explicit'
|
||||
return String
|
||||
|
||||
def __getAlbumSongSavePath(self, targetDir, albumInfo, item, extension):
|
||||
if extension is None:
|
||||
extension = ".m4a"
|
||||
|
||||
seq = self.tool.getIndexStr(item['trackNumber'], albumInfo['numberOfTracks'])
|
||||
name = seq + pathHelper.replaceLimitChar(item['title'], '-')
|
||||
fileExplicit = self._IsExplicitString(item['explicit'])
|
||||
if self.config.addhyphen == 'True':
|
||||
name = seq + '- ' + pathHelper.replaceLimitChar(item['title'], '-')
|
||||
if self.config.addexplicit == "True" and fileExplicit is not None:
|
||||
name = name + " - " + fileExplicit
|
||||
|
||||
seq = item['volumeNumber']
|
||||
path = targetDir + "/"
|
||||
if int(albumInfo['numberOfVolumes']) > 1:
|
||||
path += 'Volume' + str(seq) + "/"
|
||||
|
||||
maxlen = 255
|
||||
if systemHelper.isLinux():
|
||||
maxlen = 4090
|
||||
# truncate filename when it's longer than system's
|
||||
# filename limit which is 255
|
||||
len_sum = len(path) + len(name) + len(extension)
|
||||
if len_sum > maxlen:
|
||||
diff = maxlen - len_sum
|
||||
name = name[: len(name) + diff]
|
||||
|
||||
filePath = path + name + extension
|
||||
checklen = len(filePath)
|
||||
return filePath
|
||||
|
||||
def __getExistFiles(self, paths):
|
||||
ret = []
|
||||
for item in paths:
|
||||
if os.path.isfile(item):
|
||||
ret.append(item)
|
||||
return ret
|
||||
|
||||
def __getVideoResolutionIndex(self, reslist):
|
||||
array = []
|
||||
# if reslist != None:
|
||||
# for item in reslist:
|
||||
# subs = item.split('x')
|
||||
# subs = subs[1].split(',')
|
||||
# array.append(int(subs[0]))
|
||||
for item in reslist:
|
||||
subs = item.split('x')
|
||||
subs = subs[1].split(',')
|
||||
array.append(int(subs[0]))
|
||||
cmp = int(self.config.resolution)
|
||||
ret = 0
|
||||
for item in array:
|
||||
if cmp >= item:
|
||||
return ret
|
||||
ret += 1
|
||||
return len(array) - 1
|
||||
|
||||
def downloadAlbum(self, album_id=None, redl_flag=None):
|
||||
while_count = 9999
|
||||
while while_count > 0:
|
||||
while_count -= 1
|
||||
|
||||
if album_id is not None:
|
||||
while_count = 0
|
||||
sID = album_id
|
||||
else:
|
||||
print("----------------ALBUM------------------")
|
||||
sID = printChoice("Enter AlbumID(Enter '0' go back):", True, 0)
|
||||
if sID == 0:
|
||||
return
|
||||
|
||||
aAlbumInfo = self.tool.getAlbum(sID)
|
||||
if self.tool.errmsg != "":
|
||||
printErr(0, "Get AlbumInfo Err! " + self.tool.errmsg)
|
||||
continue
|
||||
|
||||
print("[Title] %s" % (aAlbumInfo['title']))
|
||||
print("[SongNum] %s\n" % (aAlbumInfo['numberOfTracks']))
|
||||
|
||||
# Get Tracks
|
||||
aAlbumTracks = self.tool.getAlbumTracks(sID)
|
||||
if self.tool.errmsg != "":
|
||||
printErr(0, "Get AlbumTracks Err!" + self.tool.errmsg)
|
||||
continue
|
||||
aAlbumVideos = self.tool.getAlbumVideos(sID)
|
||||
|
||||
# Creat OutputDir
|
||||
targetDir = self.__creatAlbumDir(aAlbumInfo, self.config.quality)
|
||||
# write msg
|
||||
string = self.tool.convertAlbumInfoToString(aAlbumInfo, aAlbumTracks)
|
||||
with codecs.open(targetDir + "/AlbumInfo.txt", 'w', 'utf-8') as fd:
|
||||
fd.write(string)
|
||||
# download cover
|
||||
coverPath = targetDir + '/' + pathHelper.replaceLimitChar(aAlbumInfo['title'], '-') + '.jpg'
|
||||
if aAlbumInfo['cover'] is not None:
|
||||
coverUrl = self.tool.getAlbumArtworkUrl(aAlbumInfo['cover'])
|
||||
netHelper.downloadFile(coverUrl, coverPath)
|
||||
# check exist files
|
||||
redownload = True
|
||||
if redl_flag is None:
|
||||
existFiles = pathHelper.getDirFiles(targetDir)
|
||||
for item in existFiles:
|
||||
if '.txt' in item:
|
||||
continue
|
||||
if '.jpg' in item:
|
||||
continue
|
||||
check = printChoice("Some tracks already exist. Redownload?(y/n):")
|
||||
if not cmdHelper.isInputYes(check):
|
||||
redownload = False
|
||||
break
|
||||
else:
|
||||
redownload = redl_flag
|
||||
|
||||
# download album tracks
|
||||
for item in aAlbumTracks['items']:
|
||||
streamInfo = self.tool.getStreamUrl(str(item['id']), self.config.quality)
|
||||
if self.tool.errmsg != "" or not streamInfo:
|
||||
printErr(14, item['title'] + "(Get Stream Url Err!" + self.tool.errmsg + ")")
|
||||
continue
|
||||
|
||||
fileType = self._getSongExtension(streamInfo['url'])
|
||||
filePath = self.__getAlbumSongSavePath(targetDir, aAlbumInfo, item, fileType)
|
||||
paraList = {'album': aAlbumInfo,
|
||||
'redownload': redownload,
|
||||
'title': item['title'],
|
||||
'trackinfo': item,
|
||||
'url': streamInfo['url'],
|
||||
'path': filePath,
|
||||
'retry': 3,
|
||||
'key': streamInfo['encryptionKey'],
|
||||
'coverpath': coverPath}
|
||||
self.thread.start(self.__thradfunc_dl, paraList)
|
||||
# wait all download thread
|
||||
self.thread.waitAll()
|
||||
self.tool.removeTmpFile(targetDir)
|
||||
|
||||
# remove cover
|
||||
if self.config.savephoto != 'True':
|
||||
pathHelper.remove(coverPath)
|
||||
|
||||
# download video
|
||||
|
||||
for item in aAlbumVideos:
|
||||
item = item['item']
|
||||
filePath = targetDir + '/' + pathHelper.replaceLimitChar(item['title'], '-') + ".mp4"
|
||||
filePath = os.path.abspath(filePath)
|
||||
if os.access(filePath, 0):
|
||||
os.remove(filePath)
|
||||
|
||||
try:
|
||||
resolutionList, urlList = self.tool.getVideoResolutionList(item['id'])
|
||||
selectIndex = self.__getVideoResolutionIndex(resolutionList)
|
||||
if self.ffmpeg.mergerByM3u8_Multithreading2(urlList[int(selectIndex)], filePath, showprogress=self.showpro):
|
||||
printSUCCESS(14, item['title'])
|
||||
else:
|
||||
printErr(14, item['title'])
|
||||
except:
|
||||
printErr(14, item['title'])
|
||||
# return
|
||||
|
||||
return
|
||||
|
||||
def downloadArtistAlbum(self, includeSingles=True, artistID=None):
|
||||
while True:
|
||||
print("-------------ARTIST ALBUM--------------")
|
||||
if artistID is not None:
|
||||
sID = artistID
|
||||
else:
|
||||
sID = printChoice("Enter Artist ID(Enter '0' go back):", True, 0)
|
||||
if sID == 0:
|
||||
return
|
||||
|
||||
array = self.tool.getArtistAlbum(sID, includeSingles)
|
||||
if self.tool.errmsg != "":
|
||||
printErr(0, "Get AlbumList Err! " + self.tool.errmsg)
|
||||
continue
|
||||
|
||||
redownload = True
|
||||
if artistID is None:
|
||||
check = printChoice("Skip downloaded files?(y/n):")
|
||||
if not cmdHelper.isInputYes(check):
|
||||
redownload = False
|
||||
|
||||
for index, item in enumerate(array):
|
||||
print("----Album[{0}/{1}]----".format(index+1, len(array)))
|
||||
self.downloadAlbum(item['id'], redownload)
|
||||
|
||||
if artistID is not None:
|
||||
# Break out of the function if we are only downloading one artist's albums
|
||||
return
|
||||
|
||||
|
||||
|
||||
def downloadTrack(self, track_id=None):
|
||||
while_count = 9999
|
||||
while while_count > 0:
|
||||
while_count -= 1
|
||||
|
||||
if track_id is not None:
|
||||
while_count = 0
|
||||
sID = track_id
|
||||
else:
|
||||
print("----------------TRACK------------------")
|
||||
sID = printChoice("Enter TrackID(Enter '0' go back):", True, 0)
|
||||
if sID == 0:
|
||||
return
|
||||
aTrackInfo = self.tool.getTrack(sID)
|
||||
if self.tool.errmsg != "":
|
||||
printErr(0, "Get TrackInfo Err! " + self.tool.errmsg)
|
||||
return
|
||||
aAlbumInfo = self.tool.getAlbum(aTrackInfo['album']['id'])
|
||||
if self.tool.errmsg != "":
|
||||
printErr(0, "Get TrackInfo Err! " + self.tool.errmsg)
|
||||
return
|
||||
|
||||
# t = self.tool.getTrackContributors(sID)
|
||||
|
||||
print("[AlbumTitle ] %s" % (aAlbumInfo['title']))
|
||||
print("[TrackTitle ] %s" % (aTrackInfo['title']))
|
||||
print("[Duration ] %s" % (aTrackInfo['duration']))
|
||||
print("[TrackNumber] %s" % (aTrackInfo['trackNumber']))
|
||||
print("[Explicit ] %s" % (aAlbumInfo['explicit']))
|
||||
# print("[Version ] %s\n" % (aTrackInfo['version']))
|
||||
|
||||
# Creat OutputDir
|
||||
targetDir = self.__creatAlbumDir(aAlbumInfo, self.config.quality)
|
||||
# download cover
|
||||
coverPath = targetDir + '/' + pathHelper.replaceLimitChar(aAlbumInfo['title'], '-') + '.jpg'
|
||||
if aAlbumInfo['cover'] is not None:
|
||||
coverUrl = self.tool.getAlbumArtworkUrl(aAlbumInfo['cover'])
|
||||
netHelper.downloadFile(coverUrl, coverPath)
|
||||
|
||||
# download
|
||||
streamInfo = self.tool.getStreamUrl(sID, self.config.quality)
|
||||
if self.tool.errmsg != "" or not streamInfo:
|
||||
printErr(14, aTrackInfo['title'] + "(Get Stream Url Err!" + self.tool.errmsg + ")")
|
||||
continue
|
||||
|
||||
fileType = self._getSongExtension(streamInfo['url'])
|
||||
filePath = self.__getAlbumSongSavePath(targetDir, aAlbumInfo, aTrackInfo, fileType)
|
||||
paraList = {'album': aAlbumInfo,
|
||||
'title': aTrackInfo['title'],
|
||||
'trackinfo': aTrackInfo,
|
||||
'url': streamInfo['url'],
|
||||
'path': filePath,
|
||||
'retry': 3,
|
||||
'key': streamInfo['encryptionKey'],
|
||||
'coverpath': coverPath}
|
||||
|
||||
self.thread.start(self.__thradfunc_dl, paraList)
|
||||
# wait all download thread
|
||||
self.thread.waitAll()
|
||||
self.tool.removeTmpFile(targetDir)
|
||||
|
||||
# remove cover
|
||||
if self.config.savephoto != 'True':
|
||||
pathHelper.remove(coverPath)
|
||||
return
|
||||
|
||||
def downloadVideo(self, video_id=None):
|
||||
flag = True
|
||||
while flag:
|
||||
targetDir = self.config.outputdir + "/Video/"
|
||||
if video_id is None:
|
||||
print("----------------VIDEO------------------")
|
||||
sID = printChoice("Enter VideoID(Enter '0' go back):", True, 0)
|
||||
if sID == 0:
|
||||
return
|
||||
else:
|
||||
flag = False
|
||||
sID = video_id
|
||||
|
||||
aVideoInfo = self.tool.getVideo(sID)
|
||||
if self.tool.errmsg != "":
|
||||
printErr(0, "Get VideoInfo Err! " + self.tool.errmsg)
|
||||
continue
|
||||
|
||||
print("[Title ] %s" % (aVideoInfo['title']))
|
||||
print("[Duration ] %s" % (aVideoInfo['duration']))
|
||||
print("[TrackNumber] %s" % (aVideoInfo['trackNumber']))
|
||||
print("[Type ] %s\n" % (aVideoInfo['type']))
|
||||
|
||||
# get resolution
|
||||
index = 0
|
||||
resolutionList, urlList = self.tool.getVideoResolutionList(sID)
|
||||
if self.tool.errmsg != "":
|
||||
printErr(14, self.tool.errmsg)
|
||||
continue
|
||||
|
||||
index = self.__getVideoResolutionIndex(resolutionList)
|
||||
path = targetDir + "/" + pathHelper.replaceLimitChar(aVideoInfo['title'], '-') + ".mp4"
|
||||
path = os.path.abspath(path)
|
||||
if os.access(path, 0):
|
||||
os.remove(path)
|
||||
|
||||
if self.ffmpeg.mergerByM3u8_Multithreading2(urlList[int(index)], path, True):
|
||||
printSUCCESS(14, aVideoInfo['title'])
|
||||
else:
|
||||
printErr(14, aVideoInfo['title'])
|
||||
return
|
||||
|
||||
def downloadPlaylist(self, playlist_id=None):
|
||||
while True:
|
||||
targetDir = self.config.outputdir + "/Playlist/"
|
||||
if playlist_id is None:
|
||||
print("--------------PLAYLIST-----------------")
|
||||
sID = printChoice("Enter PlayListID(Enter '0' go back):")
|
||||
if sID == '0':
|
||||
return
|
||||
else:
|
||||
sID = playlist_id
|
||||
|
||||
aPlaylistInfo, aItemInfo = self.tool.getPlaylist(sID)
|
||||
if self.tool.errmsg != "":
|
||||
printErr(0, "Get PlaylistInfo Err! " + self.tool.errmsg)
|
||||
return
|
||||
|
||||
print("[Title] %s" % (aPlaylistInfo['title']))
|
||||
print("[Type] %s" % (aPlaylistInfo['type']))
|
||||
print("[NumberOfTracks] %s" % (aPlaylistInfo['numberOfTracks']))
|
||||
print("[NumberOfVideos] %s" % (aPlaylistInfo['numberOfVideos']))
|
||||
print("[Duration] %s\n" % (aPlaylistInfo['duration']))
|
||||
|
||||
# Creat OutputDir
|
||||
targetDir = targetDir + pathHelper.replaceLimitChar(aPlaylistInfo['title'], '-')
|
||||
targetDir = os.path.abspath(targetDir).strip()
|
||||
pathHelper.mkdirs(targetDir)
|
||||
# write msg
|
||||
string = self.tool.convertPlaylistInfoToString(aPlaylistInfo, aItemInfo)
|
||||
with codecs.open(targetDir + "/PlaylistInfo.txt", 'w', 'utf-8') as fd:
|
||||
fd.write(string)
|
||||
# download cover
|
||||
coverPath = targetDir + '/' + pathHelper.replaceLimitChar(aPlaylistInfo['title'], '-') + '.jpg'
|
||||
coverUrl = self.tool.getPlaylistArtworkUrl(aPlaylistInfo['uuid'])
|
||||
check = netHelper.downloadFile(coverUrl, coverPath)
|
||||
|
||||
# download track
|
||||
bBreakFlag = False
|
||||
bFirstTime = True
|
||||
errIndex = []
|
||||
index = 0
|
||||
|
||||
while bBreakFlag is False:
|
||||
self.check.clear()
|
||||
index = 0
|
||||
tmpcoverpath = []
|
||||
for item in aItemInfo:
|
||||
type = item['type']
|
||||
item = item['item']
|
||||
if type != 'track':
|
||||
continue
|
||||
|
||||
index = index + 1
|
||||
if bFirstTime is False:
|
||||
if self.check.isInErr(index - 1, errIndex) == False:
|
||||
continue
|
||||
|
||||
streamInfo = self.tool.getStreamUrl(str(item['id']), self.config.quality)
|
||||
# streamInfo = self.tool.getStreamUrl(str(item['id']), 'DOLBY_ATMOS')
|
||||
if self.tool.errmsg != "" or not streamInfo:
|
||||
printErr(14, item['title'] + "(Get Stream Url Err!!" + self.tool.errmsg + ")")
|
||||
continue
|
||||
aAlbumInfo = self.tool.getAlbum(item['album']['id'])
|
||||
fileType = self._getSongExtension(streamInfo['url'])
|
||||
|
||||
# change targetDir
|
||||
targetDir2 = targetDir
|
||||
if self.config.plfile2arfolder == "True":
|
||||
targetDir2 = self.__creatAlbumDir(aAlbumInfo, self.config.quality)
|
||||
filePath = self.__getAlbumSongSavePath(targetDir2, aAlbumInfo, item, fileType)
|
||||
paraList = {'album': aAlbumInfo, 'title': item['title'], 'trackinfo': item,
|
||||
'url': streamInfo['url'], 'path': filePath, 'retry': 3, 'key': streamInfo['encryptionKey']}
|
||||
else:
|
||||
seq = self.tool.getIndexStr(index, len(aItemInfo))
|
||||
filePath = targetDir2 + '/' + seq + " "+ pathHelper.replaceLimitChar(item['title'], '-') + fileType
|
||||
paraList = {'album': aAlbumInfo, 'index': index, 'title': item['title'], 'trackinfo': item,
|
||||
'url': streamInfo['url'], 'path': filePath, 'retry': 3, 'key': streamInfo['encryptionKey']}
|
||||
|
||||
try:
|
||||
coverPath = targetDir2 + '/' + pathHelper.replaceLimitChar(aAlbumInfo['title'], '-') + '.jpg'
|
||||
coverUrl = self.tool.getAlbumArtworkUrl(aAlbumInfo['cover'])
|
||||
netHelper.downloadFile(coverUrl, coverPath)
|
||||
paraList['coverpath'] = coverPath
|
||||
tmpcoverpath.append(coverPath)
|
||||
except:
|
||||
cmdHelper.myprint("Could not download artwork for '{}'".format(
|
||||
item['title']), cmdHelper.TextColor.Red, None)
|
||||
|
||||
if self.config.onlym4a == "True":
|
||||
self.check.addPath(filePath.replace(".mp4", ".m4a"))
|
||||
else:
|
||||
self.check.addPath(filePath)
|
||||
self.thread.start(self.__thradfunc_dl, paraList)
|
||||
self.thread.waitAll()
|
||||
self.tool.removeTmpFile(targetDir)
|
||||
|
||||
# remove cover
|
||||
if self.config.savephoto != 'True':
|
||||
for item in tmpcoverpath:
|
||||
pathHelper.remove(item)
|
||||
|
||||
bBreakFlag = True
|
||||
bFirstTime = False
|
||||
|
||||
# check
|
||||
isErr, errIndex = self.check.checkPaths()
|
||||
if isErr:
|
||||
check = printChoice("[Err]\t\t" + str(len(errIndex)) + " Tracks Download Failed.Try Again?(y/n):")
|
||||
if check == 'y' or check == 'Y':
|
||||
bBreakFlag = False
|
||||
|
||||
# download video
|
||||
for item in aItemInfo:
|
||||
type = item['type']
|
||||
item = item['item']
|
||||
if type != 'video':
|
||||
continue
|
||||
|
||||
filePath = targetDir + '/' + pathHelper.replaceLimitChar(item['title'], '-') + ".mp4"
|
||||
filePath = os.path.abspath(filePath)
|
||||
if os.access(filePath, 0):
|
||||
os.remove(filePath)
|
||||
|
||||
videoID = item['id']
|
||||
resolutionList, urlList = self.tool.getVideoResolutionList(videoID)
|
||||
if urlList is None:
|
||||
printErr(14, item['title'] + '(' + self.tool.errmsg + ')')
|
||||
else:
|
||||
selectIndex = self.__getVideoResolutionIndex(resolutionList)
|
||||
if self.ffmpeg.mergerByM3u8_Multithreading2(urlList[int(selectIndex)], filePath, showprogress=self.showpro):
|
||||
printSUCCESS(14, item['title'])
|
||||
else:
|
||||
printErr(14, item['title'] + "(Download Or Merger Err!)")
|
||||
if playlist_id is not None:
|
||||
return
|
||||
return
|
||||
|
||||
def downloadFavorite(self):
|
||||
targetDir = self.config.outputdir + "/Favorite/"
|
||||
pathHelper.mkdirs(targetDir)
|
||||
|
||||
trackList, videoList = self.tool.getFavorite(self.config.userid)
|
||||
if self.tool.errmsg != "":
|
||||
printErr(0, "Get FavoriteList Err! " + self.tool.errmsg)
|
||||
return
|
||||
|
||||
print("[NumberOfTracks] %s" % (len(trackList)))
|
||||
print("[NumberOfVideos] %s" % (len(videoList)))
|
||||
# download track
|
||||
for item in trackList:
|
||||
item = item['item']
|
||||
streamInfo = self.tool.getStreamUrl(str(item['id']), self.config.quality)
|
||||
if self.tool.errmsg != "" or not streamInfo:
|
||||
printErr(14, item['title'] + "(Get Stream Url Err!!" + self.tool.errmsg + ")")
|
||||
continue
|
||||
|
||||
fileType = self._getSongExtension(streamInfo['url'])
|
||||
filePath = targetDir + '/' + pathHelper.replaceLimitChar(item['title'], '-') + fileType
|
||||
aAlbumInfo = self.tool.getAlbum(item['album']['id'])
|
||||
paraList = {'album': aAlbumInfo, 'title': item['title'], 'trackinfo': item,
|
||||
'url': streamInfo['url'], 'path': filePath, 'retry': 3, 'key': streamInfo['encryptionKey']}
|
||||
self.thread.start(self.__thradfunc_dl, paraList)
|
||||
self.thread.waitAll()
|
||||
|
||||
# download video
|
||||
for item in videoList:
|
||||
item = item['item']
|
||||
|
||||
filePath = targetDir + '/' + pathHelper.replaceLimitChar(item['title'], '-') + ".mp4"
|
||||
filePath = os.path.abspath(filePath)
|
||||
if os.access(filePath, 0):
|
||||
os.remove(filePath)
|
||||
|
||||
resolutionList, urlList = self.tool.getVideoResolutionList(item['id'])
|
||||
selectIndex = self.__getVideoResolutionIndex(resolutionList)
|
||||
if self.ffmpeg.mergerByM3u8_Multithreading2(urlList[int(selectIndex)], filePath, showprogress=self.showpro):
|
||||
printSUCCESS(14, item['title'])
|
||||
else:
|
||||
printErr(14, item['title'])
|
||||
return
|
||||
|
||||
def downloadUrl(self, link):
|
||||
stype, sid = self.tool.parseLink(link)
|
||||
if stype is None or sid is None:
|
||||
return
|
||||
if stype == "album":
|
||||
print("----------------ALBUM------------------")
|
||||
self.downloadAlbum(sid)
|
||||
elif stype == "track":
|
||||
print("----------------TRACK------------------")
|
||||
self.downloadTrack(sid)
|
||||
elif stype == "video":
|
||||
print("----------------VIDEO------------------")
|
||||
self.downloadVideo(sid)
|
||||
elif stype == "playlist":
|
||||
print("--------------PLAYLIST-----------------")
|
||||
self.downloadPlaylist(sid)
|
||||
elif stype == "artist":
|
||||
print("----------------ARTIST-----------------")
|
||||
self.downloadArtistAlbum(self.config.includesingle == "True", sid)
|
||||
|
||||
def downloadByFile(self, path):
|
||||
if not os.path.exists(path):
|
||||
return
|
||||
arr = self.tool.parseFile(path)
|
||||
print("----------------FILE------------------")
|
||||
print("[Number of albums] %s" % (len(arr['album'])))
|
||||
print("[Number of artists] %s" % (len(arr['artist'])))
|
||||
print("[Number of tracks] %s" % (len(arr['track'])))
|
||||
print("[Number of videos] %s" % (len(arr['video'])))
|
||||
print("[Number of URLs] %s" % (len(arr['url'])))
|
||||
|
||||
if len(arr['album']) > 0:
|
||||
redownload = True
|
||||
check = printChoice("Skip downloaded files?(y/n):")
|
||||
if not cmdHelper.isInputYes(check):
|
||||
redownload = False
|
||||
|
||||
for index, item in enumerate(arr['album']):
|
||||
print("----Album[{0}/{1}]----".format(index+1, len(arr['album'])))
|
||||
print("[ID] %s" % (item))
|
||||
self.downloadAlbum(item, redownload)
|
||||
for index, item in enumerate(arr['artist']):
|
||||
print(index)
|
||||
print("----Artist[{0}/{1}]----".format(index+1, len(arr['artist'])))
|
||||
print("[ID] %s" % (item))
|
||||
includeSingles = self.config.includesingle == "True"
|
||||
self.downloadArtistAlbum(includeSingles, item)
|
||||
for index, item in enumerate(arr['track']):
|
||||
print("----Track[{0}/{1}]----".format(index+1, len(arr['track'])))
|
||||
print("[ID] %s" % (item))
|
||||
self.downloadTrack(item)
|
||||
for index, item in enumerate(arr['video']):
|
||||
print("----Video[{0}/{1}]----".format(index+1, len(arr['video'])))
|
||||
print("[ID] %s" % (item))
|
||||
self.downloadVideo(item)
|
||||
for index, item in enumerate(arr['url']):
|
||||
print("----Url[{0}/{1}]----".format(index+1, len(arr['url'])))
|
||||
print("[link] %s" % (item))
|
||||
stype, sid = self.tool.parseLink(item)
|
||||
if stype is None or sid is None:
|
||||
printErr(14, 'Link can`t parse!')
|
||||
continue
|
||||
print("[ID] %s" % (sid))
|
||||
if stype == "album":
|
||||
print("[Type] %s" % ("album"))
|
||||
self.downloadAlbum(sid)
|
||||
if stype == "track":
|
||||
print("[Type] %s" % ("track"))
|
||||
self.downloadTrack(sid)
|
||||
if stype == "video":
|
||||
print("[Type] %s" % ("video"))
|
||||
self.downloadVideo(sid)
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : download.py
|
||||
@Time : 2020/11/08
|
||||
@Author : Yaronzz
|
||||
@Version : 1.0
|
||||
@Contact : yaronhuang@foxmail.com
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
from decryption import *
|
||||
from printf import *
|
||||
from tidal import *
|
||||
|
||||
|
||||
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 __encrypted__(stream, srcPath, descPath):
|
||||
if aigpy.string.isNull(stream.encryptionKey):
|
||||
os.replace(srcPath, descPath)
|
||||
else:
|
||||
key, nonce = decrypt_security_token(stream.encryptionKey)
|
||||
decrypt_file(srcPath, descPath, key, nonce)
|
||||
os.remove(srcPath)
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
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(album) + '/cover.jpg'
|
||||
url = TIDAL_API.getCoverUrl(album.cover, "1280", "1280")
|
||||
aigpy.net.downloadFile(url, path)
|
||||
|
||||
|
||||
def downloadAlbumInfo(album, tracks):
|
||||
if album is None:
|
||||
return
|
||||
|
||||
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" % (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'
|
||||
|
||||
for index in range(0, album.numberOfVolumes):
|
||||
volumeNumber = index + 1
|
||||
infos += f"===========CD {volumeNumber}=============\n"
|
||||
for item in tracks:
|
||||
if item.volumeNumber != volumeNumber:
|
||||
continue
|
||||
infos += '{:<8}'.format("[%d]" % item.trackNumber)
|
||||
infos += "%s\n" % item.title
|
||||
aigpy.file.write(path, infos, "w+")
|
||||
|
||||
|
||||
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(item, album, playlist)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/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
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : __init__.py
|
||||
@Time : 2020/08/19
|
||||
@Author : Yaronzz
|
||||
@Version : 1.0
|
||||
@Contact : yaronhuang@foxmail.com
|
||||
@Desc :
|
||||
'''
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : arabic.py
|
||||
@Time : 2020/08/19
|
||||
@Author : shhade for hack
|
||||
@Version : 1.0
|
||||
@Contact :
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangArabic(object):
|
||||
SETTING = "الاعدادت"
|
||||
VALUE = "القيمة"
|
||||
SETTING_DOWNLOAD_PATH = "مجلد التحميل"
|
||||
SETTING_ONLY_M4A = "تحويل m4a الى mp4"
|
||||
SETTING_ADD_EXPLICIT_TAG = "اضافة توقيع الفنان"
|
||||
SETTING_ADD_HYPHEN = "اضافة سطر تحتي"
|
||||
SETTING_ADD_YEAR = "اضافة سنة الاصدار قبل نجلد التنزيل"
|
||||
SETTING_USE_TRACK_NUM = "اضف رقم التتبع الخاص بالاغنية"
|
||||
SETTING_AUDIO_QUALITY = "دقة الصوت"
|
||||
SETTING_VIDEO_QUALITY = "دقة الفديو"
|
||||
SETTING_CHECK_EXIST = "التاكد من وجود الملف قبل التنزيل"
|
||||
SETTING_ARTIST_BEFORE_TITLE = "اسم الفنان قبل اسم الاغنية"
|
||||
SETTING_ALBUMID_BEFORE_FOLDER = "رقم التتبع قبل مجلد التنزيل"
|
||||
SETTING_INCLUDE_EP = "اضافة single&ep"
|
||||
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 = "Add lyrics"
|
||||
SETTING_LYRICS_SERVER_PROXY = "Lyrics server proxy"
|
||||
SETTING_PATH = "Settings path"
|
||||
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 = "وظيفة"
|
||||
CHOICE_ENTER = "ادخل"
|
||||
CHOICE_ENTER_URLID = "ادخل 'رابط/رقم تتبع':"
|
||||
CHOICE_EXIT = "اخرج"
|
||||
CHOICE_LOGIN = "Check AccessToken"
|
||||
CHOICE_SETTINGS = "الاعدادات"
|
||||
CHOICE_SET_ACCESS_TOKEN = "اعداد AccessToken"
|
||||
CHOICE_DOWNLOAD_BY_URL = "التحميل عبر الرابط او رقم التتبع"
|
||||
CHOICE_LOGOUT = "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'-Return,'1'-Yes):"
|
||||
CHANGE_DOWNLOAD_PATH = "مجلد التنزيل('0' not modify):"
|
||||
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):"
|
||||
CHANGE_ADD_HYPHEN = "استخدم السطور التحتية بدل الفراغات('0'-No,'1'-Yes):"
|
||||
CHANGE_ADD_YEAR = "اضافة سنة الاصدار الى مجلد الالبوم('0'-No,'1'-Yes):"
|
||||
CHANGE_USE_TRACK_NUM = "اضافة رقم الاغنية قبل اسمها('0'-No,'1'-Yes):"
|
||||
CHANGE_CHECK_EXIST = "التحقق من وجود الملف قبل التحميل('0'-No,'1'-Yes):"
|
||||
CHANGE_ARTIST_BEFORE_TITLE = "اضف اسم الفنان قبل اسم الاغنية('0'-No,'1'-Yes):"
|
||||
CHANGE_INCLUDE_EP = "اضافة مسطلحات فردي او ثنائي الى الغنية('0'-No,'1'-Yes):"
|
||||
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,'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_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..."
|
||||
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 = 'توقيع الفنان'
|
||||
MODEL_ALBUM = 'الالبوم'
|
||||
MODEL_ID = 'رقم التتبع'
|
||||
MODEL_NAME = 'الاسم'
|
||||
MODEL_TYPE = 'النوع'
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : chinese.py
|
||||
@Time : 2020/08/19
|
||||
@Author : Yaronzz
|
||||
@Version : 1.0
|
||||
@Contact : yaronhuang@foxmail.com
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangChinese(object):
|
||||
SETTING = "设置"
|
||||
VALUE = "值"
|
||||
SETTING_DOWNLOAD_PATH = "下载目录"
|
||||
SETTING_ONLY_M4A = "转换mp4为m4a"
|
||||
SETTING_ADD_EXPLICIT_TAG = "文件名添加脏标Explicit"
|
||||
SETTING_ADD_HYPHEN = "文件名用'-'代替空格"
|
||||
SETTING_ADD_YEAR = "专辑文件夹添加年代标签"
|
||||
SETTING_USE_TRACK_NUM = "歌曲名称添加序号"
|
||||
SETTING_AUDIO_QUALITY = "歌曲质量"
|
||||
SETTING_VIDEO_QUALITY = "视频质量"
|
||||
SETTING_CHECK_EXIST = "是否跳过已下载的文件"
|
||||
SETTING_ARTIST_BEFORE_TITLE = "文件名前添加歌手名"
|
||||
SETTING_ALBUMID_BEFORE_FOLDER = "专辑文件夹添加专辑ID"
|
||||
SETTING_INCLUDE_EP = "下载歌手专辑时包含其EP单曲"
|
||||
SETTING_SAVE_COVERS = "保存封面"
|
||||
SETTING_LANGUAGE = "语言"
|
||||
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_TRACKINFO = "显示歌曲信息"
|
||||
SETTING_SAVE_ALBUMINFO = "保存AlbumInfo.txt"
|
||||
SETTING_DOWNLOAD_VIDEOS = "Download videos"
|
||||
SETTING_ADD_LYRICS = "添加歌词"
|
||||
SETTING_LYRICS_SERVER_PROXY = "歌词服务器代理"
|
||||
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 = "检查AccessToken"
|
||||
CHOICE_SETTINGS = "配置"
|
||||
CHOICE_SET_ACCESS_TOKEN = "设置AccessToken"
|
||||
CHOICE_DOWNLOAD_BY_URL = "通过链接或ID下载"
|
||||
CHOICE_LOGOUT = "注销"
|
||||
CHOICE_APIKEY = "选择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 = "歌名后添加脏话标签('0'-不,'1'-是):"
|
||||
CHANGE_ADD_HYPHEN = "文件名中用'-'代替空格('0'-不,'1'-是):"
|
||||
CHANGE_ADD_YEAR = "专辑目录前添加年代标签('0'-不,'1'-是):"
|
||||
CHANGE_USE_TRACK_NUM = "文件名前添加序号('0'-不,'1'-是):"
|
||||
CHANGE_CHECK_EXIST = "下载前检查是否有已下载的文件('0'-不,'1'-是):"
|
||||
CHANGE_ARTIST_BEFORE_TITLE = "文件名前添加歌手名称('0'-不,'1'-是):"
|
||||
CHANGE_INCLUDE_EP = "下载歌手专辑时包含其EP单曲('0'-不,'1'-是):"
|
||||
CHANGE_ALBUMID_BEFORE_FOLDER = "专辑目录前添加ID('0'-不,'1'-是):"
|
||||
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 = "保存歌词文件 ('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 = "开始启动登录..."
|
||||
AUTH_LOGIN_CODE = "你的登录码为: {}"
|
||||
AUTH_NEXT_STEP = "请打开 {} 并在 {} 之内完成操作."
|
||||
AUTH_WAITING = "等待登录验证..."
|
||||
AUTH_TIMEOUT = "操作超时."
|
||||
|
||||
MSG_VALID_ACCESSTOKEN = "AccessToken有效期为 {}."
|
||||
MSG_INVALID_ACCESSTOKEN = "AccessToken失效. 正在尝试更新它."
|
||||
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 = '脏标'
|
||||
MODEL_ALBUM = '专辑'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = '名称'
|
||||
MODEL_TYPE = '类型'
|
||||
@@ -0,0 +1,126 @@
|
||||
# !/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : croatian.py
|
||||
@Time : 2020/08/19
|
||||
@Author : Yaronzz
|
||||
@Version : 1.0
|
||||
@Contact : yaronhuang@foxmail.com
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangCroatian(object):
|
||||
SETTING = "POSTAVKE"
|
||||
VALUE = "VRIJEDNOST"
|
||||
SETTING_DOWNLOAD_PATH = "putanja preuzimanja"
|
||||
SETTING_ONLY_M4A = "Pretvori mp4 u m4a"
|
||||
SETTING_ADD_EXPLICIT_TAG = "Dodaj eksplicitni znak"
|
||||
SETTING_ADD_HYPHEN = "Dodaj crticu"
|
||||
SETTING_ADD_YEAR = "Dodaj godinu prije imena albuma u mapi"
|
||||
SETTING_USE_TRACK_NUM = "Dodaj korisnicki broj pjesme"
|
||||
SETTING_AUDIO_QUALITY = "Kvaliteta zvuka"
|
||||
SETTING_VIDEO_QUALITY = "Kvaliteta videozapisa"
|
||||
SETTING_CHECK_EXIST = "Provjeri postoji li"
|
||||
SETTING_ARTIST_BEFORE_TITLE = "Ime izvodjaca prije imena pjesme"
|
||||
SETTING_ALBUMID_BEFORE_FOLDER = "ID oznaka prije imena albuma u mapi"
|
||||
SETTING_INCLUDE_EP = "Ukljuci singl i EP"
|
||||
SETTING_SAVE_COVERS = "Spremi ilustraciju albuma"
|
||||
SETTING_LANGUAGE = "Jezik"
|
||||
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 = "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 = "ODABIR"
|
||||
FUNCTION = "FUNKCIJA"
|
||||
CHOICE_ENTER = "Ulaz"
|
||||
CHOICE_ENTER_URLID = "Unesi 'Url/ID':"
|
||||
CHOICE_EXIT = "Izlaz"
|
||||
CHOICE_LOGIN = "Check AccessToken"
|
||||
CHOICE_SETTINGS = "Postavke"
|
||||
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]"
|
||||
PRINT_SUCCESS = "[USPIJESNO]"
|
||||
|
||||
PRINT_ENTER_CHOICE = "Unesi odabir:"
|
||||
PRINT_LATEST_VERSION = "Posljednja verzija:"
|
||||
# PRINT_USERNAME = "korisnik:"
|
||||
# PRINT_PASSWORD = "lozinka:"
|
||||
|
||||
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,'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):"
|
||||
CHANGE_ADD_HYPHEN = "Koristi crtice umjesto razmaka u imeni datoteke ('0'-Ne,'1'-Da):"
|
||||
CHANGE_ADD_YEAR = "Dodaj godinu u imenu albuma u mapi('0'-Ne,'1'-Da):"
|
||||
CHANGE_USE_TRACK_NUM = "Dodaj broj pjesme prije imena pjesme u datoteci ('0'-Ne,'1'-Da):"
|
||||
CHANGE_CHECK_EXIST = "Provjeri postoji li ista datoteka prije preuzimanja pjesme('0'-Ne,'1'-Da):"
|
||||
CHANGE_ARTIST_BEFORE_TITLE = "Dodaj ime izvodjaca prije imena pjesme('0'-Ne,'1'-Da):"
|
||||
CHANGE_INCLUDE_EP = "Ukljuci singlove i EP-ove prilikom preuzimanja albuma izvodjaca('0'-Ne,'1'-Da):"
|
||||
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,'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_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..."
|
||||
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 = "Pogreska putanje!"
|
||||
MSG_INPUT_ERR = "Pogreska unosa!"
|
||||
|
||||
MODEL_ALBUM_PROPERTY = "ALBUM-SVOJSTVO"
|
||||
MODEL_TRACK_PROPERTY = "PJESMA-SVOJSTVO"
|
||||
MODEL_VIDEO_PROPERTY = "VIDEOZAPIS-SVOJSTVO"
|
||||
MODEL_ARTIST_PROPERTY = "IZVODJAC-SVOJSTVO"
|
||||
MODEL_PLAYLIST_PROPERTY = "PLAYLISTA-SVOJSTVO"
|
||||
|
||||
MODEL_TITLE = 'Naziv'
|
||||
MODEL_TRACK_NUMBER = 'Broj pjesme'
|
||||
MODEL_VIDEO_NUMBER = 'Broj videozapisa'
|
||||
MODEL_RELEASE_DATE = 'Datum izlaska'
|
||||
MODEL_VERSION = 'Verzija'
|
||||
MODEL_EXPLICIT = 'Eksplicitno'
|
||||
MODEL_ALBUM = 'Album'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = 'Naziv'
|
||||
MODEL_TYPE = 'Vrsta'
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : czech.py
|
||||
@Time : 2022/11/13
|
||||
@Author : Tomikk & Sweder
|
||||
@Version : 1.2
|
||||
@Contact : justtomikk@gmail.com & djsweder@gmail.com
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangCzech(object):
|
||||
SETTING = "Nastavení"
|
||||
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 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 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 singly & EP"
|
||||
SETTING_SAVE_COVERS = "Uložit obal alba"
|
||||
SETTING_LANGUAGE = "Změna jazyka"
|
||||
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 = "Zvolit"
|
||||
CHOICE_ENTER_URLID = "Vložit 'Url/ID':"
|
||||
CHOICE_EXIT = "Ukončit"
|
||||
CHOICE_LOGIN = "Zkontrolovat přístupový token"
|
||||
CHOICE_SETTINGS = "Nastavení"
|
||||
CHOICE_SET_ACCESS_TOKEN = "Nastavit přístupový token"
|
||||
CHOICE_DOWNLOAD_BY_URL = "Stáhnout buď dle URL nebo ID"
|
||||
CHOICE_LOGOUT = "Odhlásit"
|
||||
CHOICE_APIKEY = "Vybrat APIKey"
|
||||
|
||||
PRINT_ERR = "[Chyba]"
|
||||
PRINT_INFO = "[Info]"
|
||||
PRINT_SUCCESS = "[Staženo]"
|
||||
|
||||
PRINT_ENTER_CHOICE = "Zvolit volbu:"
|
||||
PRINT_LATEST_VERSION = "Nejnovější verze:"
|
||||
# PRINT_USERNAME = "přihlašovací jméno:"
|
||||
# PRINT_PASSWORD = "heslo"
|
||||
|
||||
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 = "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 = "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 = "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 zadání!"
|
||||
|
||||
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 = 'Explicitní'
|
||||
MODEL_ALBUM = 'Album'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = 'Jméno'
|
||||
MODEL_TYPE = 'Typ'
|
||||
@@ -0,0 +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_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'
|
||||
@@ -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'
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : english.py
|
||||
@Time : 2021/11/24
|
||||
@Author : Yaronzz & jee019
|
||||
@Version : 1.2
|
||||
@Contact : yaronhuang@foxmail.com
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangEnglish(object):
|
||||
SETTING = "SETTINGS"
|
||||
VALUE = "VALUE"
|
||||
SETTING_DOWNLOAD_PATH = "Download path"
|
||||
SETTING_ONLY_M4A = "Convert mp4 to m4a"
|
||||
SETTING_ADD_EXPLICIT_TAG = "Add explicit tag"
|
||||
SETTING_ADD_HYPHEN = "Add hyphen"
|
||||
SETTING_ADD_YEAR = "Add year before album-folder"
|
||||
SETTING_USE_TRACK_NUM = "Add user track number"
|
||||
SETTING_AUDIO_QUALITY = "Audio quality"
|
||||
SETTING_VIDEO_QUALITY = "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 = "Include singles & EPs"
|
||||
SETTING_SAVE_COVERS = "Save covers"
|
||||
SETTING_LANGUAGE = "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 = "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 = "CHOICE"
|
||||
FUNCTION = "FUNCTION"
|
||||
CHOICE_ENTER = "Enter"
|
||||
CHOICE_ENTER_URLID = "Enter 'Url/ID':"
|
||||
CHOICE_EXIT = "Exit"
|
||||
CHOICE_LOGIN = "Check AccessToken"
|
||||
CHOICE_SETTINGS = "Settings"
|
||||
CHOICE_SET_ACCESS_TOKEN = "Set AccessToken"
|
||||
CHOICE_DOWNLOAD_BY_URL = "Download by url or ID"
|
||||
CHOICE_LOGOUT = "Logout"
|
||||
CHOICE_APIKEY = "Select APIKey"
|
||||
|
||||
PRINT_ERR = "[ERR]"
|
||||
PRINT_INFO = "[INFO]"
|
||||
PRINT_SUCCESS = "[SUCCESS]"
|
||||
|
||||
PRINT_ENTER_CHOICE = "Enter Choice:"
|
||||
PRINT_LATEST_VERSION = "Latest version:"
|
||||
# PRINT_USERNAME = "username:"
|
||||
# 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,'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):"
|
||||
CHANGE_ADD_HYPHEN = "Use hyphens instead of spaces in file names('0'-No,'1'-Yes):"
|
||||
CHANGE_ADD_YEAR = "Add year to album folder names('0'-No,'1'-Yes):"
|
||||
CHANGE_USE_TRACK_NUM = "Add track number before file names('0'-No,'1'-Yes):"
|
||||
CHANGE_CHECK_EXIST = "Check exist file before download track('0'-No,'1'-Yes):"
|
||||
CHANGE_ARTIST_BEFORE_TITLE = "Add artistName before track title('0'-No,'1'-Yes):"
|
||||
CHANGE_INCLUDE_EP = "Include singles and EPs when downloading an artist's albums('0'-No,'1'-Yes):"
|
||||
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_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_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..."
|
||||
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 = "Path is error!"
|
||||
MSG_INPUT_ERR = "Input error!"
|
||||
|
||||
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 = 'Title'
|
||||
MODEL_TRACK_NUMBER = 'Track Number'
|
||||
MODEL_VIDEO_NUMBER = 'Video Number'
|
||||
MODEL_RELEASE_DATE = 'Release Date'
|
||||
MODEL_VERSION = 'Version'
|
||||
MODEL_EXPLICIT = 'Explicit'
|
||||
MODEL_ALBUM = 'Album'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = 'Name'
|
||||
MODEL_TYPE = 'Type'
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : filipino.py
|
||||
@Time : 2020/08/21
|
||||
@Author : Ni Ño
|
||||
@Version : 1.0
|
||||
@Contact :
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangFilipino(object):
|
||||
SETTING = "SETTINGS"
|
||||
VALUE = "VALUE"
|
||||
SETTING_DOWNLOAD_PATH = "Paroroonan ng Download"
|
||||
SETTING_ONLY_M4A = "I-convert ang mp4 bilang m4a"
|
||||
SETTING_ADD_EXPLICIT_TAG = "Lagyan ng explicit tag"
|
||||
SETTING_ADD_HYPHEN = "Lagyan ng hyphen"
|
||||
SETTING_ADD_YEAR = "Lagyan ng taon bago ang album-folder"
|
||||
SETTING_USE_TRACK_NUM = "Lagyan ng bilang ng user track"
|
||||
SETTING_AUDIO_QUALITY = "Kalidad ng Audio"
|
||||
SETTING_VIDEO_QUALITY = "Kalidad ng Video"
|
||||
SETTING_CHECK_EXIST = "Suriin kung mayroon na"
|
||||
SETTING_ARTIST_BEFORE_TITLE = "Pangalan ng artist bago ang pamagat ng kanta"
|
||||
SETTING_ALBUMID_BEFORE_FOLDER = "Id bago ang album-folder"
|
||||
SETTING_INCLUDE_EP = "Isama ang single at ep"
|
||||
SETTING_SAVE_COVERS = "I-save ang mga cover"
|
||||
SETTING_LANGUAGE = "Lenggwahe"
|
||||
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 = "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 = "PAGPIPILIAN"
|
||||
FUNCTION = "SILBI"
|
||||
CHOICE_ENTER = "Ilagay"
|
||||
CHOICE_ENTER_URLID = "Ilagay ang 'Url/ID':"
|
||||
CHOICE_EXIT = "Mag Exit"
|
||||
CHOICE_LOGIN = "Check AccessToken"
|
||||
CHOICE_SETTINGS = "Settings"
|
||||
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]"
|
||||
PRINT_SUCCESS = "[TAPOS NA]"
|
||||
|
||||
PRINT_ENTER_CHOICE = "Pumili ng sagot:"
|
||||
PRINT_LATEST_VERSION = "Pinakabagong Version:"
|
||||
# PRINT_USERNAME = "username:"
|
||||
# PRINT_PASSWORD = "password:"
|
||||
|
||||
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,'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):"
|
||||
CHANGE_ADD_HYPHEN = "Gamitin ang hyphens kesa sa spaces sa pangalan ng files('0'-Hindi,'1'-Oo):"
|
||||
CHANGE_ADD_YEAR = "Lagyan ng taon sa pangalan ng album folder('0'-Hindi,'1'-Oo):"
|
||||
CHANGE_USE_TRACK_NUM = "Lagyan ng bilang ng track bago ang pangalan ng files('0'-Hindi,'1'-Oo):"
|
||||
CHANGE_CHECK_EXIST = "Suriin kung naidownload na bago mag download muli('0'-Hindi,'1'-Oo):"
|
||||
CHANGE_ARTIST_BEFORE_TITLE = "Lagyan ng pangalan ng artist bago ang pamagat ng kanta('0'-Hindi,'1'-Oo):"
|
||||
CHANGE_INCLUDE_EP = "Isama ang singles at EPs sa pagdownload ng mga album mula sa artist('0'-Hindi,'1'-Oo):"
|
||||
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,'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_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..."
|
||||
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 = "May error sa paroroonan ng download!"
|
||||
MSG_INPUT_ERR = "May error sa pag-input!"
|
||||
|
||||
MODEL_ALBUM_PROPERTY = "PROPERTY NG ALBUM"
|
||||
MODEL_TRACK_PROPERTY = "PROPERTY NG TRACK"
|
||||
MODEL_VIDEO_PROPERTY = "PROPERTY NG VIDEO"
|
||||
MODEL_ARTIST_PROPERTY = "PROPERTY NG ARTIST"
|
||||
MODEL_PLAYLIST_PROPERTY = "PROPERTY NG PLAYLIST"
|
||||
|
||||
MODEL_TITLE = 'Pamagat'
|
||||
MODEL_TRACK_NUMBER = 'Bilang ng Track'
|
||||
MODEL_VIDEO_NUMBER = 'Bilang ng Video'
|
||||
MODEL_RELEASE_DATE = 'Petsa ng Pag-release'
|
||||
MODEL_VERSION = 'Bersyon'
|
||||
MODEL_EXPLICIT = 'Explicit'
|
||||
MODEL_ALBUM = 'Album'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = 'Pangalan'
|
||||
MODEL_TYPE = 'Uri'
|
||||
@@ -0,0 +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_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'
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : german.py
|
||||
@Time : 2022/11/8
|
||||
@Authors : Sematre, MineClashTV, Click1701
|
||||
@Version : 1.1
|
||||
@Contact :
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangGerman(object):
|
||||
SETTING = "EINSTELLUNG"
|
||||
VALUE = "WERT"
|
||||
SETTING_DOWNLOAD_PATH = "Download Pfad"
|
||||
SETTING_ONLY_M4A = "mp4 in m4a konvertieren"
|
||||
SETTING_ADD_EXPLICIT_TAG = "Explicit Tag hinzufügen"
|
||||
SETTING_ADD_HYPHEN = "Bindestrich hinzufügen"
|
||||
SETTING_ADD_YEAR = "Jahr vor Album-Ordner hinzufügen"
|
||||
SETTING_USE_TRACK_NUM = "Benutzerdefinierte Titelnummer hinzufügen"
|
||||
SETTING_AUDIO_QUALITY = "Tonqualität"
|
||||
SETTING_VIDEO_QUALITY = "Videoqualität"
|
||||
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 = "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_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_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"
|
||||
CHOICE_ENTER = "Mit"
|
||||
CHOICE_ENTER_URLID = "'Url/ID' eingeben:"
|
||||
CHOICE_EXIT = "Beenden"
|
||||
CHOICE_LOGIN = "AccessToken überprüfen"
|
||||
CHOICE_SETTINGS = "Einstellungen"
|
||||
CHOICE_SET_ACCESS_TOKEN = "AccessToken setzen"
|
||||
CHOICE_DOWNLOAD_BY_URL = "Download per URL oder ID"
|
||||
CHOICE_LOGOUT = "Ausloggen"
|
||||
CHOICE_APIKEY = "APIKey Auswahl"
|
||||
|
||||
PRINT_ERR = "[FEHLER]"
|
||||
PRINT_INFO = "[INFO]"
|
||||
PRINT_SUCCESS = "[ERFOLG]"
|
||||
|
||||
PRINT_ENTER_CHOICE = "Auswahl:"
|
||||
PRINT_LATEST_VERSION = "Neueste Version:"
|
||||
# PRINT_USERNAME = "Benutzername:"
|
||||
# PRINT_PASSWORD = "Passwort:"
|
||||
|
||||
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,'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 = "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_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 = "Warte auf Autorisierung..."
|
||||
AUTH_TIMEOUT = "Zeitüberschreitung der Operation."
|
||||
|
||||
MSG_VALID_ACCESSTOKEN = "AccessToken gültig für {}."
|
||||
MSG_INVALID_ACCESSTOKEN = "AccessToken abgelaufen. Er muss erneuert werden."
|
||||
MSG_PATH_ERR = "Ungültiger Pfad!"
|
||||
MSG_INPUT_ERR = "Eingabefehler!"
|
||||
|
||||
MODEL_ALBUM_PROPERTY = "ALBUM-EIGENSCHAFT"
|
||||
MODEL_TRACK_PROPERTY = "TRACK-EIGENSCHAFT"
|
||||
MODEL_VIDEO_PROPERTY = "VIDEO-EIGENSCHAFT"
|
||||
MODEL_ARTIST_PROPERTY = "KÜNSTLER-EIGENSCHAFT"
|
||||
MODEL_PLAYLIST_PROPERTY = "PLAYLIST-EIGENSCHAFT"
|
||||
|
||||
MODEL_TITLE = 'Titel'
|
||||
MODEL_TRACK_NUMBER = 'Titelnummer'
|
||||
MODEL_VIDEO_NUMBER = 'Videonummer'
|
||||
MODEL_RELEASE_DATE = 'Veröffentlichungsdatum'
|
||||
MODEL_VERSION = 'Version'
|
||||
MODEL_EXPLICIT = 'Explicit'
|
||||
MODEL_ALBUM = 'Album'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = 'Name'
|
||||
MODEL_TYPE = 'Typ'
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : hungarian.py
|
||||
@Time : 2022/08/01
|
||||
@Author : Shanahan
|
||||
@Version : 1.2
|
||||
@Contact :
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangHungarian(object):
|
||||
SETTING = "BEÁLLÍTÁSOK"
|
||||
VALUE = "ÉRTÉK"
|
||||
SETTING_DOWNLOAD_PATH = "Letöltési útvonal"
|
||||
SETTING_ONLY_M4A = "mp4 konvertálása m4a-ra"
|
||||
SETTING_ADD_EXPLICIT_TAG = "Explicit tag hozzáadása"
|
||||
SETTING_ADD_HYPHEN = "Kötőjel hozzáadása"
|
||||
SETTING_ADD_YEAR = "Év hozzáadása az album-mappa előtt"
|
||||
SETTING_USE_TRACK_NUM = "Add user track number"
|
||||
SETTING_AUDIO_QUALITY = "Audió minősége"
|
||||
SETTING_VIDEO_QUALITY = "Videó minősége"
|
||||
SETTING_CHECK_EXIST = "Ellenőrizze, hogy létezik-e"
|
||||
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ó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_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_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Ó"
|
||||
CHOICE_ENTER = "Írja be a"
|
||||
CHOICE_ENTER_URLID = "Adja meg az 'Url/ID'-t:"
|
||||
CHOICE_EXIT = "Kilépés"
|
||||
CHOICE_LOGIN = "AccessToken ellenőrzése"
|
||||
CHOICE_SETTINGS = "Beállítások"
|
||||
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Ó]"
|
||||
PRINT_SUCCESS = "[SIKERES]"
|
||||
|
||||
PRINT_ENTER_CHOICE = "Válasszon:"
|
||||
PRINT_LATEST_VERSION = "Legújabb verzió:"
|
||||
# PRINT_USERNAME = "felhasználónév:"
|
||||
# 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,'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):"
|
||||
CHANGE_ADD_HYPHEN = "Kötőjel használata szóköz helyett a fájlnevekben('0'-Nem,'1'-Igen):"
|
||||
CHANGE_ADD_YEAR = "Évszám hozzáadása az album mappanevekhez('0'-Nem,'1'-Igen):"
|
||||
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_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_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_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..."
|
||||
AUTH_LOGIN_CODE = "A bejelentkezési kódod {}"
|
||||
AUTH_NEXT_STEP = "Menj a {} a következő {} a beállítás befejezéséhez."
|
||||
AUTH_WAITING = "Engedélyre várva..."
|
||||
AUTH_TIMEOUT = "A művelet leállt."
|
||||
|
||||
MSG_VALID_ACCESSTOKEN = "AccessToken érvényessége {}."
|
||||
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-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'
|
||||
MODEL_VIDEO_NUMBER = 'Videó száma'
|
||||
MODEL_RELEASE_DATE = 'Megjelenés dátuma'
|
||||
MODEL_VERSION = 'Verzió'
|
||||
MODEL_EXPLICIT = 'Explicit'
|
||||
MODEL_ALBUM = 'Album'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = 'Név'
|
||||
MODEL_TYPE = 'Típus'
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : italian.py
|
||||
@Time : 2020/08/20
|
||||
@Author : Normando
|
||||
@Version : 1.0
|
||||
@Contact : normando@me.com
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangItalian(object):
|
||||
SETTING = "IMPOSTAZIONI"
|
||||
VALUE = "VALORE"
|
||||
SETTING_DOWNLOAD_PATH = "Percorso Download"
|
||||
SETTING_ONLY_M4A = "Convertire mp4 in m4a"
|
||||
SETTING_ADD_EXPLICIT_TAG = "Aggiungere tag 'Contenuto esplicito'"
|
||||
SETTING_ADD_HYPHEN = "Aggiungere trattino"
|
||||
SETTING_ADD_YEAR = "Aggiungere anno nella cartella album"
|
||||
SETTING_USE_TRACK_NUM = "Aggiungere numero traccia utente"
|
||||
SETTING_AUDIO_QUALITY = "Qualità Audio"
|
||||
SETTING_VIDEO_QUALITY = "Video Video"
|
||||
SETTING_CHECK_EXIST = "Controlla esistenza"
|
||||
SETTING_ARTIST_BEFORE_TITLE = "Nome artista prima del titolo della traccia"
|
||||
SETTING_ALBUMID_BEFORE_FOLDER = "Numero Id nell cartella album"
|
||||
SETTING_INCLUDE_EP = "Includere singolo&ep"
|
||||
SETTING_SAVE_COVERS = "Salva copertine"
|
||||
SETTING_LANGUAGE = "Lingua"
|
||||
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 = "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 = "SCELTA"
|
||||
FUNCTION = "FUNZIONE"
|
||||
CHOICE_ENTER = "Inserire"
|
||||
CHOICE_ENTER_URLID = "Inserire 'Url/ID':"
|
||||
CHOICE_EXIT = "Uscita"
|
||||
CHOICE_LOGIN = "Check AccessToken"
|
||||
CHOICE_SETTINGS = "Impostazioni"
|
||||
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]"
|
||||
PRINT_SUCCESS = "[SUCCESSO]"
|
||||
|
||||
PRINT_ENTER_CHOICE = "Inserire scelta:"
|
||||
PRINT_LATEST_VERSION = "Ultima versione:"
|
||||
# PRINT_USERNAME = "username:"
|
||||
# PRINT_PASSWORD = "password:"
|
||||
|
||||
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,'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ì):"
|
||||
CHANGE_ADD_HYPHEN = "Usare trattini al posto degli spazi nei nomi dei file ('0'-No,'1'-Sì):"
|
||||
CHANGE_ADD_YEAR = "Aggiungere l'anno al nome della cartella dell'album ('0'-No,'1'-Sì):"
|
||||
CHANGE_USE_TRACK_NUM = "Aggiungere il numero traccia prima del nome dei file ('0'-No,'1'-Sì):"
|
||||
CHANGE_CHECK_EXIST = "Controllare se il file esiste prima di scaricare la traccia ('0'-No,'1'-Sì):"
|
||||
CHANGE_ARTIST_BEFORE_TITLE = "Aggiungere il nome dell'artista prima del titolo della traccia ('0'-No,'1'-Sì):"
|
||||
CHANGE_INCLUDE_EP = "Includere singoli e EP quando si scaricano gli album di un artista ('0'-No,'1'-Sì):"
|
||||
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,'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_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..."
|
||||
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 = "Percorso errato!"
|
||||
MSG_INPUT_ERR = "Inserimento errato!"
|
||||
|
||||
MODEL_ALBUM_PROPERTY = "PROPRIETÀ-ALBUM"
|
||||
MODEL_TRACK_PROPERTY = "PROPRIETÀ-TRACCIA"
|
||||
MODEL_VIDEO_PROPERTY = "PROPRIETÀ-VIDEO"
|
||||
MODEL_ARTIST_PROPERTY = "PROPRIETÀ-ARTISTA"
|
||||
MODEL_PLAYLIST_PROPERTY = "PROPRIETÀ-PLAYLIST"
|
||||
|
||||
MODEL_TITLE = 'Titolo'
|
||||
MODEL_TRACK_NUMBER = 'Numero Traccia'
|
||||
MODEL_VIDEO_NUMBER = 'Numero Video'
|
||||
MODEL_RELEASE_DATE = 'Data uscita'
|
||||
MODEL_VERSION = 'Versione'
|
||||
MODEL_EXPLICIT = 'Contenuto Esplicito'
|
||||
MODEL_ALBUM = 'Album'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = 'Nome'
|
||||
MODEL_TYPE = 'Tipo'
|
||||
@@ -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 = 'タイプ'
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : korean.py
|
||||
@Time : 2021/11/24
|
||||
@Author : jee019
|
||||
@Version : 1.1
|
||||
@Contact : qwer010910@gmail.com
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangKorean(object):
|
||||
SETTING = "설정"
|
||||
VALUE = "값"
|
||||
SETTING_DOWNLOAD_PATH = "다운로드 경로"
|
||||
SETTING_ONLY_M4A = "mp4를 m4a로 변환"
|
||||
SETTING_ADD_EXPLICIT_TAG = "explicit 태그 추가"
|
||||
SETTING_ADD_HYPHEN = "하이픈 추가"
|
||||
SETTING_ADD_YEAR = "앨범 폴더 앞에 연도 추가"
|
||||
SETTING_USE_TRACK_NUM = "사용자 트랙 번호 추가"
|
||||
SETTING_AUDIO_QUALITY = "음질"
|
||||
SETTING_VIDEO_QUALITY = "영상 화질"
|
||||
SETTING_CHECK_EXIST = "존재 유무 확인"
|
||||
SETTING_ARTIST_BEFORE_TITLE = "트랙 제목 앞 아티스트 이름"
|
||||
SETTING_ALBUMID_BEFORE_FOLDER = "앨범 폴더 앞 ID"
|
||||
SETTING_INCLUDE_EP = "싱글 및 EP 포함"
|
||||
SETTING_SAVE_COVERS = "커버 저장"
|
||||
SETTING_LANGUAGE = "언어"
|
||||
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_TRACKINFO = "트랙 정보 표시"
|
||||
SETTING_SAVE_ALBUMINFO = "AlbumInfo.txt 저장"
|
||||
SETTING_DOWNLOAD_VIDEOS = "Download videos"
|
||||
SETTING_ADD_LYRICS = "가사 추가"
|
||||
SETTING_LYRICS_SERVER_PROXY = "가사 서버 프록시"
|
||||
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 = "기능"
|
||||
CHOICE_ENTER = "엔터"
|
||||
CHOICE_ENTER_URLID = "'Url/ID' 입력:"
|
||||
CHOICE_EXIT = "종료"
|
||||
CHOICE_LOGIN = "액세스 토큰 확인"
|
||||
CHOICE_SETTINGS = "설정"
|
||||
CHOICE_SET_ACCESS_TOKEN = "액세스 토큰 설정"
|
||||
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'-보통,'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'-예):"
|
||||
CHANGE_ADD_HYPHEN = "파일 이름에 공백 대신 하이픈 사용('0'-아니요,'1'-예):"
|
||||
CHANGE_ADD_YEAR = "앨범 폴더 이름에 연도 추가('0'-아니요,'1'-예):"
|
||||
CHANGE_USE_TRACK_NUM = "파일 이름 앞에 트랙 번호 추가('0'-아니요,'1'-예):"
|
||||
CHANGE_CHECK_EXIST = "다운로드 트랙 전에 존재하는 파일 확인('0'-아니요,'1'-예):"
|
||||
CHANGE_ARTIST_BEFORE_TITLE = "트랙 제목 앞에 아티스트 이름 추가('0'-아니요,'1'-예):"
|
||||
CHANGE_INCLUDE_EP = "아티스트 앨범 다운로드시 싱글 및 EP 포함('0'-아니요,'1'-예):"
|
||||
CHANGE_ALBUMID_BEFORE_FOLDER = "앨범 폴더 앞에 ID 추가('0'-아니요,'1'-예):"
|
||||
CHANGE_SAVE_COVERS = "커버 저장('0'-아니요,'1'-예):"
|
||||
CHANGE_LANGUAGE = "언어 선택"
|
||||
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 = "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 = "로그인 중..."
|
||||
AUTH_LOGIN_CODE = "로그인 코드는 다음과 같습니다. {}"
|
||||
AUTH_NEXT_STEP = "설치를 완료하려면 {}로 이동하십시오. 다음 {} 내에 있습니다."
|
||||
AUTH_WAITING = "승인 대기 중..."
|
||||
AUTH_TIMEOUT = "작업 시간 초과"
|
||||
|
||||
MSG_VALID_ACCESSTOKEN = "{}에 대해 액세스 토큰이 유효합니다."
|
||||
MSG_INVALID_ACCESSTOKEN = "만료된 액세스 토큰입니다. 새로 고침 중입니다."
|
||||
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 = '아이디'
|
||||
MODEL_NAME = '이름'
|
||||
MODEL_TYPE = '형식'
|
||||
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : language.py
|
||||
@Time : 2020/08/19
|
||||
@Author : Yaronzz
|
||||
@Version : 1.0
|
||||
@Contact : yaronhuang@foxmail.com
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
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
|
||||
|
||||
_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)
|
||||
|
||||
|
||||
LANG = Language()
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : norwegian.py
|
||||
@Time : 2021/03/25
|
||||
@Author : roberts91
|
||||
@Version : 1.0
|
||||
@Contact :
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangNorwegian(object):
|
||||
SETTING = "INNSTILLINGER"
|
||||
VALUE = "Verdi"
|
||||
SETTING_DOWNLOAD_PATH = "Nedlastingssti"
|
||||
SETTING_ONLY_M4A = "Konverter MP4 til M4A"
|
||||
SETTING_ADD_EXPLICIT_TAG = "Legg til eksplisitt tag"
|
||||
SETTING_ADD_HYPHEN = "Legg til bindestrek"
|
||||
SETTING_ADD_YEAR = "Legg til år før albummappenavn"
|
||||
SETTING_USE_TRACK_NUM = "Legg til spornummer"
|
||||
SETTING_AUDIO_QUALITY = "Lydkvalitet"
|
||||
SETTING_VIDEO_QUALITY = "Videokvalitet"
|
||||
SETTING_CHECK_EXIST = "Kontroller eksistens"
|
||||
SETTING_ARTIST_BEFORE_TITLE = "Artistnavn før spornummer"
|
||||
SETTING_ALBUMID_BEFORE_FOLDER = "Id før album mappe"
|
||||
SETTING_INCLUDE_EP = "Inkluder single&EP"
|
||||
SETTING_SAVE_COVERS = "Lagre cover"
|
||||
SETTING_LANGUAGE = "Språk"
|
||||
SETTING_USE_PLAYLIST_FOLDER = "Bruk spillelistemappe"
|
||||
SETTING_MULITHREAD_DOWNLOAD = "Last ned flere samtidig"
|
||||
SETTING_ALBUM_FOLDER_FORMAT = "Albummappens format"
|
||||
SETTING_PLAYLIST_FOLDER_FORMAT = "Spillelistemappens format"
|
||||
SETTING_TRACK_FILE_FORMAT = "Spor filformat"
|
||||
SETTING_VIDEO_FILE_FORMAT = "Video filformat"
|
||||
SETTING_SHOW_PROGRESS = "Vis fremgang"
|
||||
SETTING_SHOW_TRACKINFO = "Vis sporinformasjon"
|
||||
SETTING_SAVE_ALBUMINFO = "Lagre AlbumInfo.txt"
|
||||
SETTING_DOWNLOAD_VIDEOS = "Last ned video"
|
||||
SETTING_ADD_LYRICS = "Legg til sangtekst"
|
||||
SETTING_LYRICS_SERVER_PROXY = "Sangtekst server proxy"
|
||||
SETTING_ADD_LRC_FILE = "Lagre sangtekster med tidsreferanser (.lrc fil)"
|
||||
SETTING_PATH = "Innstillinger sti"
|
||||
SETTING_APIKEY = "API-nøkkel støtte"
|
||||
SETTING_ADD_TYPE_FOLDER = "Legg til Type-Folder"
|
||||
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
|
||||
|
||||
CHOICE = "VALG"
|
||||
FUNCTION = "FUNKSJON"
|
||||
CHOICE_ENTER = "Tast inn"
|
||||
CHOICE_ENTER_URLID = "Tast inn 'Url/ID':"
|
||||
CHOICE_EXIT = "Avslutt"
|
||||
CHOICE_LOGIN = "Kontroller AccessToken"
|
||||
CHOICE_SETTINGS = "Innstillinger"
|
||||
CHOICE_SET_ACCESS_TOKEN = "Sett AccessToken"
|
||||
CHOICE_DOWNLOAD_BY_URL = "Last ned via URL eller ID"
|
||||
CHOICE_LOGOUT = "Logg ut"
|
||||
CHOICE_APIKEY = "Velg APIKey"
|
||||
|
||||
PRINT_ERR = "[FEIL]"
|
||||
PRINT_INFO = "[INFO]"
|
||||
PRINT_SUCCESS = "[SUCCES]"
|
||||
|
||||
PRINT_ENTER_CHOICE = "Tast inn valg:"
|
||||
PRINT_LATEST_VERSION = "Seneste versjon:"
|
||||
# PRINT_USERNAME = "username:"
|
||||
# PRINT_PASSWORD = "password:"
|
||||
|
||||
CHANGE_START_SETTINGS = "Start innstillinger('0'-Tilbake,'1'-Ja):"
|
||||
CHANGE_DOWNLOAD_PATH = "Nedlastingssti('0'-ikke endre):"
|
||||
CHANGE_AUDIO_QUALITY = "Lydkvalitet('0'-Normal,'1'-Høy,'2'-HiFi,'3'-Master,'4'-Max):"
|
||||
CHANGE_VIDEO_QUALITY = "Videokvalitet(1080, 720, 480, 360):"
|
||||
CHANGE_ONLYM4A = "Konverter MP4 til M4A('0'-Nei,'1'-Ja):"
|
||||
CHANGE_ADD_EXPLICIT_TAG = "Legg til eksplisitt tag i filnavn('0'-Nei,'1'-Ja):"
|
||||
CHANGE_ADD_HYPHEN = "Bruk bindestreker i stedet for mellomrom i filnavn('0'-Nei,'1'-Ja):"
|
||||
CHANGE_ADD_YEAR = "Legg til år i albumnavn('0'-Nei,'1'-Ja):"
|
||||
CHANGE_USE_TRACK_NUM = "Legg til spornummer før filnavn('0'-Nei,'1'-Ja):"
|
||||
CHANGE_CHECK_EXIST = "Kontrollér filens eksistens før nedlasting('0'-Nei,'1'-Ja):"
|
||||
CHANGE_ARTIST_BEFORE_TITLE = "Legg til artistnavn før sportittel('0'-Nei,'1'-Ja):"
|
||||
CHANGE_INCLUDE_EP = "Inkluder singler og EP'er når man laster ned en artists album('0'-Nei,'1'-Ja):"
|
||||
CHANGE_ALBUMID_BEFORE_FOLDER = "Legg til ID før albummappe('0'-Nei,'1'-Ja):"
|
||||
CHANGE_SAVE_COVERS = "Lagre cover('0'-Nei,'1'-Ja):"
|
||||
CHANGE_LANGUAGE = "Velg språk"
|
||||
CHANGE_ALBUM_FOLDER_FORMAT = "Albummappe format('0'-ikke endre, 'default'-for å sette til standardverdi):"
|
||||
CHANGE_PLAYLIST_FOLDER_FORMAT = "Spillelistemappe format('0'-ikke endre, 'default'-for å sette til standardverdi):"
|
||||
CHANGE_TRACK_FILE_FORMAT = "Sportittel filformat('0'-ikke endre, 'default'-for å sette til standardverdi):"
|
||||
CHANGE_VIDEO_FILE_FORMAT = "Videofil format('0'-ikke endre, 'default'-for å sette til standardverdi):"
|
||||
CHANGE_SHOW_PROGRESS = "Vis fremgang('0'-Nei,'1'-Ja):"
|
||||
CHANGE_SHOW_TRACKINFO = "Vis sporinformasjon('0'-Nei,'1'-Ja):"
|
||||
CHANGE_SAVE_ALBUM_INFO = "Lagre AlbumInfo.txt('0'-Nei,'1'-Ja):"
|
||||
CHANGE_DOWNLOAD_VIDEOS = "Last ned videers (i spillelister, album, mikser)('0'-No,'1'-Yes):"
|
||||
CHANGE_ADD_LYRICS = "Legg til sangtekst('0'-Nei,'1'-Ja):"
|
||||
CHANGE_LYRICS_SERVER_PROXY = "Sangtekst server proxy('0'-not modify):"
|
||||
CHANGE_ADD_LRC_FILE = "Lagre sangtekster med tidsreferanser .lrc fil ('0'-Nei,'1'-Ja):"
|
||||
CHANGE_ADD_TYPE_FOLDER = "Legg til Type-mappe, f.eks. Album/Video/Spilleliste('0'-Nei,'1'-Ja):"
|
||||
CHANGE_MULITHREAD_DOWNLOAD = "Last ned flere samtidig('0'-Nei,'1'-Ja):"
|
||||
CHANGE_USE_DOWNLOAD_DELAY = "Use Download Delay('0'-No,'1'-Yes):"
|
||||
|
||||
# {} are required in these strings
|
||||
AUTH_START_LOGIN = "Starter login-prosessen."
|
||||
AUTH_LOGIN_CODE = "Din login kode er {}"
|
||||
AUTH_NEXT_STEP = "Gå til {} innen de neste {} for å avslutte setup."
|
||||
AUTH_WAITING = "Venter på godkjennelse..."
|
||||
AUTH_TIMEOUT = "Tiden gikk ut."
|
||||
|
||||
MSG_VALID_ACCESSTOKEN = "AccessToken tilgjengelig for {}."
|
||||
MSG_INVALID_ACCESSTOKEN = "AccessToken utløpt. Forøsker å oppdatere"
|
||||
MSG_PATH_ERR = "Sti feil!"
|
||||
MSG_INPUT_ERR = "Inntastningsfeol!"
|
||||
|
||||
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 = 'Tittel'
|
||||
MODEL_TRACK_NUMBER = 'Spornummer'
|
||||
MODEL_VIDEO_NUMBER = 'Videonummer'
|
||||
MODEL_RELEASE_DATE = 'Utgivelsesdato'
|
||||
MODEL_VERSION = 'Versjon'
|
||||
MODEL_EXPLICIT = 'Eksplisitt'
|
||||
MODEL_ALBUM = 'Album'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = 'Navn'
|
||||
MODEL_TYPE = 'Type'
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : polish.py
|
||||
@Time : 2022/03/04
|
||||
@Author : PatrykMis
|
||||
@Version : 1.0
|
||||
@Contact : patryk.mis@member.fsf.org
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangPolish(object):
|
||||
SETTING = "USTAWIENIA"
|
||||
VALUE = "WARTOŚĆ"
|
||||
SETTING_DOWNLOAD_PATH = "Ścieżka pobierania"
|
||||
SETTING_ONLY_M4A = "Konwertuj mp4 do m4a"
|
||||
SETTING_ADD_EXPLICIT_TAG = "Dodaj tag jednoznaczne"
|
||||
SETTING_ADD_HYPHEN = "Dodaj myslnik"
|
||||
SETTING_ADD_YEAR = "Dodaj rok porzed folderem albumu"
|
||||
SETTING_USE_TRACK_NUM = "Dodaj numer utworu użytkownika"
|
||||
SETTING_AUDIO_QUALITY = "Jakość audio"
|
||||
SETTING_VIDEO_QUALITY = "Jakość wideo"
|
||||
SETTING_CHECK_EXIST = "Sprawdź istnienie"
|
||||
SETTING_ARTIST_BEFORE_TITLE = "Nazwa artysty przed tytułem utworu"
|
||||
SETTING_ALBUMID_BEFORE_FOLDER = "Id przed folderem albumu"
|
||||
SETTING_INCLUDE_EP = "Uwzględnij single i EP"
|
||||
SETTING_SAVE_COVERS = "Zapisz okładki"
|
||||
SETTING_LANGUAGE = "Język"
|
||||
SETTING_USE_PLAYLIST_FOLDER = "Użyj folder playlisty"
|
||||
SETTING_MULITHREAD_DOWNLOAD = "Pobieranie wielowątkowe"
|
||||
SETTING_ALBUM_FOLDER_FORMAT = "Format folderu albumu"
|
||||
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
|
||||
SETTING_TRACK_FILE_FORMAT = "Format pliku utworu"
|
||||
SETTING_VIDEO_FILE_FORMAT = "Video file format"
|
||||
SETTING_SHOW_PROGRESS = "Pokaż postęp"
|
||||
SETTING_SHOW_TRACKINFO = "Pokaż informacje o utworze"
|
||||
SETTING_SAVE_ALBUMINFO = "Zapisz AlbumInfo.txt"
|
||||
SETTING_DOWNLOAD_VIDEOS = "Download videos"
|
||||
SETTING_ADD_LYRICS = "Dodaj teksty utworów"
|
||||
SETTING_LYRICS_SERVER_PROXY = "Serwer proxy dla tekstów"
|
||||
SETTING_ADD_LRC_FILE = "Zapisz czasowe teksty utworów (plik .lrc)"
|
||||
SETTING_PATH = "Ścieżka ustawień"
|
||||
SETTING_APIKEY = "Obsługa APIKey"
|
||||
SETTING_ADD_TYPE_FOLDER = "Dodaj folder typu"
|
||||
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
|
||||
|
||||
CHOICE = "WYBÓR"
|
||||
FUNCTION = "FUNKCJA"
|
||||
CHOICE_ENTER = "Wpisz"
|
||||
CHOICE_ENTER_URLID = "Wpisz 'Url/ID':"
|
||||
CHOICE_EXIT = "Wyjdź"
|
||||
CHOICE_LOGIN = "Sprawdź AccessToken"
|
||||
CHOICE_SETTINGS = "Ustawienia"
|
||||
CHOICE_SET_ACCESS_TOKEN = "Ustaw AccessToken"
|
||||
CHOICE_DOWNLOAD_BY_URL = "Pobierz według adresu URL lub ID"
|
||||
CHOICE_LOGOUT = "Wyloguj"
|
||||
CHOICE_APIKEY = "Wybierz APIKey"
|
||||
|
||||
PRINT_ERR = "[BŁĄD]"
|
||||
PRINT_INFO = "[INFO]"
|
||||
PRINT_SUCCESS = "[SUKCES]"
|
||||
|
||||
PRINT_ENTER_CHOICE = "Wprowadź Wybór:"
|
||||
PRINT_LATEST_VERSION = "Najnowsza wersja:"
|
||||
# PRINT_USERNAME = "nazwa użytkownika:"
|
||||
# PRINT_PASSWORD = "hasło:"
|
||||
|
||||
CHANGE_START_SETTINGS = "Uruchomić ustawienia('0'-Powrót,'1'-Tak):"
|
||||
CHANGE_DOWNLOAD_PATH = "Ścieżka pobierania('0'-bez zmian):"
|
||||
CHANGE_AUDIO_QUALITY = "Jakość audio('0'-Normalna,'1'-Wysoka,'2'-HiFi,'3'-Master,'4'-Max):"
|
||||
CHANGE_VIDEO_QUALITY = "Jakość wideo(1080, 720, 480, 360):"
|
||||
CHANGE_ONLYM4A = "Konwertuj mp4 do m4a('0'-Nie,'1'-Tak):"
|
||||
CHANGE_ADD_EXPLICIT_TAG = "Dodaj tag jednoznaczne do nazwy pliku('0'-Nie,'1'-Tak):"
|
||||
CHANGE_ADD_HYPHEN = "Używaj myślników zamiast spacji w nazwach plików('0'-Nie,'1'-Tak):"
|
||||
CHANGE_ADD_YEAR = "Dodaj rok do nazw folderów albumów('0'-Nie,'1'-Tak):"
|
||||
CHANGE_USE_TRACK_NUM = "Dodaj numer utworu przed nazwami plików('0'-Nie,'1'-Tak):"
|
||||
CHANGE_CHECK_EXIST = "Sprawdź istniejący plik przed pobraniem utworu('0'-Nie,'1'-Tak):"
|
||||
CHANGE_ARTIST_BEFORE_TITLE = "Dodaj nazwę artysty przed tytułem utworu('0'-Nie,'1'-Tak):"
|
||||
CHANGE_INCLUDE_EP = "Uwzględnij single i EP podczas pobierania albumów wykonawcy('0'-Nie,'1'-Tak):"
|
||||
CHANGE_ALBUMID_BEFORE_FOLDER = "Dodaj ID przed folderem albumu('0'-Nie,'1'-Tak):"
|
||||
CHANGE_SAVE_COVERS = "Zapisz okładki('0'-Nie,'1'-Tak):"
|
||||
CHANGE_LANGUAGE = "Wybierz język"
|
||||
CHANGE_ALBUM_FOLDER_FORMAT = "Format folderu albumu('0'-nie modyfikuj,'default'-by ustawić domyślny):"
|
||||
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
|
||||
CHANGE_TRACK_FILE_FORMAT = "Format pliku utworu('0'-nie modyfikuj,'default'-by ustawić domyślny):"
|
||||
CHANGE_VIDEO_FILE_FORMAT = "Video file format('0'-not modify,'default'-to set default):"
|
||||
CHANGE_SHOW_PROGRESS = "Pokaż postęp('0'-Nie,'1'-Tak):"
|
||||
CHANGE_SHOW_TRACKINFO = "Pokaż informacje o utworze('0'-Nie,'1'-Tak):"
|
||||
CHANGE_SAVE_ALBUM_INFO = "Zapisz AlbumInfo.txt('0'-Nie,'1'-Tak):"
|
||||
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
|
||||
CHANGE_ADD_LYRICS = "Dodaj teksty utworów('0'-Nie,'1'-Tak):"
|
||||
CHANGE_LYRICS_SERVER_PROXY = "Serwer proxy dla tekstów('0'-nie modyfikuj):"
|
||||
CHANGE_ADD_LRC_FILE = "Zapisz plik .lrc czasowych tekstów utworów ('0'-Nie,'1'-Tak):"
|
||||
CHANGE_ADD_TYPE_FOLDER = "Dodaj folder typu, np. Album/wideo/lista odtwarzania('0'-Nie,'1'-Tak):"
|
||||
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 = "Rozpoczęcie procesu logowania..."
|
||||
AUTH_LOGIN_CODE = "Twój kod logowania to {}"
|
||||
AUTH_NEXT_STEP = "Przejdź do {} w ciągu następnych {} aby zakończyć konfigurację."
|
||||
AUTH_WAITING = "Oczekiwanie na autoryzację..."
|
||||
AUTH_TIMEOUT = "Przekroczono limit czasu operacji."
|
||||
|
||||
MSG_VALID_ACCESSTOKEN = "AccessToken dobry przez {}."
|
||||
MSG_INVALID_ACCESSTOKEN = "AccessToken wygasł. Próba jego odświeżenia."
|
||||
MSG_PATH_ERR = "Ścieżka jest błędna!"
|
||||
MSG_INPUT_ERR = "Błąd wejścia!"
|
||||
|
||||
MODEL_ALBUM_PROPERTY = "ALBUM-WŁAŚCIWOŚĆ"
|
||||
MODEL_TRACK_PROPERTY = "UTWÓR-WŁAŚCIWOŚĆ"
|
||||
MODEL_VIDEO_PROPERTY = "WIDEO-WŁAŚCIWOŚĆ"
|
||||
MODEL_ARTIST_PROPERTY = "ARTYSTA-WŁAŚCIWOŚĆ"
|
||||
MODEL_PLAYLIST_PROPERTY = "PLAYLISTA-WŁAŚCIWOŚĆ"
|
||||
|
||||
MODEL_TITLE = 'Tytuł'
|
||||
MODEL_TRACK_NUMBER = 'Numer Utworu'
|
||||
MODEL_VIDEO_NUMBER = 'Numer Wideo'
|
||||
MODEL_RELEASE_DATE = 'Data Wydania'
|
||||
MODEL_VERSION = 'Wersja'
|
||||
MODEL_EXPLICIT = 'Jednoznaczny'
|
||||
MODEL_ALBUM = 'Album'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = 'Nazwa'
|
||||
MODEL_TYPE = 'Typ'
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : portuguese.py
|
||||
@Time : 2020/08/19
|
||||
@Author : BR8N0BL4CK & João
|
||||
@Version : 1.0
|
||||
@Contact :
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangPortuguese(object):
|
||||
SETTING = "Configurações"
|
||||
VALUE = "VALOR"
|
||||
SETTING_DOWNLOAD_PATH = "Caminho do download"
|
||||
SETTING_ONLY_M4A = "Converter mp4 para m4a"
|
||||
SETTING_ADD_EXPLICIT_TAG = "Adicionar etiqueta explícito"
|
||||
SETTING_ADD_HYPHEN = "Adicionar hífen"
|
||||
SETTING_ADD_YEAR = "Adicionar ano antes do nome do álbum na pasta"
|
||||
SETTING_USE_TRACK_NUM = "Adicionar Número da Faixa"
|
||||
SETTING_AUDIO_QUALITY = "Qualidade Do Áudio"
|
||||
SETTING_VIDEO_QUALITY = "Qualidade Do Vídeo"
|
||||
SETTING_CHECK_EXIST = "Verificar Existência"
|
||||
SETTING_ARTIST_BEFORE_TITLE = "ArtistaNome Antes do Track-Título"
|
||||
SETTING_ALBUMID_BEFORE_FOLDER = "Número De Identificação do Álbum antes na Pasta"
|
||||
SETTING_INCLUDE_EP = "Incluir Single & EP"
|
||||
SETTING_SAVE_COVERS = "Salvar Capas"
|
||||
SETTING_LANGUAGE = "idioma"
|
||||
SETTING_USE_PLAYLIST_FOLDER = "Usar pasta de lista de reprodução"
|
||||
SETTING_MULITHREAD_DOWNLOAD = "Download de vários tópicos"
|
||||
SETTING_ALBUM_FOLDER_FORMAT = "Formato da pasta do álbum"
|
||||
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
|
||||
SETTING_TRACK_FILE_FORMAT = "Track file format"
|
||||
SETTING_VIDEO_FILE_FORMAT = "Video file format"
|
||||
SETTING_SHOW_PROGRESS = "Mostrar progresso"
|
||||
SETTING_SHOW_TRACKINFO = "Mostrar informações da faixa"
|
||||
SETTING_SAVE_ALBUMINFO = "Salvar AlbumInfo.txt"
|
||||
SETTING_DOWNLOAD_VIDEOS = "Download videos"
|
||||
SETTING_ADD_LYRICS = "Adicionar Letra da Música"
|
||||
SETTING_LYRICS_SERVER_PROXY = "Proxy do servidor de letras"
|
||||
SETTING_ADD_LRC_FILE = "Salvar letras cronometradas (.lrc file)"
|
||||
SETTING_PATH = "Settings path"
|
||||
SETTING_APIKEY = "Suporte APIKey"
|
||||
SETTING_ADD_TYPE_FOLDER = "Adicionar tipo de pasta"
|
||||
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
|
||||
|
||||
CHOICE = "ESCOLHER"
|
||||
FUNCTION = "FUNÇÃO"
|
||||
CHOICE_ENTER = "Entrar"
|
||||
CHOICE_ENTER_URLID = "ADICIONAR 'Url/ID':"
|
||||
CHOICE_EXIT = "SAIR"
|
||||
CHOICE_LOGIN = "Verificar o token de acesso"
|
||||
CHOICE_SETTINGS = "Configurações"
|
||||
CHOICE_SET_ACCESS_TOKEN = "Adicionar Token de Acesso"
|
||||
CHOICE_DOWNLOAD_BY_URL = "Download Por url ou id"
|
||||
CHOICE_LOGOUT = "Logout"
|
||||
CHOICE_APIKEY = "Selecione a APIKey"
|
||||
|
||||
PRINT_ERR = "[ERRO]"
|
||||
PRINT_INFO = "[INFORMAÇÕES]"
|
||||
PRINT_SUCCESS = "[SUCESSO]"
|
||||
|
||||
PRINT_ENTER_CHOICE = "Entrar em Escolher:"
|
||||
PRINT_LATEST_VERSION = "Última Versão:"
|
||||
# PRINT_USERNAME = "Nome De Usuário:"
|
||||
# PRINT_PASSWORD = "Senha:"
|
||||
|
||||
CHANGE_START_SETTINGS = "Configurações Iniciais('0'-Retornar,'1'-Sim):"
|
||||
CHANGE_DOWNLOAD_PATH = "Caminho do download('0' Não Modificar):"
|
||||
CHANGE_AUDIO_QUALITY = "Qualidade De Áudio('0'-Normal,'1'-Alta,'2'-HiFi,'3'-Master,'4'-Max):"
|
||||
CHANGE_VIDEO_QUALITY = "Qualidade Do Vídeo(1080, 720, 480, 360):"
|
||||
CHANGE_ONLYM4A = "Converter mp4 para m4a('0'-Não,'1'-Sim):"
|
||||
CHANGE_ADD_EXPLICIT_TAG = "Adicionar Etiqueta Explícito para os nomes dos arquivos('0'-Não,'1'-Sim):"
|
||||
CHANGE_ADD_HYPHEN = "Usar hífen em vez de espaços nos nomes dos arquivos('0'-Não,'1'-Sim):"
|
||||
CHANGE_ADD_YEAR = "Adicionar Ano aos nomes das pastas dos álbums('0'-Não,'1'-Sim):"
|
||||
CHANGE_USE_TRACK_NUM = "Adicionar número da faixa antes do nome do arquivo('0'-Não,'1'-Sim):"
|
||||
CHANGE_CHECK_EXIST = "Verificar existência do arquivo antes de baixar a faixa('0'-Não,'1'-Sim):"
|
||||
CHANGE_ARTIST_BEFORE_TITLE = "Adicionar o nome do artista antes do título da faixa('0'-Não,'1'-Sim):"
|
||||
CHANGE_INCLUDE_EP = "Incluir singles e EPs quando baixar álbums de um artista('0'-Não,'1'-Sim):"
|
||||
CHANGE_ALBUMID_BEFORE_FOLDER = "Adicionar id antes no nome da pasta do álbum('0'-Não,'1'-Sim):"
|
||||
CHANGE_SAVE_COVERS = "Salvar Capas('0'-Não,'1'-Sim):"
|
||||
CHANGE_LANGUAGE = "Selecionar idioma"
|
||||
CHANGE_ALBUM_FOLDER_FORMAT = "Formato da pasta do álbum ('0' não modificar)"
|
||||
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
|
||||
CHANGE_TRACK_FILE_FORMAT = "Formato do arquivo de trilha ('0' não modificar):"
|
||||
CHANGE_VIDEO_FILE_FORMAT = "Video file format('0'-not modify,'default'-to set default):"
|
||||
CHANGE_SHOW_PROGRESS = "Mostrar progresso('0'-Não,'1'-Sim):"
|
||||
CHANGE_SHOW_TRACKINFO = "Mostrar informações da faixa('0'-Não,'1'-Sim):"
|
||||
CHANGE_SAVE_ALBUM_INFO = "Salvar AlbumInfo.txt('0'-Não,'1'-Sim):"
|
||||
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
|
||||
CHANGE_ADD_LYRICS = "Adicionar letras('0'-Não,'1'-Sim):"
|
||||
CHANGE_LYRICS_SERVER_PROXY = "Proxy do servidor de letras ('0' não modificar):"
|
||||
CHANGE_ADD_LRC_FILE = "Salvar arquivo .lrc de letras cronometradas ('0'-Não,'1'-Sim):"
|
||||
CHANGE_ADD_TYPE_FOLDER = "Adicionar Tipo de Pasta, por exemplo, Álbum/Vídeo/Lista de Reprodução('0'-Não,'1'-Sim):"
|
||||
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 = "Iniciando o processo de login..."
|
||||
AUTH_LOGIN_CODE = "Seu código de login é {}"
|
||||
AUTH_NEXT_STEP = "Vá para {} no próximo {} para concluir a configuração."
|
||||
AUTH_WAITING = "Espera da autorização..."
|
||||
AUTH_TIMEOUT = "A operação expirou."
|
||||
|
||||
MSG_VALID_ACCESSTOKEN = "Token de acesso bom por {}."
|
||||
MSG_INVALID_ACCESSTOKEN = "Token de acesso expirado. Tentando atualizá-lo."
|
||||
MSG_PATH_ERR = "Erro no local de salvamento dos arquivos!"
|
||||
MSG_INPUT_ERR = "Erro de Entrada!"
|
||||
|
||||
MODEL_ALBUM_PROPERTY = "ÁLBUM-PROPRIEDADE"
|
||||
MODEL_TRACK_PROPERTY = "FAIXA-PROPRIEDADE"
|
||||
MODEL_VIDEO_PROPERTY = "VÍDEO-PROPRIEDADE"
|
||||
MODEL_ARTIST_PROPERTY = "ARTISTA-PROPRIEDADE"
|
||||
MODEL_PLAYLIST_PROPERTY = "PLAYLIST-PPROPRIEDADE"
|
||||
|
||||
MODEL_TITLE = 'Título'
|
||||
MODEL_TRACK_NUMBER = 'Número Da Faixa'
|
||||
MODEL_VIDEO_NUMBER = 'Número Do Vídeo'
|
||||
MODEL_RELEASE_DATE = 'Data De Lançamento'
|
||||
MODEL_VERSION = 'Versão'
|
||||
MODEL_EXPLICIT = 'Explícito'
|
||||
MODEL_ALBUM = 'Álbum'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = 'Nome'
|
||||
MODEL_TYPE = 'Tipo'
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : russian.py
|
||||
@Time : 2020/11/29
|
||||
@Author : sergey.seve-s
|
||||
@Version : 1.0
|
||||
@Contact :
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangRussian(object):
|
||||
SETTING = "НАСТРОЙКА"
|
||||
VALUE = "УСТАНОВКА"
|
||||
SETTING_DOWNLOAD_PATH = "Место сохранения"
|
||||
SETTING_ONLY_M4A = "Сохранять mp4 как m4a"
|
||||
SETTING_ADD_EXPLICIT_TAG = "Добавить тег Нецензурно"
|
||||
SETTING_ADD_HYPHEN = "Добавить дефис"
|
||||
SETTING_ADD_YEAR = "Добавить год перед именем папки-альбома"
|
||||
SETTING_USE_TRACK_NUM = "Добавить номер трека"
|
||||
SETTING_AUDIO_QUALITY = "Качество аудио"
|
||||
SETTING_VIDEO_QUALITY = "Качество видео"
|
||||
SETTING_CHECK_EXIST = "Проверять наличие"
|
||||
SETTING_ARTIST_BEFORE_TITLE = "Исполнитель перед названием трека"
|
||||
SETTING_ALBUMID_BEFORE_FOLDER = "ID перед названием папки"
|
||||
SETTING_INCLUDE_EP = "Включить сингл и миньон"
|
||||
SETTING_SAVE_COVERS = "Добавлять обложку"
|
||||
SETTING_LANGUAGE = "Язык"
|
||||
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_TRACKINFO = "Show Track Info"
|
||||
SETTING_SAVE_ALBUMINFO = "Сохранять AlbumInfo.txt"
|
||||
SETTING_DOWNLOAD_VIDEOS = "Download videos"
|
||||
SETTING_ADD_LYRICS = "Добавлять текст песень"
|
||||
SETTING_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 = "Использовать ссылку для загрузки"
|
||||
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'-Стандарт,'1'-Высокое,'2'-HiFi,'3'-MQA,'4'-Max):"
|
||||
CHANGE_VIDEO_QUALITY = "Качество видео(1080, 720, 480, 360):"
|
||||
CHANGE_ONLYM4A = "Сохранять mp4 как m4a('0'-Нет,'1'-Да):"
|
||||
CHANGE_ADD_EXPLICIT_TAG = "Добавить тег 'Нецензурно' ('0'-Нет,'1'-Да):"
|
||||
CHANGE_ADD_HYPHEN = "Использовать дефис вместо пробела в имени трека('0'-Нет,'1'-Да):"
|
||||
CHANGE_ADD_YEAR = "Добавлять год перед названием альбома('0'-Нет,'1'-Да):"
|
||||
CHANGE_USE_TRACK_NUM = "Добавить номер перед названием трека('0'-Нет,'1'-Да):"
|
||||
CHANGE_CHECK_EXIST = "Проверять наличие перед загрузкой('0'-Нет,'1'-Да):"
|
||||
CHANGE_ARTIST_BEFORE_TITLE = "Добавить имя артиста перед названием трека('0'-Нет,'1'-Да):"
|
||||
CHANGE_INCLUDE_EP = "Включать синглы и миньоны в дискографию('0'-Нет'1'-Да):"
|
||||
CHANGE_ALBUMID_BEFORE_FOLDER = "Добавить ID перед названием альбома('0'-Нет,'1'-Да):"
|
||||
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 = "Video file format('0'-not modify,'default'-to set default):"
|
||||
CHANGE_SHOW_PROGRESS = "Показывать процесс загрузки('0'-Нет,'1'-Да):"
|
||||
CHANGE_SHOW_TRACKINFO = "Show track info('0'-No,'1'-Yes):"
|
||||
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'-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 = "Входим в сервис..."
|
||||
AUTH_LOGIN_CODE = "Ваш код для входа {}"
|
||||
AUTH_NEXT_STEP = "Перейдите к {} в течении {}, для завершения настройки."
|
||||
AUTH_WAITING = "Ожидание авторизации..."
|
||||
AUTH_TIMEOUT = "Закончилось время ожидания."
|
||||
|
||||
MSG_VALID_ACCESSTOKEN = "AccessToken успешно применён {}."
|
||||
MSG_INVALID_ACCESSTOKEN = "Срок действия AccessToken истек. Попытка обновления."
|
||||
MSG_PATH_ERR = "Неверное место!"
|
||||
MSG_INPUT_ERR = "Ошибка ввода!"
|
||||
|
||||
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 = 'Название'
|
||||
MODEL_TRACK_NUMBER = 'Номер трека'
|
||||
MODEL_VIDEO_NUMBER = 'Номер видео'
|
||||
MODEL_RELEASE_DATE = 'Дата издания'
|
||||
MODEL_VERSION = 'Версия'
|
||||
MODEL_EXPLICIT = 'Нецензурно'
|
||||
MODEL_ALBUM = 'Альбом'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = 'Имя'
|
||||
MODEL_TYPE = 'Тип'
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : spanish.py
|
||||
@Time : 2022/07/07
|
||||
@Author : Frikilinux & JavierSC
|
||||
@Version : 2.3
|
||||
@Contact :
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangSpanish(object):
|
||||
SETTING = "AJUSTES"
|
||||
VALUE = "VALORES"
|
||||
SETTING_DOWNLOAD_PATH = "Ruta de descarga"
|
||||
SETTING_ONLY_M4A = "Convertir mp4 a m4a"
|
||||
SETTING_ADD_EXPLICIT_TAG = "Agregar etiqueta de 'Contenido explícito'"
|
||||
SETTING_ADD_HYPHEN = "Agregar guión"
|
||||
SETTING_ADD_YEAR = "Agregar año en la carpeta del álbum"
|
||||
SETTING_USE_TRACK_NUM = "Agregar número de la pista"
|
||||
SETTING_AUDIO_QUALITY = "Calidad de audio"
|
||||
SETTING_VIDEO_QUALITY = "Calidad de video"
|
||||
SETTING_CHECK_EXIST = "Verificar si existe"
|
||||
SETTING_ARTIST_BEFORE_TITLE = "Nombre del artista en el título de la pista"
|
||||
SETTING_ALBUMID_BEFORE_FOLDER = "Añadir ID de la carpeta del álbum"
|
||||
SETTING_INCLUDE_EP = "Incluir sencillos y EPs"
|
||||
SETTING_SAVE_COVERS = "Guardar carátulas"
|
||||
SETTING_LANGUAGE = "Idioma"
|
||||
SETTING_USE_PLAYLIST_FOLDER = "Usar directorio de la lista de reproducción"
|
||||
SETTING_MULITHREAD_DOWNLOAD = "Descarga Multi-hilo"
|
||||
SETTING_ALBUM_FOLDER_FORMAT = "Formato del nombre de carpeta del álbum"
|
||||
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
|
||||
SETTING_TRACK_FILE_FORMAT = "Formato del nombre de archivo de la pista"
|
||||
SETTING_VIDEO_FILE_FORMAT = "Video file format"
|
||||
SETTING_SHOW_PROGRESS = "Mostrar progreso"
|
||||
SETTING_SHOW_TRACKINFO = "Mostrar información de pista"
|
||||
SETTING_SAVE_ALBUMINFO = "Guardar AlbumInfo.txt"
|
||||
SETTING_DOWNLOAD_VIDEOS = "Download videos"
|
||||
SETTING_ADD_LYRICS = "Añadir letras"
|
||||
SETTING_LYRICS_SERVER_PROXY = "Proxy del servidor de letras"
|
||||
SETTING_ADD_LRC_FILE = "Añadir letras cronometradas (archivo .lrc)"
|
||||
SETTING_PATH = "Ruta de ajustes"
|
||||
SETTING_APIKEY = "Soporte de la APIKey"
|
||||
SETTING_ADD_TYPE_FOLDER = "Añadir tipo de carpeta"
|
||||
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
|
||||
|
||||
CHOICE = "SELECCIÓN"
|
||||
FUNCTION = "FUNCIÓN"
|
||||
CHOICE_ENTER = "Ingresar"
|
||||
CHOICE_ENTER_URLID = "Ingresar 'Url/ID':"
|
||||
CHOICE_EXIT = "Salir"
|
||||
CHOICE_LOGIN = "Verificar el token de acceso"
|
||||
CHOICE_SETTINGS = "Ajustes"
|
||||
CHOICE_SET_ACCESS_TOKEN = "Establecer AccessToken"
|
||||
CHOICE_DOWNLOAD_BY_URL = "Descargar por Url o ID"
|
||||
CHOICE_LOGOUT = "Cerrar sesión"
|
||||
CHOICE_APIKEY = "Seleccionar APIKey"
|
||||
|
||||
PRINT_ERR = "[ERROR]"
|
||||
PRINT_INFO = "[INFO]"
|
||||
PRINT_SUCCESS = "[ÉXITO]"
|
||||
|
||||
PRINT_ENTER_CHOICE = "Ingresar Selección:"
|
||||
PRINT_LATEST_VERSION = "Última versión:"
|
||||
# PRINT_USERNAME = "nombre de usuario:"
|
||||
# PRINT_PASSWORD = "contraseña:"
|
||||
|
||||
CHANGE_START_SETTINGS = "¿Iniciar ajustes? ('0'-Volver,'1'-Sí):"
|
||||
CHANGE_DOWNLOAD_PATH = "Ruta de descarga ('0' No modificar):"
|
||||
CHANGE_AUDIO_QUALITY = "Calidad de audio ('0'-Normal,'1'-High,'2'-HiFi,'3'-Master,'4'-Max):"
|
||||
CHANGE_VIDEO_QUALITY = "Calidad de video (1080, 720, 480, 360):"
|
||||
CHANGE_ONLYM4A = "¿Convertir mp4 a m4a? ('0'-No,'1'-Sí):"
|
||||
CHANGE_ADD_EXPLICIT_TAG = "¿Agregar etiqueta de contenido explícito a los nombres de archivo? ('0'-No,'1'-Sí):"
|
||||
CHANGE_ADD_HYPHEN = "¿Usar guiones en lugar de espacios en el nombre de los archivos? ('0'-No,'1'-Sí):"
|
||||
CHANGE_ADD_YEAR = "¿Agregar año a el nombre de las carpetas del álbum? ('0'-No,'1'-Sí):"
|
||||
CHANGE_USE_TRACK_NUM = "¿Agregar número de la pista? ('0'-No,'1'-Sí):"
|
||||
CHANGE_CHECK_EXIST = "¿Verificar si el archivo existe antes de descargar la pista? ('0'-No,'1'-Sí):"
|
||||
CHANGE_ARTIST_BEFORE_TITLE = "¿Añadir el nombre del artista en el título de la pista? ('0'-No,'1'-Sí):"
|
||||
CHANGE_INCLUDE_EP = "¿Incluir Sencillos y EPs al descargar el álbum del artista? ('0'-No,'1'-Sí):"
|
||||
CHANGE_ALBUMID_BEFORE_FOLDER = "¿Añadir ID de la carpeta del álbum? ('0'-No,'1'-Sí):"
|
||||
CHANGE_SAVE_COVERS = "¿Guardar carátulas?('0'-No,'1'-Sí):"
|
||||
CHANGE_LANGUAGE = "Seleccione el idioma"
|
||||
CHANGE_ALBUM_FOLDER_FORMAT = "Formato del nombre de carpeta del álbum ('0' No modificar):"
|
||||
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
|
||||
CHANGE_TRACK_FILE_FORMAT = "Formato del nombre de archivo de la pista ('0' No modificar):"
|
||||
CHANGE_VIDEO_FILE_FORMAT = "Formato del archivo de video('0'-No modificar,'default'-por defecto):"
|
||||
CHANGE_SHOW_PROGRESS = "¿Mostrar progreso? ('0'-No,'1'-Sí):"
|
||||
CHANGE_SHOW_TRACKINFO = "¿Mostrar información de pista?('0'-No,'1'-Sí):"
|
||||
CHANGE_SAVE_ALBUM_INFO = "¿Guardar AlbumInfo.txt?('0'-No,'1'-Sí):"
|
||||
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
|
||||
CHANGE_ADD_LYRICS = "¿Añadir letras?('0'-No,'1'-Sí):"
|
||||
CHANGE_LYRICS_SERVER_PROXY = "¿Proxy del servidor de letras?('0' no modificar):"
|
||||
CHANGE_ADD_LRC_FILE = "¿Añadir letras cronometradas en un archivo .lrc? ('0'-No,'1'-Sí):"
|
||||
CHANGE_ADD_TYPE_FOLDER = "Añadir tipo de carpeta, ej: Album/Video/Playlist('0'-No,'1'-Sí):"
|
||||
CHANGE_MULITHREAD_DOWNLOAD = "¿Descarga Multi-hilo?('0'-No,'1'-Sí:"
|
||||
CHANGE_USE_DOWNLOAD_DELAY = "Use Download Delay('0'-No,'1'-Yes):"
|
||||
|
||||
# {} are required in these strings
|
||||
AUTH_START_LOGIN = "Iniciando sesión..."
|
||||
AUTH_LOGIN_CODE = "Su código para autorizar la sesión es {}"
|
||||
AUTH_NEXT_STEP = "Diríjase a {} en los próximos {} para completar la autorización."
|
||||
AUTH_WAITING = "Esperando la autorización..."
|
||||
AUTH_TIMEOUT = "Se superó el tiempo de espera."
|
||||
|
||||
MSG_VALID_ACCESSTOKEN = "Token de acceso válido por {}."
|
||||
MSG_INVALID_ACCESSTOKEN = "El token de acceso ha expirado. Tratando de renovarlo."
|
||||
MSG_PATH_ERR = "¡La ruta no es correcta!"
|
||||
MSG_INPUT_ERR = "¡Error de entrada!"
|
||||
|
||||
MODEL_ALBUM_PROPERTY = "PROPIEDAD-DE-ÁLBUM"
|
||||
MODEL_TRACK_PROPERTY = "PROPIEDAD-DE-PISTA"
|
||||
MODEL_VIDEO_PROPERTY = "PROPIEDAD-DE-VIDEO"
|
||||
MODEL_ARTIST_PROPERTY = "PROPIEDAD-DE-ARTISTA"
|
||||
MODEL_PLAYLIST_PROPERTY = "PROPIEDAD-DE-PLAYLIST"
|
||||
|
||||
MODEL_TITLE = 'Título'
|
||||
MODEL_TRACK_NUMBER = 'Número de pistas'
|
||||
MODEL_VIDEO_NUMBER = 'Número de videos'
|
||||
MODEL_RELEASE_DATE = 'Fecha de lanzamiento'
|
||||
MODEL_VERSION = 'Versión'
|
||||
MODEL_EXPLICIT = 'Explícito'
|
||||
MODEL_ALBUM = 'Álbum'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = 'Nombre'
|
||||
MODEL_TYPE = 'Tipo'
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : turkish.py
|
||||
@Time : 2020/09/13
|
||||
@Author : Gorgeous & shhade for hack & Mutlu ŞEN
|
||||
@Version : 1.0
|
||||
@Contact : realmutlusen@gmail.com
|
||||
@Desc : Yanlış çeviri ya da düzenleme için 'realmutlusen@gmail.com'a mail atabilirsiniz.
|
||||
'''
|
||||
|
||||
|
||||
class LangTurkish(object):
|
||||
SETTING = "AYARLAR"
|
||||
VALUE = "VERİLER"
|
||||
SETTING_DOWNLOAD_PATH = "İndirme konumu:"
|
||||
SETTING_ONLY_M4A = ".mp4 uzantısı m4a'ya çevrilsin:"
|
||||
SETTING_ADD_EXPLICIT_TAG = "'Küfürlü' etiketi eklensin:"
|
||||
SETTING_ADD_HYPHEN = "Boşluk yerine '-' eklensin:"
|
||||
SETTING_ADD_YEAR = "Yıl eklensin:"
|
||||
SETTING_USE_TRACK_NUM = "Artist numarası eklensin:"
|
||||
SETTING_AUDIO_QUALITY = "Ses kalitesi:"
|
||||
SETTING_VIDEO_QUALITY = "Video kalitesi:"
|
||||
SETTING_CHECK_EXIST = "İndirilmiş mi diye kontrol edilsin:"
|
||||
SETTING_ARTIST_BEFORE_TITLE = "Artist adı eklensin:"
|
||||
SETTING_ALBUMID_BEFORE_FOLDER = "ID eklensin:"
|
||||
SETTING_INCLUDE_EP = "Single'leri ve EP'leri dahil edisin:"
|
||||
SETTING_SAVE_COVERS = "Albüm kapağı indirilsin:"
|
||||
SETTING_LANGUAGE = "Kullanılan lisan:"
|
||||
SETTING_USE_PLAYLIST_FOLDER = "Albümler klasör halinde indirilsin mi ?"
|
||||
SETTING_MULITHREAD_DOWNLOAD = "Şarkılar tek tek indirilsin mi?"
|
||||
SETTING_ALBUM_FOLDER_FORMAT = "Klasör ismi formatı:"
|
||||
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
|
||||
SETTING_TRACK_FILE_FORMAT = "Dosya ismi formatı:"
|
||||
SETTING_VIDEO_FILE_FORMAT = "Video file format"
|
||||
SETTING_SHOW_PROGRESS = "İndirme Çubuğu Görüntüleme:"
|
||||
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 = "Seçim"
|
||||
FUNCTION = "İşlemler"
|
||||
CHOICE_ENTER = "Enter"
|
||||
CHOICE_ENTER_URLID = "'Url/ID' Gir:"
|
||||
CHOICE_EXIT = "Çıkış"
|
||||
CHOICE_LOGIN = "AccessToken kontrolü"
|
||||
CHOICE_SETTINGS = "Ayarlar'ı Düzenle"
|
||||
CHOICE_SET_ACCESS_TOKEN = "'AccessToken' Gir"
|
||||
CHOICE_DOWNLOAD_BY_URL = "URL ya da ID ile indir"
|
||||
CHOICE_LOGOUT = "Çıkış"
|
||||
CHOICE_APIKEY = "Select APIKey"
|
||||
|
||||
PRINT_ERR = "[HATA OLUŞTU]"
|
||||
PRINT_INFO = "[BİLGİ]"
|
||||
PRINT_SUCCESS = "[İNDİRİLDİ]"
|
||||
|
||||
PRINT_ENTER_CHOICE = "Seçim Gir: "
|
||||
PRINT_LATEST_VERSION = "Güncelleme Mevcut:"
|
||||
# PRINT_USERNAME = "Kullanıcı Adı ya da Mail Adresi:"
|
||||
# PRINT_PASSWORD = "Şifre:"
|
||||
|
||||
CHANGE_START_SETTINGS = ">>> Ayarları düzenlemek istediğine emin misin ? ('0'-Geri Dön,'1'-Evet): "
|
||||
CHANGE_DOWNLOAD_PATH = ">>> İndirme Konumu ('0' aynı kalsın): "
|
||||
CHANGE_AUDIO_QUALITY = ">>> Ses Kalitesi ('0'-Normal,'1'-Yüksek,'2'-HiFi,'3'-[M]aster,'4'-Max): "
|
||||
CHANGE_VIDEO_QUALITY = ">>> Video Kalitesi (1080, 720, 480, 360): "
|
||||
CHANGE_ONLYM4A = ">>> .mp4 uzantılı dosyalar .m4a'ya çevrilsin mi?('0'-Hayır,'1'-Evet): "
|
||||
CHANGE_ADD_EXPLICIT_TAG = ">>> 'Explicit' yani 'küfürlü' etiketi eklensin mi?('0'-Hayır,'1'-Evet): "
|
||||
CHANGE_ADD_HYPHEN = ">>> Şarkı dosyasının isminde boşluk yerine '-' eklensin mi ?('0'-Hayır,'1'-Evet): "
|
||||
CHANGE_ADD_YEAR = ">>> Albüm klasörünün isminde yıl olsun mu ?('0'-Hayır,'1'-Evet): "
|
||||
CHANGE_USE_TRACK_NUM = ">>> Şarkı dosyasının isminde albümdeki sırası yazsın mı ?('0'-Hayır,'1'-Evet): "
|
||||
CHANGE_CHECK_EXIST = ">>> Dosya daha önce indirilmiş mi diye kontrol edilsin mi ?('0'-Hayır,'1'-Evet): "
|
||||
CHANGE_ARTIST_BEFORE_TITLE = ">>> Şarkı dosyasının ismine sanatçının adı eklensin mi?('0'-Hayır,'1'-Evet): "
|
||||
CHANGE_INCLUDE_EP = ">>> Artist'in tüm albümlerini indirirken Single'leri ve EP'leri de dahil edilsin mi ?('0'-Hayır,'1'-Evet): "
|
||||
CHANGE_ALBUMID_BEFORE_FOLDER = ">>> Albüm klasörünün ismine ID eklensin mi ?('0'-Hayır,'1'-Evet): "
|
||||
CHANGE_SAVE_COVERS = ">>> Albüm kapağı indirilsin mi?('0'-Hayır,'1'-Evet): "
|
||||
CHANGE_LANGUAGE = ">>> Lisan Seç "
|
||||
CHANGE_ALBUM_FOLDER_FORMAT = "Albüm Klasör İsmi Formatı('0' aynı kalsın):"
|
||||
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
|
||||
CHANGE_TRACK_FILE_FORMAT = "Dosya İsmi Formatı('0' aynı kalsın):"
|
||||
CHANGE_VIDEO_FILE_FORMAT = "Video file format('0'-not modify,'default'-to set default):"
|
||||
CHANGE_SHOW_PROGRESS = "İndirme Çubuğu Görüntülensin mi?('0'-Hayır,'1'-Evet):"
|
||||
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 = "Giriş işlemleri başlatıldı..."
|
||||
AUTH_LOGIN_CODE = "Girmen gereken kod: {}"
|
||||
AUTH_NEXT_STEP = "Bu siteden {} hesabınıza giriş yapınız ve üstteki kodu giriniz. ({} dakikanız var.)"
|
||||
AUTH_WAITING = "İşlemleri tamamlamanız bekleniyor..."
|
||||
AUTH_TIMEOUT = "Lütfen size verilen süre içerisinde işlemleriniz tamamlayınız."
|
||||
|
||||
MSG_VALID_ACCESSTOKEN = "AccessToken good for {}."
|
||||
MSG_INVALID_ACCESSTOKEN = "Expired AccessToken. Attempting to refresh it."
|
||||
MSG_PATH_ERR = "İndirme konumu ile alakalı bir sorun var! ('/storage/emulated/0/Download/' şeklinde girebilirsiniz.)"
|
||||
MSG_INPUT_ERR = "Giriş Hatalı!"
|
||||
|
||||
MODEL_ALBUM_PROPERTY = "ALBÜM-BİLGİLERİ"
|
||||
MODEL_TRACK_PROPERTY = "ŞARKI-BİLGİLERİ"
|
||||
MODEL_VIDEO_PROPERTY = "VİDEO-BİLGİLERİ"
|
||||
MODEL_ARTIST_PROPERTY = "ARTİST-BİLGİLERİ"
|
||||
MODEL_PLAYLIST_PROPERTY = "OYNATMA LİSTESİ-BİLGİLERİ"
|
||||
|
||||
MODEL_TITLE = 'Şarkı/Albüm Adı:'
|
||||
MODEL_TRACK_NUMBER = 'Şarkı Sayısı'
|
||||
MODEL_VIDEO_NUMBER = 'Video Sayısı'
|
||||
MODEL_RELEASE_DATE = 'Çıkış Yılı:'
|
||||
MODEL_VERSION = 'Versiyon'
|
||||
MODEL_EXPLICIT = 'Küfürlü'
|
||||
MODEL_ALBUM = 'Albüm'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = 'İsim'
|
||||
MODEL_TYPE = 'Türü'
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : ukrainian.py
|
||||
@Time : 2022/02/20
|
||||
@Author : Montyzzz & 9uyone
|
||||
@Version : 1.2
|
||||
@Contact : ---
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangUkrainian(object):
|
||||
SETTING = "НАЛАШТУВАННЯ"
|
||||
VALUE = "ЗНАЧЕННЯ"
|
||||
SETTING_DOWNLOAD_PATH = "Шлях завантаження"
|
||||
SETTING_ONLY_M4A = "Перетворювати mp4 на m4a"
|
||||
SETTING_ADD_EXPLICIT_TAG = "Додавати тег Нецензурно"
|
||||
SETTING_ADD_HYPHEN = "Додавати дефіс"
|
||||
SETTING_ADD_YEAR = "Додавати рік перед ім'ям папки альбому"
|
||||
SETTING_USE_TRACK_NUM = "Додавати номер треку"
|
||||
SETTING_AUDIO_QUALITY = "Якість аудіо"
|
||||
SETTING_VIDEO_QUALITY = "Якість відео"
|
||||
SETTING_CHECK_EXIST = "Перевіряти наявність"
|
||||
SETTING_ARTIST_BEFORE_TITLE = "Виконавець перед назвою треку"
|
||||
SETTING_ALBUMID_BEFORE_FOLDER = "ID перед назвою папки"
|
||||
SETTING_INCLUDE_EP = "Включати сингли та міньйони (EP)"
|
||||
SETTING_SAVE_COVERS = "Зберігати обкладинки"
|
||||
SETTING_LANGUAGE = "Мова"
|
||||
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_TRACKINFO = "Показувати інформацію про трек"
|
||||
SETTING_SAVE_ALBUMINFO = "Зберігати AlbumInfo.txt"
|
||||
SETTING_DOWNLOAD_VIDEOS = "Download videos"
|
||||
SETTING_ADD_LYRICS = "Додавати тексти пісень"
|
||||
SETTING_LYRICS_SERVER_PROXY = "Проксі для сервера з текстами пісень"
|
||||
SETTING_ADD_LRC_FILE = "Зберігати тексти з відмітками часу (.lrc файл)"
|
||||
SETTING_PATH = "Шлях налаштувань"
|
||||
SETTING_APIKEY = "Підтримка ключа API"
|
||||
SETTING_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-адресою або ідентифікатором"
|
||||
CHOICE_LOGOUT = "Деавторизація"
|
||||
CHOICE_APIKEY = "Вибрати ключ API"
|
||||
|
||||
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'-Звичайна,'1'-Висока,'2'-HiFi,'3'-MQA,'4'-Max):"
|
||||
CHANGE_VIDEO_QUALITY = "Якість відео(1080,720,480,360):"
|
||||
CHANGE_ONLYM4A = "Перетворювати mp4 на m4a('0'-Ні,'1'-Так):"
|
||||
CHANGE_ADD_EXPLICIT_TAG = "Додавати тег 'Нецензурно'('0'-Ні,'1'-Так):"
|
||||
CHANGE_ADD_HYPHEN = "Використати дефіс замість пробілів в іменах файлів('0'-Ні,'1'-Так):"
|
||||
CHANGE_ADD_YEAR = "Додавати рік до назв тек альбомів('0'-Ні,'1'-Так):"
|
||||
CHANGE_USE_TRACK_NUM = "Додавати номер доріжки перед назвами файлів('0'-Ні,'1'-Так):"
|
||||
CHANGE_CHECK_EXIST = "Перевіряти наявний файл перед завантаженням треку('0'-Ні,'1'-Так):"
|
||||
CHANGE_ARTIST_BEFORE_TITLE = "Додати ім’я виконавця перед заголовком треку('0'-Ні,'1'-Так):"
|
||||
CHANGE_INCLUDE_EP = "Включати сингли та міньйони під час завантаження альбомів виконавця('0'-Ні,'1'-Так):"
|
||||
CHANGE_ALBUMID_BEFORE_FOLDER = "Додати ідентифікатор перед текою альбому('0'-Ні,'1'-Так):"
|
||||
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 = "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_ADD_TYPE_FOLDER = "Додавати теку-тип,наприклад Альбом/Відео/Плейлист('0'-Ні,'1'-Так):"
|
||||
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 = "Початок процесу авторизації..."
|
||||
AUTH_LOGIN_CODE = "Ваш логін-код: {}"
|
||||
AUTH_NEXT_STEP = "Зайдіть на {} протягом наступних {} для завершення налаштування."
|
||||
AUTH_WAITING = "Очікування авторизації..."
|
||||
AUTH_TIMEOUT = "Час очікування минув."
|
||||
|
||||
MSG_VALID_ACCESSTOKEN = "AccessToken хороший упродовж {}."
|
||||
MSG_INVALID_ACCESSTOKEN = "Термін дії AccessToken'а закінчився. Пробуємо оновити його."
|
||||
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 = 'Нецензурно'
|
||||
MODEL_ALBUM = 'Альбом'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = 'Ім\'я'
|
||||
MODEL_TYPE = 'Тип'
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : vietnamese.py
|
||||
@Time : 2022/2/9
|
||||
@Author : MinhNgo, CDzungx
|
||||
@Version : 1.0
|
||||
@Contact : iam.minhnc@outlook.com
|
||||
@Desc :
|
||||
'''
|
||||
|
||||
|
||||
class LangVietnamese(object):
|
||||
SETTING = "THIẾT LẬP"
|
||||
VALUE = "GIÁ TRỊ"
|
||||
SETTING_DOWNLOAD_PATH = "Đường dẫn tải về"
|
||||
SETTING_ONLY_M4A = "Đổi mp4 sang m4a"
|
||||
SETTING_ADD_EXPLICIT_TAG = "Thêm tag explicit"
|
||||
SETTING_ADD_HYPHEN = "Thêm dấu nối"
|
||||
SETTING_ADD_YEAR = "Thêm năm trước thư mục album"
|
||||
SETTING_USE_TRACK_NUM = "Thêm số thứ tự bài"
|
||||
SETTING_AUDIO_QUALITY = "Chất lượng âm thanh"
|
||||
SETTING_VIDEO_QUALITY = "Chất lượng video"
|
||||
SETTING_CHECK_EXIST = "Kiểm tra tồn tại"
|
||||
SETTING_ARTIST_BEFORE_TITLE = "Tên nghệ sĩ phía trước tựa bài hát"
|
||||
SETTING_ALBUMID_BEFORE_FOLDER = "Id trước thư mục album"
|
||||
SETTING_INCLUDE_EP = "Bao gồm đĩa đơn & ep"
|
||||
SETTING_SAVE_COVERS = "Tải ảnh bìa"
|
||||
SETTING_LANGUAGE = "Ngôn ngữ"
|
||||
SETTING_USE_PLAYLIST_FOLDER = "Thư mục cho danh sách phát"
|
||||
SETTING_MULITHREAD_DOWNLOAD = "Tải về đa luồng"
|
||||
SETTING_ALBUM_FOLDER_FORMAT = "Định dạng thư mục album"
|
||||
SETTING_PLAYLIST_FOLDER_FORMAT = "Playlist folder format"
|
||||
SETTING_TRACK_FILE_FORMAT = "Định dạng tên tệp nhạc"
|
||||
SETTING_VIDEO_FILE_FORMAT = "Video file format"
|
||||
SETTING_SHOW_PROGRESS = "Hiện tiến trình"
|
||||
SETTING_SHOW_TRACKINFO = "Hiện thông tin bài"
|
||||
SETTING_SAVE_ALBUMINFO = "Lưu AlbumInfo.txt"
|
||||
SETTING_DOWNLOAD_VIDEOS = "Download videos"
|
||||
SETTING_ADD_LYRICS = "Thêm lời bài hát"
|
||||
SETTING_LYRICS_SERVER_PROXY = "Máy chủ proxy cho lyrics"
|
||||
SETTING_ADD_LRC_FILE = "Lưu timed lyrics (tệp .lrc)"
|
||||
SETTING_PATH = "Đường dẫn cài đặt"
|
||||
SETTING_APIKEY = "Hỗ trợ APIKey"
|
||||
SETTING_ADD_TYPE_FOLDER = "Thêm Loại-Thư mục"
|
||||
SETTING_DOWNLOAD_DELAY = "Use Download Delay"
|
||||
|
||||
CHOICE = "LỰA CHỌN"
|
||||
FUNCTION = "CHỨC NĂNG"
|
||||
CHOICE_ENTER = "Nhập"
|
||||
CHOICE_ENTER_URLID = "Nhập 'Url/ID':"
|
||||
CHOICE_EXIT = "Thoát"
|
||||
CHOICE_LOGIN = "Kiểm tra AccessToken"
|
||||
CHOICE_SETTINGS = "Thiết lập"
|
||||
CHOICE_SET_ACCESS_TOKEN = "Nhập AccessToken"
|
||||
CHOICE_DOWNLOAD_BY_URL = "Tải về qua url hoặc id"
|
||||
CHOICE_LOGOUT = "Đăng xuất"
|
||||
CHOICE_APIKEY = "Chọn APIKey"
|
||||
|
||||
PRINT_ERR = "[LỖI]"
|
||||
PRINT_INFO = "[THÔNG TIN]"
|
||||
PRINT_SUCCESS = "[XONG]"
|
||||
|
||||
PRINT_ENTER_CHOICE = "Nhập lựa chọn:"
|
||||
PRINT_LATEST_VERSION = "Bản mới nhất:"
|
||||
# PRINT_USERNAME = "tên đăng nhập:"
|
||||
# PRINT_PASSWORD = "mật khẩu:"
|
||||
|
||||
CHANGE_START_SETTINGS = "Bắt đầu thiết lập('0'-Về,'1'-Có):"
|
||||
CHANGE_DOWNLOAD_PATH = "Đường dẫn tải về('0' không đổi):"
|
||||
CHANGE_AUDIO_QUALITY = "Chất lượng âm thanh('0'-Normal,'1'-High,'2'-HiFi,'3'-Master,'4'-Max):"
|
||||
CHANGE_VIDEO_QUALITY = "Chất lượng video(1080, 720, 480, 360):"
|
||||
CHANGE_ONLYM4A = "Đổi mp4 sang m4a('0'-Không,'1'-Có):"
|
||||
CHANGE_ADD_EXPLICIT_TAG = "Thêm tag explicit vào tên tệp('0'-Không,'1'-Có):"
|
||||
CHANGE_ADD_HYPHEN = "Dùng gạch nối thay vì dấu cách trong tên tệp('0'-Không,'1'-Có):"
|
||||
CHANGE_ADD_YEAR = "Thêm năm phía trước tên thư mục album('0'-Không,'1'-Có):"
|
||||
CHANGE_USE_TRACK_NUM = "Thêm số thứ tự bài ở đầu tên tệp('0'-Không,'1'-Có):"
|
||||
CHANGE_CHECK_EXIST = "Kiểm tra tệp đã tồn tại chưa trước khi tải('0'-Không,'1'-Có):"
|
||||
CHANGE_ARTIST_BEFORE_TITLE = "Thêm tên nghệ sĩ trước tựa đề('0'-Không,'1'-Có):"
|
||||
CHANGE_INCLUDE_EP = "Bao gồm đĩa đơn và EPs khi tải tất cả nhạc của nghệ sĩ('0'-Không,'1'-Có):"
|
||||
CHANGE_ALBUMID_BEFORE_FOLDER = "Thêm id phía trước tên thư mục album('0'-Không,'1'-Có):"
|
||||
CHANGE_SAVE_COVERS = "Tải ảnh bìa('0'-Không,'1'-Có):"
|
||||
CHANGE_LANGUAGE = "Chọn ngôn ngữ"
|
||||
CHANGE_ALBUM_FOLDER_FORMAT = "Định dạng thư mục album('0' không đổi,'default' để đặt về mặc định):"
|
||||
CHANGE_PLAYLIST_FOLDER_FORMAT = "Playlist folder format('0'-not modify,'default'-to set default):"
|
||||
CHANGE_TRACK_FILE_FORMAT = "Định dạng tên tệp nhạc('0' không đổi,'default' để đặt về mặc định):"
|
||||
CHANGE_VIDEO_FILE_FORMAT = "Video file format('0'-not modify,'default'-to set default):"
|
||||
CHANGE_SHOW_PROGRESS = "Hiện tiến trình('0'-Không,'1'-Có):"
|
||||
CHANGE_SHOW_TRACKINFO = "Hiện thông tin bài('0'-Không,'1'-Có):"
|
||||
CHANGE_SAVE_ALBUM_INFO = "Lưu AlbumInfo.txt('0'-Không,'1'-Có):"
|
||||
CHANGE_DOWNLOAD_VIDEOS = "Download videos (when downloading playlists, albums, mixes)('0'-No,'1'-Yes):"
|
||||
CHANGE_ADD_LYRICS = "Thêm lời bài hát('0'-Không,'1'-Có):"
|
||||
CHANGE_LYRICS_SERVER_PROXY = "Máy chủ proxy cho lyrics('0' không đổi):"
|
||||
CHANGE_ADD_LRC_FILE = "Lưu timed lyrics tệp .lrc ('0'-Không,'1'-Có):"
|
||||
CHANGE_ADD_TYPE_FOLDER = "Thêm Loại-Thư mục, ví dụ Album/Video/Playlist('0'-Không,'1'-Có):"
|
||||
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 = "Đang bắt đầu đăng nhập..."
|
||||
AUTH_LOGIN_CODE = "Mã đăng nhập của bạn là {}"
|
||||
AUTH_NEXT_STEP = "Vào trang {} trong vòng {} để hoàn tất thiết lập."
|
||||
AUTH_WAITING = "Đang chờ xác minh..."
|
||||
AUTH_TIMEOUT = "Đã vượt quá thời gian chờ."
|
||||
|
||||
MSG_VALID_ACCESSTOKEN = "AccessToken vẫn tốt trong {}."
|
||||
MSG_INVALID_ACCESSTOKEN = "AccessToken hết hạn. Đang cố làm mới."
|
||||
MSG_PATH_ERR = "Lỗi đường dẫn!"
|
||||
MSG_INPUT_ERR = "Lỗi nhập!"
|
||||
|
||||
MODEL_ALBUM_PROPERTY = "THÔNG-TIN-ALBUM"
|
||||
MODEL_TRACK_PROPERTY = "THÔNG-TIN-BÀI"
|
||||
MODEL_VIDEO_PROPERTY = "THÔNG-TIN-VIDEO"
|
||||
MODEL_ARTIST_PROPERTY = "THÔNG-TIN-NGHỆ-SĨ"
|
||||
MODEL_PLAYLIST_PROPERTY = "THÔNG-TIN-DANH-SÁCH-PHÁT"
|
||||
|
||||
MODEL_TITLE = 'Tựa Đề'
|
||||
MODEL_TRACK_NUMBER = 'Số Bài'
|
||||
MODEL_VIDEO_NUMBER = 'Số Video'
|
||||
MODEL_RELEASE_DATE = 'Ngày Phát Hành'
|
||||
MODEL_VERSION = 'Phiên Bản'
|
||||
MODEL_EXPLICIT = 'Explicit'
|
||||
MODEL_ALBUM = 'Album'
|
||||
MODEL_ID = 'ID'
|
||||
MODEL_NAME = 'Tên'
|
||||
MODEL_TYPE = 'Loại'
|
||||
@@ -0,0 +1,208 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : model.py
|
||||
@Time : 2020/08/08
|
||||
@Author : Yaronzz
|
||||
@Version : 3.0
|
||||
@Contact : yaronhuang@foxmail.com
|
||||
@Desc :
|
||||
'''
|
||||
import aigpy
|
||||
|
||||
class StreamUrl(aigpy.model.ModelBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.trackid = None
|
||||
self.url = None
|
||||
self.urls = None
|
||||
self.codec = None
|
||||
self.encryptionKey = None
|
||||
self.soundQuality = None
|
||||
|
||||
|
||||
class VideoStreamUrl(aigpy.model.ModelBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.codec = None
|
||||
self.resolution = None
|
||||
self.resolutions = None
|
||||
self.m3u8Url = None
|
||||
|
||||
|
||||
class Artist(aigpy.model.ModelBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.id = None
|
||||
self.name = None
|
||||
self.type = None
|
||||
self.picture = None
|
||||
|
||||
|
||||
class Album(aigpy.model.ModelBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.id = None
|
||||
self.title = None
|
||||
self.duration = 0
|
||||
self.numberOfTracks = 0
|
||||
self.numberOfVideos = 0
|
||||
self.numberOfVolumes = 0
|
||||
self.releaseDate = None
|
||||
self.type = None
|
||||
self.version = None
|
||||
self.cover = None
|
||||
self.explicit = False
|
||||
self.audioQuality = None
|
||||
self.audioModes = None
|
||||
self.artist = Artist()
|
||||
self.artists = Artist()
|
||||
|
||||
|
||||
class Playlist(aigpy.model.ModelBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.uuid = None
|
||||
self.title = None
|
||||
self.numberOfTracks = 0
|
||||
self.numberOfVideos = 0
|
||||
self.description = None
|
||||
self.duration = 0
|
||||
self.image = None
|
||||
self.squareImage = None
|
||||
|
||||
|
||||
class Track(aigpy.model.ModelBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.id = None
|
||||
self.title = None
|
||||
self.duration = 0
|
||||
self.trackNumber = 0
|
||||
self.volumeNumber = 0
|
||||
self.trackNumberOnPlaylist = 0
|
||||
self.version = None
|
||||
self.isrc = None
|
||||
self.explicit = False
|
||||
self.audioQuality = None
|
||||
self.copyRight = None
|
||||
self.artist = Artist()
|
||||
self.artists = Artist()
|
||||
self.album = Album()
|
||||
self.allowStreaming = False
|
||||
self.playlist = None
|
||||
|
||||
|
||||
class Video(aigpy.model.ModelBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.id = None
|
||||
self.title = None
|
||||
self.duration = 0
|
||||
self.imageID = None
|
||||
self.trackNumber = 0
|
||||
self.releaseDate = None
|
||||
self.version = None
|
||||
self.quality = None
|
||||
self.explicit = False
|
||||
self.artist = Artist()
|
||||
self.artists = Artist()
|
||||
self.album = Album()
|
||||
self.allowStreaming = False
|
||||
self.playlist = None
|
||||
|
||||
|
||||
class Mix(aigpy.model.ModelBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.id = None
|
||||
self.tracks = Track()
|
||||
self.videos = Video()
|
||||
|
||||
|
||||
class Lyrics(aigpy.model.ModelBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.trackId = None
|
||||
self.lyricsProvider = None
|
||||
self.providerCommontrackId = None
|
||||
self.providerLyricsId = None
|
||||
self.lyrics = None
|
||||
self.subtitles = None
|
||||
|
||||
|
||||
class SearchDataBase(aigpy.model.ModelBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.limit = 0
|
||||
self.offset = 0
|
||||
self.totalNumberOfItems = 0
|
||||
|
||||
|
||||
class SearchAlbums(SearchDataBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.items = Album()
|
||||
|
||||
|
||||
class SearchArtists(SearchDataBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.items = Artist()
|
||||
|
||||
|
||||
class SearchTracks(SearchDataBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.items = Track()
|
||||
|
||||
|
||||
class SearchVideos(SearchDataBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.items = Video()
|
||||
|
||||
|
||||
class SearchPlaylists(SearchDataBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.items = Playlist()
|
||||
|
||||
|
||||
class SearchResult(aigpy.model.ModelBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.artists = SearchArtists()
|
||||
self.albums = SearchAlbums()
|
||||
self.tracks = SearchTracks()
|
||||
self.videos = SearchVideos()
|
||||
self.playlists = SearchPlaylists()
|
||||
|
||||
|
||||
class LoginKey(aigpy.model.ModelBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.deviceCode = None
|
||||
self.userCode = None
|
||||
self.verificationUrl = None
|
||||
self.authCheckTimeout = None
|
||||
self.authCheckInterval = None
|
||||
self.userId = None
|
||||
self.countryCode = None
|
||||
self.accessToken = None
|
||||
self.refreshToken = None
|
||||
self.expiresIn = None
|
||||
|
||||
|
||||
class StreamRespond(aigpy.model.ModelBase):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.trackid = None
|
||||
self.videoid = None
|
||||
self.streamType = None
|
||||
self.assetPresentation = None
|
||||
self.audioMode = None
|
||||
self.audioQuality = None
|
||||
self.videoQuality = None
|
||||
self.manifestMimeType = None
|
||||
self.manifest = None
|
||||
@@ -0,0 +1,199 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""
|
||||
@File : paths.py
|
||||
@Date : 2022/06/10
|
||||
@Author : Yaronzz
|
||||
@Version : 1.0
|
||||
@Contact : yaronhuang@foxmail.com
|
||||
@Desc :
|
||||
"""
|
||||
import os
|
||||
import aigpy
|
||||
import datetime
|
||||
|
||||
from tidal import *
|
||||
from settings import *
|
||||
|
||||
|
||||
def __fixPath__(name: str):
|
||||
return aigpy.path.replaceLimitChar(name, '-').strip()
|
||||
|
||||
|
||||
def __getYear__(releaseDate: str):
|
||||
if releaseDate is None or releaseDate == '':
|
||||
return ''
|
||||
return aigpy.string.getSubOnlyEnd(releaseDate, '-')
|
||||
|
||||
|
||||
def __getDurationStr__(seconds):
|
||||
time_string = str(datetime.timedelta(seconds=seconds))
|
||||
if time_string.startswith('0:'):
|
||||
time_string = time_string[2:]
|
||||
return time_string
|
||||
|
||||
|
||||
def __getExtension__(stream: StreamUrl):
|
||||
if '.flac' in stream.url:
|
||||
return '.flac'
|
||||
if '.mp4' in stream.url:
|
||||
if 'ac4' in stream.codec or 'mha1' in stream.codec:
|
||||
return '.mp4'
|
||||
elif 'flac' in stream.codec:
|
||||
return '.flac'
|
||||
return '.m4a'
|
||||
return '.m4a'
|
||||
|
||||
|
||||
def getAlbumPath(album):
|
||||
artistName = __fixPath__(TIDAL_API.getArtistsName(album.artists))
|
||||
albumArtistName = __fixPath__(album.artist.name) if album.artist is not None else ""
|
||||
|
||||
# album folder pre: [ME]
|
||||
flag = TIDAL_API.getFlag(album, Type.Album, True, "")
|
||||
if SETTINGS.audioQuality != AudioQuality.Master and SETTINGS.audioQuality != AudioQuality.Max:
|
||||
flag = flag.replace("M", "")
|
||||
if flag != "":
|
||||
flag = "[" + flag + "] "
|
||||
|
||||
# album and addyear
|
||||
albumName = __fixPath__(album.title)
|
||||
year = __getYear__(album.releaseDate)
|
||||
|
||||
# retpath
|
||||
retpath = SETTINGS.albumFolderFormat
|
||||
if retpath is None or len(retpath) <= 0:
|
||||
retpath = SETTINGS.getDefaultAlbumFolderFormat()
|
||||
retpath = retpath.replace(R"{ArtistName}", artistName)
|
||||
retpath = retpath.replace(R"{AlbumArtistName}", albumArtistName)
|
||||
retpath = retpath.replace(R"{Flag}", flag)
|
||||
retpath = retpath.replace(R"{AlbumID}", str(album.id))
|
||||
retpath = retpath.replace(R"{AlbumYear}", year)
|
||||
retpath = retpath.replace(R"{AlbumTitle}", albumName)
|
||||
retpath = retpath.replace(R"{AudioQuality}", album.audioQuality)
|
||||
retpath = retpath.replace(R"{DurationSeconds}", str(album.duration))
|
||||
retpath = retpath.replace(R"{Duration}", __getDurationStr__(album.duration))
|
||||
retpath = retpath.replace(R"{NumberOfTracks}", str(album.numberOfTracks))
|
||||
retpath = retpath.replace(R"{NumberOfVideos}", str(album.numberOfVideos))
|
||||
retpath = retpath.replace(R"{NumberOfVolumes}", str(album.numberOfVolumes))
|
||||
retpath = retpath.replace(R"{ReleaseDate}", str(album.releaseDate))
|
||||
retpath = retpath.replace(R"{RecordType}", album.type)
|
||||
retpath = retpath.replace(R"{None}", "")
|
||||
retpath = retpath.strip()
|
||||
return f"{SETTINGS.downloadPath}/{retpath}"
|
||||
|
||||
def getPlaylistPath(playlist):
|
||||
playlistName = __fixPath__(playlist.title)
|
||||
|
||||
# retpath
|
||||
retpath = SETTINGS.playlistFolderFormat
|
||||
if retpath is None or len(retpath) <= 0:
|
||||
retpath = SETTINGS.getDefaultPlaylistFolderFormat()
|
||||
retpath = retpath.replace(R"{PlaylistUUID}", str(playlist.uuid))
|
||||
retpath = retpath.replace(R"{PlaylistName}", playlistName)
|
||||
return f"{SETTINGS.downloadPath}/{retpath}"
|
||||
|
||||
|
||||
def getTrackPath(track, stream, album=None, playlist=None):
|
||||
base = './'
|
||||
number = str(track.trackNumber).rjust(2, '0')
|
||||
if album is not None:
|
||||
base = getAlbumPath(album)
|
||||
if album.numberOfVolumes > 1:
|
||||
base += f'/CD{str(track.volumeNumber)}'
|
||||
|
||||
if playlist is not None and SETTINGS.usePlaylistFolder:
|
||||
base = getPlaylistPath(playlist)
|
||||
number = str(track.trackNumberOnPlaylist).rjust(2, '0')
|
||||
|
||||
# artist
|
||||
artists = __fixPath__(TIDAL_API.getArtistsName(track.artists))
|
||||
artist = __fixPath__(track.artist.name) if track.artist is not None else ""
|
||||
|
||||
# title
|
||||
title = __fixPath__(track.title)
|
||||
if not aigpy.string.isNull(track.version):
|
||||
title += f' ({__fixPath__(track.version)})'
|
||||
|
||||
# explicit
|
||||
explicit = "(Explicit)" if track.explicit else ''
|
||||
|
||||
# album and addyear
|
||||
albumName = __fixPath__(album.title) if album is not None else ''
|
||||
year = __getYear__(album.releaseDate) if album is not None else ''
|
||||
|
||||
# extension
|
||||
extension = __getExtension__(stream)
|
||||
|
||||
retpath = SETTINGS.trackFileFormat
|
||||
if retpath is None or len(retpath) <= 0:
|
||||
retpath = SETTINGS.getDefaultTrackFileFormat()
|
||||
retpath = retpath.replace(R"{TrackNumber}", number)
|
||||
retpath = retpath.replace(R"{ArtistName}", artist)
|
||||
retpath = retpath.replace(R"{ArtistsName}", artists)
|
||||
retpath = retpath.replace(R"{TrackTitle}", title)
|
||||
retpath = retpath.replace(R"{ExplicitFlag}", explicit)
|
||||
retpath = retpath.replace(R"{AlbumYear}", year)
|
||||
retpath = retpath.replace(R"{AlbumTitle}", albumName)
|
||||
retpath = retpath.replace(R"{AudioQuality}", track.audioQuality)
|
||||
retpath = retpath.replace(R"{DurationSeconds}", str(track.duration))
|
||||
retpath = retpath.replace(R"{Duration}", __getDurationStr__(track.duration))
|
||||
retpath = retpath.replace(R"{TrackID}", str(track.id))
|
||||
retpath = retpath.strip()
|
||||
return f"{base}/{retpath}{extension}"
|
||||
|
||||
|
||||
def getVideoPath(video, album=None, playlist=None):
|
||||
base = SETTINGS.downloadPath + '/Video/'
|
||||
if album is not None and album.title is not None:
|
||||
base = getAlbumPath(album)
|
||||
elif playlist is not None:
|
||||
base = getPlaylistPath(playlist)
|
||||
|
||||
# get number
|
||||
number = str(video.trackNumber).rjust(2, '0')
|
||||
|
||||
# get artist
|
||||
artists = __fixPath__(TIDAL_API.getArtistsName(video.artists))
|
||||
artist = __fixPath__(video.artist.name) if video.artist is not None else ""
|
||||
|
||||
# explicit
|
||||
explicit = "(Explicit)" if video.explicit else ''
|
||||
|
||||
# title and year and extension
|
||||
title = __fixPath__(video.title)
|
||||
year = __getYear__(video.releaseDate)
|
||||
extension = ".mp4"
|
||||
|
||||
retpath = SETTINGS.videoFileFormat
|
||||
if retpath is None or len(retpath) <= 0:
|
||||
retpath = SETTINGS.getDefaultVideoFileFormat()
|
||||
retpath = retpath.replace(R"{VideoNumber}", number)
|
||||
retpath = retpath.replace(R"{ArtistName}", artist)
|
||||
retpath = retpath.replace(R"{ArtistsName}", artists)
|
||||
retpath = retpath.replace(R"{VideoTitle}", title)
|
||||
retpath = retpath.replace(R"{ExplicitFlag}", explicit)
|
||||
retpath = retpath.replace(R"{VideoYear}", year)
|
||||
retpath = retpath.replace(R"{VideoID}", str(video.id))
|
||||
retpath = retpath.strip()
|
||||
return f"{base}/{retpath}{extension}"
|
||||
|
||||
|
||||
def __getHomePath__():
|
||||
if "XDG_CONFIG_HOME" in os.environ:
|
||||
return os.environ['XDG_CONFIG_HOME']
|
||||
elif "HOME" in os.environ:
|
||||
return os.environ['HOME']
|
||||
elif "HOMEDRIVE" in os.environ and "HOMEPATH" in os.environ:
|
||||
return os.environ['HOMEDRIVE'] + os.environ['HOMEPATH']
|
||||
else:
|
||||
return os.path.abspath("./")
|
||||
|
||||
def getLogPath():
|
||||
return __getHomePath__() + '/.tidal-dl.log'
|
||||
|
||||
def getTokenPath():
|
||||
return __getHomePath__() + '/.tidal-dl.token.json'
|
||||
|
||||
def getProfilePath():
|
||||
return __getHomePath__() + '/.tidal-dl.json'
|
||||
@@ -0,0 +1,309 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : printf.py
|
||||
@Time : 2020/08/16
|
||||
@Author : Yaronzz
|
||||
@Version : 3.0
|
||||
@Contact : yaronhuang@foxmail.com
|
||||
@Desc :
|
||||
'''
|
||||
from pickle import GLOBAL
|
||||
import threading
|
||||
import aigpy
|
||||
import logging
|
||||
import prettytable
|
||||
|
||||
import apiKey as apiKey
|
||||
|
||||
from model import *
|
||||
from paths import *
|
||||
from settings import *
|
||||
from lang.language import *
|
||||
|
||||
|
||||
VERSION = '2022.10.31.1'
|
||||
__LOGO__ = f'''
|
||||
/$$$$$$$$ /$$ /$$ /$$ /$$ /$$
|
||||
|__ $$__/|__/ | $$ | $$ | $$| $$
|
||||
| $$ /$$ /$$$$$$$ /$$$$$$ | $$ /$$$$$$$| $$
|
||||
| $$ | $$ /$$__ $$ |____ $$| $$ /$$$$$$ /$$__ $$| $$
|
||||
| $$ | $$| $$ | $$ /$$$$$$$| $$|______/| $$ | $$| $$
|
||||
| $$ | $$| $$ | $$ /$$__ $$| $$ | $$ | $$| $$
|
||||
| $$ | $$| $$$$$$$| $$$$$$$| $$ | $$$$$$$| $$
|
||||
|__/ |__/ \_______/ \_______/|__/ \_______/|__/
|
||||
|
||||
https://github.com/yaronzz/Tidal-Media-Downloader
|
||||
|
||||
{VERSION}
|
||||
'''
|
||||
|
||||
print_mutex = threading.Lock()
|
||||
|
||||
|
||||
class Printf(object):
|
||||
|
||||
@staticmethod
|
||||
def logo():
|
||||
print(__LOGO__)
|
||||
logging.info(__LOGO__)
|
||||
|
||||
@staticmethod
|
||||
def __gettable__(columns, rows):
|
||||
tb = prettytable.PrettyTable()
|
||||
tb.field_names = list(aigpy.cmd.green(item) for item in columns)
|
||||
tb.align = 'l'
|
||||
for item in rows:
|
||||
tb.add_row(item)
|
||||
return tb
|
||||
|
||||
@staticmethod
|
||||
def usage():
|
||||
print("=============TIDAL-DL HELP==============")
|
||||
tb = Printf.__gettable__(["OPTION", "DESC"], [
|
||||
["-h or --help", "show help-message"],
|
||||
["-v or --version", "show version"],
|
||||
["-g or --gui", "show simple-gui"],
|
||||
["-o or --output", "download path"],
|
||||
["-l or --link", "url/id/filePath"],
|
||||
["-q or --quality", "track quality('Normal','High,'HiFi','Master')"],
|
||||
["-r or --resolution", "video resolution('P1080', 'P720', 'P480', 'P360')"]
|
||||
])
|
||||
print(tb)
|
||||
|
||||
@staticmethod
|
||||
def checkVersion():
|
||||
onlineVer = aigpy.pip.getLastVersion('tidal-dl')
|
||||
if onlineVer is not None:
|
||||
icmp = aigpy.system.cmpVersion(onlineVer, VERSION)
|
||||
if icmp > 0:
|
||||
Printf.info(LANG.select.PRINT_LATEST_VERSION + ' ' + onlineVer)
|
||||
|
||||
@staticmethod
|
||||
def settings():
|
||||
data = SETTINGS
|
||||
tb = Printf.__gettable__([LANG.select.SETTING, LANG.select.VALUE], [
|
||||
#settings - path and format
|
||||
[LANG.select.SETTING_PATH, getProfilePath()],
|
||||
[LANG.select.SETTING_DOWNLOAD_PATH, data.downloadPath],
|
||||
[LANG.select.SETTING_ALBUM_FOLDER_FORMAT, data.albumFolderFormat],
|
||||
[LANG.select.SETTING_PLAYLIST_FOLDER_FORMAT, data.playlistFolderFormat],
|
||||
[LANG.select.SETTING_TRACK_FILE_FORMAT, data.trackFileFormat],
|
||||
[LANG.select.SETTING_VIDEO_FILE_FORMAT, data.videoFileFormat],
|
||||
|
||||
#settings - quality
|
||||
[LANG.select.SETTING_AUDIO_QUALITY, data.audioQuality],
|
||||
[LANG.select.SETTING_VIDEO_QUALITY, data.videoQuality],
|
||||
|
||||
#settings - else
|
||||
[LANG.select.SETTING_USE_PLAYLIST_FOLDER, data.usePlaylistFolder],
|
||||
[LANG.select.SETTING_CHECK_EXIST, data.checkExist],
|
||||
[LANG.select.SETTING_SHOW_PROGRESS, data.showProgress],
|
||||
[LANG.select.SETTING_SHOW_TRACKINFO, data.showTrackInfo],
|
||||
[LANG.select.SETTING_SAVE_ALBUMINFO, data.saveAlbumInfo],
|
||||
[LANG.select.SETTING_DOWNLOAD_VIDEOS, data.downloadVideos],
|
||||
[LANG.select.SETTING_SAVE_COVERS, data.saveCovers],
|
||||
[LANG.select.SETTING_INCLUDE_EP, data.includeEP],
|
||||
[LANG.select.SETTING_LANGUAGE, LANG.getLangName(data.language)],
|
||||
[LANG.select.SETTING_ADD_LRC_FILE, data.lyricFile],
|
||||
[LANG.select.SETTING_MULITHREAD_DOWNLOAD, data.multiThread],
|
||||
[LANG.select.SETTING_APIKEY, f"[{data.apiKeyIndex}]" + apiKey.getItem(data.apiKeyIndex)['formats']],
|
||||
[LANG.select.SETTING_DOWNLOAD_DELAY, data.downloadDelay],
|
||||
])
|
||||
print(tb)
|
||||
|
||||
@staticmethod
|
||||
def choices():
|
||||
print("====================================================")
|
||||
tb = Printf.__gettable__([LANG.select.CHOICE, LANG.select.FUNCTION], [
|
||||
[aigpy.cmd.green(LANG.select.CHOICE_ENTER + " '0':"), LANG.select.CHOICE_EXIT],
|
||||
[aigpy.cmd.green(LANG.select.CHOICE_ENTER + " '1':"), LANG.select.CHOICE_LOGIN],
|
||||
[aigpy.cmd.green(LANG.select.CHOICE_ENTER + " '2':"), LANG.select.CHOICE_LOGOUT],
|
||||
[aigpy.cmd.green(LANG.select.CHOICE_ENTER + " '3':"), LANG.select.CHOICE_SET_ACCESS_TOKEN],
|
||||
[aigpy.cmd.green(LANG.select.CHOICE_ENTER + " '4':"), LANG.select.CHOICE_SETTINGS + '-Path'],
|
||||
[aigpy.cmd.green(LANG.select.CHOICE_ENTER + " '5':"), LANG.select.CHOICE_SETTINGS + '-Quality'],
|
||||
[aigpy.cmd.green(LANG.select.CHOICE_ENTER + " '6':"), LANG.select.CHOICE_SETTINGS + '-Else'],
|
||||
[aigpy.cmd.green(LANG.select.CHOICE_ENTER + " '7':"), LANG.select.CHOICE_APIKEY],
|
||||
[aigpy.cmd.green(LANG.select.CHOICE_ENTER_URLID), LANG.select.CHOICE_DOWNLOAD_BY_URL],
|
||||
])
|
||||
tb.set_style(prettytable.PLAIN_COLUMNS)
|
||||
print(tb)
|
||||
print("====================================================")
|
||||
|
||||
@staticmethod
|
||||
def enter(string):
|
||||
aigpy.cmd.colorPrint(string, aigpy.cmd.TextColor.Yellow, None)
|
||||
ret = input("")
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def enterBool(string):
|
||||
aigpy.cmd.colorPrint(string, aigpy.cmd.TextColor.Yellow, None)
|
||||
ret = input("")
|
||||
return ret == '1'
|
||||
|
||||
@staticmethod
|
||||
def enterPath(string, errmsg, retWord='0', default=""):
|
||||
while True:
|
||||
ret = aigpy.cmd.inputPath(aigpy.cmd.yellow(string), retWord)
|
||||
if ret == retWord:
|
||||
return default
|
||||
elif ret == "":
|
||||
print(aigpy.cmd.red(LANG.select.PRINT_ERR + " ") + errmsg)
|
||||
else:
|
||||
break
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def enterLimit(string, errmsg, limit=[]):
|
||||
while True:
|
||||
ret = aigpy.cmd.inputLimit(aigpy.cmd.yellow(string), limit)
|
||||
if ret is None:
|
||||
print(aigpy.cmd.red(LANG.select.PRINT_ERR + " ") + errmsg)
|
||||
else:
|
||||
break
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def enterFormat(string, current, default):
|
||||
ret = Printf.enter(string)
|
||||
if ret == '0' or aigpy.string.isNull(ret):
|
||||
return current
|
||||
if ret.lower() == 'default':
|
||||
return default
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def err(string):
|
||||
global print_mutex
|
||||
print_mutex.acquire()
|
||||
print(aigpy.cmd.red(LANG.select.PRINT_ERR + " ") + string)
|
||||
# logging.error(string)
|
||||
print_mutex.release()
|
||||
|
||||
@staticmethod
|
||||
def info(string):
|
||||
global print_mutex
|
||||
print_mutex.acquire()
|
||||
print(aigpy.cmd.blue(LANG.select.PRINT_INFO + " ") + string)
|
||||
print_mutex.release()
|
||||
|
||||
@staticmethod
|
||||
def success(string):
|
||||
global print_mutex
|
||||
print_mutex.acquire()
|
||||
print(aigpy.cmd.green(LANG.select.PRINT_SUCCESS + " ") + string)
|
||||
print_mutex.release()
|
||||
|
||||
@staticmethod
|
||||
def album(data: Album):
|
||||
tb = Printf.__gettable__([LANG.select.MODEL_ALBUM_PROPERTY, LANG.select.VALUE], [
|
||||
[LANG.select.MODEL_TITLE, data.title],
|
||||
["ID", data.id],
|
||||
[LANG.select.MODEL_TRACK_NUMBER, data.numberOfTracks],
|
||||
[LANG.select.MODEL_VIDEO_NUMBER, data.numberOfVideos],
|
||||
[LANG.select.MODEL_RELEASE_DATE, data.releaseDate],
|
||||
[LANG.select.MODEL_VERSION, data.version],
|
||||
[LANG.select.MODEL_EXPLICIT, data.explicit],
|
||||
])
|
||||
print(tb)
|
||||
logging.info("====album " + str(data.id) + "====\n" +
|
||||
"title:" + data.title + "\n" +
|
||||
"track num:" + str(data.numberOfTracks) + "\n" +
|
||||
"video num:" + str(data.numberOfVideos) + "\n" +
|
||||
"==================================")
|
||||
|
||||
@staticmethod
|
||||
def track(data: Track, stream: StreamUrl = None):
|
||||
tb = Printf.__gettable__([LANG.select.MODEL_TRACK_PROPERTY, LANG.select.VALUE], [
|
||||
[LANG.select.MODEL_TITLE, data.title],
|
||||
["ID", data.id],
|
||||
[LANG.select.MODEL_ALBUM, data.album.title],
|
||||
[LANG.select.MODEL_VERSION, data.version],
|
||||
[LANG.select.MODEL_EXPLICIT, data.explicit],
|
||||
["Max-Q", data.audioQuality],
|
||||
])
|
||||
if stream is not None:
|
||||
tb.add_row(["Get-Q", str(stream.soundQuality)])
|
||||
tb.add_row(["Get-Codec", str(stream.codec)])
|
||||
print(tb)
|
||||
logging.info("====track " + str(data.id) + "====\n" + \
|
||||
"title:" + data.title + "\n" + \
|
||||
"version:" + str(data.version) + "\n" + \
|
||||
"==================================")
|
||||
|
||||
@staticmethod
|
||||
def video(data: Video, stream: VideoStreamUrl = None):
|
||||
tb = Printf.__gettable__([LANG.select.MODEL_VIDEO_PROPERTY, LANG.select.VALUE], [
|
||||
[LANG.select.MODEL_TITLE, data.title],
|
||||
[LANG.select.MODEL_ALBUM, data.album.title if data.album != None else None],
|
||||
[LANG.select.MODEL_VERSION, data.version],
|
||||
[LANG.select.MODEL_EXPLICIT, data.explicit],
|
||||
["Max-Q", data.quality],
|
||||
])
|
||||
if stream is not None:
|
||||
tb.add_row(["Get-Q", str(stream.resolution)])
|
||||
tb.add_row(["Get-Codec", str(stream.codec)])
|
||||
print(tb)
|
||||
logging.info("====video " + str(data.id) + "====\n" +
|
||||
"title:" + data.title + "\n" +
|
||||
"version:" + str(data.version) + "\n" +
|
||||
"==================================")
|
||||
|
||||
@staticmethod
|
||||
def artist(data: Artist, num):
|
||||
tb = Printf.__gettable__([LANG.select.MODEL_ARTIST_PROPERTY, LANG.select.VALUE], [
|
||||
[LANG.select.MODEL_ID, data.id],
|
||||
[LANG.select.MODEL_NAME, data.name],
|
||||
["Number of albums", num],
|
||||
[LANG.select.MODEL_TYPE, str(data.type)],
|
||||
])
|
||||
print(tb)
|
||||
logging.info("====artist " + str(data.id) + "====\n" +
|
||||
"name:" + data.name + "\n" +
|
||||
"album num:" + str(num) + "\n" +
|
||||
"==================================")
|
||||
|
||||
@staticmethod
|
||||
def playlist(data):
|
||||
tb = Printf.__gettable__([LANG.select.MODEL_PLAYLIST_PROPERTY, LANG.select.VALUE], [
|
||||
[LANG.select.MODEL_TITLE, data.title],
|
||||
[LANG.select.MODEL_TRACK_NUMBER, data.numberOfTracks],
|
||||
[LANG.select.MODEL_VIDEO_NUMBER, data.numberOfVideos],
|
||||
])
|
||||
print(tb)
|
||||
logging.info("====playlist " + str(data.uuid) + "====\n" +
|
||||
"title:" + data.title + "\n" +
|
||||
"track num:" + str(data.numberOfTracks) + "\n" +
|
||||
"video num:" + str(data.numberOfVideos) + "\n" +
|
||||
"==================================")
|
||||
|
||||
@staticmethod
|
||||
def mix(data):
|
||||
tb = Printf.__gettable__([LANG.select.MODEL_PLAYLIST_PROPERTY, LANG.select.VALUE], [
|
||||
[LANG.select.MODEL_ID, data.id],
|
||||
[LANG.select.MODEL_TRACK_NUMBER, len(data.tracks)],
|
||||
[LANG.select.MODEL_VIDEO_NUMBER, len(data.videos)],
|
||||
])
|
||||
print(tb)
|
||||
logging.info("====Mix " + str(data.id) + "====\n" +
|
||||
"track num:" + str(len(data.tracks)) + "\n" +
|
||||
"video num:" + str(len(data.videos)) + "\n" +
|
||||
"==================================")
|
||||
|
||||
@staticmethod
|
||||
def apikeys(items):
|
||||
print("-------------API-KEYS---------------")
|
||||
tb = prettytable.PrettyTable()
|
||||
tb.field_names = [aigpy.cmd.green('Index'),
|
||||
aigpy.cmd.green('Valid'),
|
||||
aigpy.cmd.green('Platform'),
|
||||
aigpy.cmd.green('Formats'), ]
|
||||
tb.align = 'l'
|
||||
|
||||
for index, item in enumerate(items):
|
||||
tb.add_row([str(index),
|
||||
aigpy.cmd.green('True') if item["valid"] == "True" else aigpy.cmd.red('False'),
|
||||
item["platform"],
|
||||
item["formats"]])
|
||||
print(tb)
|
||||
@@ -1,72 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from aigpy import cmdHelper
|
||||
from aigpy import systemHelper
|
||||
|
||||
def printErr(length, elsestr):
|
||||
cmdHelper.myprint("[ERR]".ljust(length), cmdHelper.TextColor.Red, None)
|
||||
print(elsestr)
|
||||
|
||||
|
||||
def printWarning(length, elsestr):
|
||||
cmdHelper.myprint("[WARNING]".ljust(length), cmdHelper.TextColor.Red, None)
|
||||
print(elsestr)
|
||||
|
||||
def printSUCCESS(length, elsestr):
|
||||
cmdHelper.myprint("[SUCCESS]".ljust(length), cmdHelper.TextColor.Green, None)
|
||||
print(elsestr)
|
||||
|
||||
def printChoice(string, isInt=False, default=None):
|
||||
tmpstr = ""
|
||||
cmdHelper.myprint(string, cmdHelper.TextColor.Yellow, None)
|
||||
if not isInt:
|
||||
return cmdHelper.myinput(tmpstr)
|
||||
else:
|
||||
return cmdHelper.myinputInt(tmpstr, default)
|
||||
def printChoice2(string, default=None):
|
||||
ret = printChoice(string, False, default)
|
||||
try:
|
||||
iret = int(ret)
|
||||
return ret, iret
|
||||
except:
|
||||
return ret, default
|
||||
def printMenu():
|
||||
print("=====================Choice=========================")
|
||||
cmdHelper.myprint(" Enter '0' : ", cmdHelper.TextColor.Green, None)
|
||||
print("Exit.")
|
||||
cmdHelper.myprint(" Enter '1' : ", cmdHelper.TextColor.Green, None)
|
||||
print("LogIn And Get SessionID.")
|
||||
cmdHelper.myprint(" Enter '2' : ", cmdHelper.TextColor.Green, None)
|
||||
print("Change Settings.")
|
||||
cmdHelper.myprint(" Enter '3' : ", cmdHelper.TextColor.Green, None)
|
||||
print("Download an Album.")
|
||||
cmdHelper.myprint(" Enter '4' : ", cmdHelper.TextColor.Green, None)
|
||||
print("Download a Track.")
|
||||
cmdHelper.myprint(" Enter '5' : ", cmdHelper.TextColor.Green, None)
|
||||
print("Download a PlayList.")
|
||||
cmdHelper.myprint(" Enter '6' : ", cmdHelper.TextColor.Green, None)
|
||||
print("Download a Video.")
|
||||
cmdHelper.myprint(" Enter '7' : ", cmdHelper.TextColor.Green, None)
|
||||
print("Download a Favorite.")
|
||||
cmdHelper.myprint(" Enter '8' : ", cmdHelper.TextColor.Green, None)
|
||||
print("Download All Albums by an Artist.")
|
||||
cmdHelper.myprint(" Enter '9' : ", cmdHelper.TextColor.Green, None)
|
||||
print("Show Current Config.")
|
||||
cmdHelper.myprint(" Enter URL : ", cmdHelper.TextColor.Green, None)
|
||||
print("Download By URL.")
|
||||
cmdHelper.myprint(" Enter Path: ", cmdHelper.TextColor.Green, None)
|
||||
print("Download By File.")
|
||||
print("====================================================")
|
||||
|
||||
|
||||
LOG = '''
|
||||
/$$$$$$$$ /$$ /$$ /$$ /$$ /$$
|
||||
|__ $$__/|__/ | $$ | $$ | $$| $$
|
||||
| $$ /$$ /$$$$$$$ /$$$$$$ | $$ /$$$$$$$| $$
|
||||
| $$ | $$ /$$__ $$ |____ $$| $$ /$$$$$$ /$$__ $$| $$
|
||||
| $$ | $$| $$ | $$ /$$$$$$$| $$|______/| $$ | $$| $$
|
||||
| $$ | $$| $$ | $$ /$$__ $$| $$ | $$ | $$| $$
|
||||
| $$ | $$| $$$$$$$| $$$$$$$| $$ | $$$$$$$| $$
|
||||
|__/ |__/ \_______/ \_______/|__/ \_______/|__/
|
||||
|
||||
https://github.com/yaronzz/Tidal-Media-Downloader
|
||||
'''
|
||||
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : settings.py
|
||||
@Time : 2020/11/08
|
||||
@Author : Yaronzz
|
||||
@Version : 3.0
|
||||
@Contact : yaronhuang@foxmail.com
|
||||
@Desc :
|
||||
'''
|
||||
import json
|
||||
import aigpy
|
||||
import base64
|
||||
|
||||
from lang.language import *
|
||||
from enums import *
|
||||
|
||||
|
||||
class Settings(aigpy.model.ModelBase):
|
||||
checkExist = True
|
||||
includeEP = True
|
||||
saveCovers = True
|
||||
language = 0
|
||||
lyricFile = False
|
||||
apiKeyIndex = 0
|
||||
showProgress = True
|
||||
showTrackInfo = True
|
||||
saveAlbumInfo = False
|
||||
downloadVideos = True
|
||||
multiThread = False
|
||||
downloadDelay = True
|
||||
|
||||
downloadPath = "./download/"
|
||||
audioQuality = AudioQuality.Normal
|
||||
videoQuality = VideoQuality.P360
|
||||
usePlaylistFolder = True
|
||||
albumFolderFormat = R"{ArtistName}/{Flag} {AlbumTitle} [{AlbumID}] [{AlbumYear}]"
|
||||
playlistFolderFormat = R"Playlist/{PlaylistName} [{PlaylistUUID}]"
|
||||
trackFileFormat = R"{TrackNumber} - {ArtistName} - {TrackTitle}{ExplicitFlag}"
|
||||
videoFileFormat = R"{VideoNumber} - {ArtistName} - {VideoTitle}{ExplicitFlag}"
|
||||
|
||||
def getDefaultPathFormat(self, type: Type):
|
||||
if type == Type.Album:
|
||||
return R"{ArtistName}/{Flag} {AlbumTitle} [{AlbumID}] [{AlbumYear}]"
|
||||
elif type == Type.Playlist:
|
||||
return R"Playlist/{PlaylistName} [{PlaylistUUID}]"
|
||||
elif type == Type.Track:
|
||||
return R"{TrackNumber} - {ArtistName} - {TrackTitle}{ExplicitFlag}"
|
||||
elif type == Type.Video:
|
||||
return R"{VideoNumber} - {ArtistName} - {VideoTitle}{ExplicitFlag}"
|
||||
return ""
|
||||
|
||||
def getAudioQuality(self, value):
|
||||
for item in AudioQuality:
|
||||
if item.name == value:
|
||||
return item
|
||||
return AudioQuality.Normal
|
||||
|
||||
def getVideoQuality(self, value):
|
||||
for item in VideoQuality:
|
||||
if item.name == value:
|
||||
return item
|
||||
return VideoQuality.P360
|
||||
|
||||
def read(self, path):
|
||||
self._path_ = path
|
||||
txt = aigpy.file.getContent(self._path_)
|
||||
if len(txt) > 0:
|
||||
data = json.loads(txt)
|
||||
if aigpy.model.dictToModel(data, self) is None:
|
||||
return
|
||||
|
||||
self.audioQuality = self.getAudioQuality(self.audioQuality)
|
||||
self.videoQuality = self.getVideoQuality(self.videoQuality)
|
||||
|
||||
if self.albumFolderFormat is None:
|
||||
self.albumFolderFormat = self.getDefaultPathFormat(Type.Album)
|
||||
if self.trackFileFormat is None:
|
||||
self.trackFileFormat = self.getDefaultPathFormat(Type.Track)
|
||||
if self.playlistFolderFormat is None:
|
||||
self.playlistFolderFormat = self.getDefaultPathFormat(Type.Playlist)
|
||||
if self.videoFileFormat is None:
|
||||
self.videoFileFormat = self.getDefaultPathFormat(Type.Video)
|
||||
if self.apiKeyIndex is None:
|
||||
self.apiKeyIndex = 0
|
||||
|
||||
LANG.setLang(self.language)
|
||||
|
||||
def save(self):
|
||||
data = aigpy.model.modelToDict(self)
|
||||
data['audioQuality'] = self.audioQuality.name
|
||||
data['videoQuality'] = self.videoQuality.name
|
||||
txt = json.dumps(data)
|
||||
aigpy.file.write(self._path_, txt, 'w+')
|
||||
|
||||
|
||||
class TokenSettings(aigpy.model.ModelBase):
|
||||
userid = None
|
||||
countryCode = None
|
||||
accessToken = None
|
||||
refreshToken = None
|
||||
expiresAfter = 0
|
||||
|
||||
def __encode__(self, string):
|
||||
sw = bytes(string, 'utf-8')
|
||||
st = base64.b64encode(sw)
|
||||
return st
|
||||
|
||||
def __decode__(self, string):
|
||||
try:
|
||||
sr = base64.b64decode(string)
|
||||
st = sr.decode()
|
||||
return st
|
||||
except:
|
||||
return string
|
||||
|
||||
def read(self, path):
|
||||
self._path_ = path
|
||||
txt = aigpy.file.getContent(self._path_)
|
||||
if len(txt) > 0:
|
||||
data = json.loads(self.__decode__(txt))
|
||||
aigpy.model.dictToModel(data, self)
|
||||
|
||||
def save(self):
|
||||
data = aigpy.model.modelToDict(self)
|
||||
txt = json.dumps(data)
|
||||
aigpy.file.write(self._path_, self.__encode__(txt), 'wb')
|
||||
|
||||
|
||||
# Singleton
|
||||
SETTINGS = Settings()
|
||||
TOKEN = TokenSettings()
|
||||
+487
-620
File diff suppressed because it is too large
Load Diff
+496
-229
@@ -1,229 +1,496 @@
|
||||
#### 2020-05-19
|
||||
- by Command(eg. tidal-dl https://tidal.com/browse/track/70973230)
|
||||
- Add label [M] before albumtitle
|
||||
- Update token
|
||||
|
||||
#### 2020-05-15
|
||||
- Cloud token
|
||||
|
||||
#### 2020-05-14
|
||||
- Update token
|
||||
|
||||
#### 2020-05-04
|
||||
- Hide password
|
||||
|
||||
#### 2020-03-23
|
||||
- Fix downloading redirects that can be obtained through the
|
||||
/playbackinfopostpaywall method.
|
||||
- When downloading, download to a .part file, which is then
|
||||
either decrypted or renamed into place, to avoid leaving broken files.
|
||||
|
||||
#### 2020-3-17
|
||||
- Fix bug of download ArtistAlbum
|
||||
|
||||
#### 2020-03-11
|
||||
- Fix bug of 'Asset is not ready for playback'
|
||||
|
||||
#### 2020-03-10
|
||||
- Update token
|
||||
|
||||
#### 2020-02-28
|
||||
- Fix bug of savepath
|
||||
- Add Year: before/After
|
||||
- save covers(settings)
|
||||
- Flac: add isrc
|
||||
- Fix:no version in Tag
|
||||
|
||||
#### 2020-02-14
|
||||
- Fix bug of download track
|
||||
- ByUrl: add artist
|
||||
- ByUrl: support 'https://tidal.com/browse/'
|
||||
|
||||
#### 2020-01-22
|
||||
- Download artist album include singles(settings)
|
||||
- Download by file include artist
|
||||
- Fix english typos
|
||||
- Fix bug of tracknumber(download playlist)
|
||||
|
||||
#### 2020-01-17
|
||||
- Artists hyphen ';' to ', '
|
||||
- Fix bug of download playlist
|
||||
- Fix bug of download artwork
|
||||
- Added Explicit to the file name(settings)
|
||||
- Playlist organized with artist folder(settings)
|
||||
- Playlist: add tracknum before tracktitle
|
||||
|
||||
#### v2019-10-26
|
||||
- Download playlist by url
|
||||
- Config 'AddYear' before album dir
|
||||
- Download playlist track-picture
|
||||
|
||||
#### v2019-09-27
|
||||
- Add skip switch when download atrist/file
|
||||
- Fix bug of download playlist
|
||||
|
||||
#### v2019-09-10
|
||||
- Fix bug of download videos
|
||||
- Add version to title
|
||||
- Add hyphen between number and title(settings)
|
||||
|
||||
#### v2019-09-02
|
||||
- Fix bug of parse link
|
||||
- Download by file
|
||||
|
||||
#### v2019-08-19
|
||||
- Show Config
|
||||
- Tag: add composer
|
||||
|
||||
#### v2019-08-17
|
||||
- Download ArtistAlbum: Add EP&Singles
|
||||
|
||||
#### v2019-08-12
|
||||
- Fix bug of tag
|
||||
- Add setting-showprogress (Only enable when threadnum=1)
|
||||
|
||||
#### v2019-08-11
|
||||
- Fix tag of title
|
||||
- Download album videos
|
||||
|
||||
#### v2019-08-07
|
||||
- Fix Bug: login;threadnum
|
||||
|
||||
#### v2019-08-05
|
||||
- Support python 2.7
|
||||
|
||||
#### v2019-07-30
|
||||
- Add Setting-OnlyM4a(auto covert mp4 To m4a)
|
||||
- Fix some bug when first login
|
||||
- Check ffmpeg status
|
||||
|
||||
#### v2019-07-23
|
||||
- CLI: add a serial number before the file name
|
||||
|
||||
#### v2019-07-22
|
||||
- Fix Some Bug
|
||||
|
||||
#### v2019-07-18
|
||||
- Fix Bug: Set Metadata
|
||||
|
||||
#### v2019-07-12
|
||||
- Fix Some Bug
|
||||
|
||||
#### v2019-07-11
|
||||
- Add Func:Download By Url
|
||||
|
||||
#### v2019-07-01
|
||||
- Add HI_RES Quality
|
||||
|
||||
#### v2019-06-24
|
||||
- Fix Bug When Downloading Playlist
|
||||
|
||||
#### v2019-06-16
|
||||
- Fix Bug Of Track Tag
|
||||
|
||||
#### v2019-06-01
|
||||
- Fix Encoding BUG
|
||||
- Add Cover To Track
|
||||
|
||||
#### v2019-05-08
|
||||
- Update FFmpegTool
|
||||
|
||||
#### v2019-05-06
|
||||
- Change 'Track' TargetDir
|
||||
- Download 'Playlist'&'Track' Image
|
||||
- Fuc: Download ArtistAlbums
|
||||
|
||||
#### v2019-04-23
|
||||
- Add 'Resolution' To Config
|
||||
- Change Playlist Items TrackNum
|
||||
|
||||
#### v2019-04-22
|
||||
- Download Album: Track Title Append Version
|
||||
|
||||
#### v2019-04-16
|
||||
- Change Album TargetDir
|
||||
- Add 'ReleaseDate' to Track Metadata
|
||||
- Remove BUG:Playlist Path
|
||||
|
||||
#### v2019-04-11
|
||||
- Remove BUG:Download Playlist Video
|
||||
|
||||
#### v2019-04-08
|
||||
- Change Tmp File Flag
|
||||
|
||||
#### v2019-04-02
|
||||
- Highlight(Only Linux)
|
||||
|
||||
#### v2019-04-01
|
||||
- Remove Encoding Err
|
||||
|
||||
#### v2019-03-29
|
||||
- Dl Album:If Exist TrackFile. Support ReDownload Or Ignore
|
||||
|
||||
#### v2019-03-28
|
||||
- Check After Set Metadata
|
||||
|
||||
#### v2019-03-13
|
||||
- Deal Err: Get pip version failed
|
||||
|
||||
#### v2019-03-11
|
||||
- Check Files After Download Playlist
|
||||
- Show Last Version
|
||||
|
||||
#### v2019-03-06
|
||||
- Add Config 'ThreadNum'
|
||||
- Support Linux
|
||||
- Add 'requirements.txt'
|
||||
- Show Tool Version
|
||||
- Set Metadata in Linux
|
||||
|
||||
#### v2019-03-04
|
||||
- Simplified Code
|
||||
|
||||
#### v2019-02-27
|
||||
- Download FavoriteVideos
|
||||
|
||||
#### v2019-02-26
|
||||
- Download Playlist:Deal with err 'Too Big Page'
|
||||
|
||||
#### v2019-02-25
|
||||
- Playlist LimitNum = 9999
|
||||
- Download FavoriteTracks
|
||||
|
||||
#### v2019-02-19
|
||||
- Print more err message
|
||||
|
||||
#### v2019-02-19
|
||||
- Download AlbumCover
|
||||
- Set Track Metadata
|
||||
|
||||
#### v2019-02-14
|
||||
- Set music-filetype by StreamUrlInfo
|
||||
|
||||
#### v2019-01-28
|
||||
- Add decryption.py -- Download LOSSLESS music
|
||||
|
||||
#### v2018-12-28
|
||||
- Add Progressbar - Download Video
|
||||
|
||||
#### v2018-12-19
|
||||
- Update ffmpegHelper
|
||||
- Simplified Code
|
||||
|
||||
#### v2018-12-11
|
||||
- Fuc: Download Playlist Video
|
||||
|
||||
#### v2018-12-01
|
||||
- Optimized Code
|
||||
- Multithreading Download Video
|
||||
- Fuc: Download Playlist
|
||||
|
||||
#### v2018-11-22
|
||||
- Multithreading Download
|
||||
- Fuc: Download Track
|
||||
- Fuc: Download Video
|
||||
|
||||
#### v2018-11-21
|
||||
- Func: Download Album
|
||||
- Func: Get SessionID By Account
|
||||
- Upload Version To PIP Server : pip install tidal-dl
|
||||
TYPE tidal-dl
|
||||
USE pip3 install tidal-dl --upgrade
|
||||
|
||||
#### v2022-10-31
|
||||
|
||||
- [X] Add delay setting by @grzekru
|
||||
|
||||
#### v2022-08-29
|
||||
|
||||
- [X] Fix #931
|
||||
|
||||
#### v2022-07-06
|
||||
|
||||
- [X] Mulithread download
|
||||
|
||||
#### v2022-06-23
|
||||
|
||||
- [X] remove redundant configuration
|
||||
- [X] add simple-gui
|
||||
- [X] optimize code
|
||||
|
||||
#### v2022-03-04
|
||||
|
||||
- [X] fix "file name contain *" #844
|
||||
- [X] Update Vietnamese
|
||||
- [X] update Hungarian
|
||||
- [X] Update Ukrainian
|
||||
- [X] Update Dutch
|
||||
- [X] fix bug of setting path
|
||||
|
||||
#### v2022-02-07
|
||||
|
||||
- [X] update api key by 1nikolas
|
||||
|
||||
#### v2022-01-21
|
||||
|
||||
- [X] update api key by @morguldir
|
||||
- [X] Fix bug of "ReleaseDate"
|
||||
|
||||
#### v2022-01-18
|
||||
|
||||
- [X] Gui: search view
|
||||
- [X] Gui: download view
|
||||
|
||||
#### v2022-01-11
|
||||
|
||||
- [X] Settings: add type-folder(eg Album/Video/Playlist)
|
||||
- [X] Album folder format support: {None}
|
||||
|
||||
#### v2021-11-30
|
||||
|
||||
- [X] Add language:Japanese
|
||||
- [X] Support select apikey(Different keys support different formats)
|
||||
|
||||
#### v2021-11-15
|
||||
|
||||
- [X] Add language:Korean
|
||||
- [X] Update vietnamese
|
||||
- [X] Additional tags for album path and track name
|
||||
|
||||
#### v2021-09-23
|
||||
|
||||
- [X] Get lyrics from tidal
|
||||
- [X] Support mixes
|
||||
|
||||
#### v2021-09-10
|
||||
|
||||
- [X] Add settings: show track-info
|
||||
- [X] Fix bug of "Illegal characters in path"
|
||||
|
||||
#### v2021-05-31
|
||||
|
||||
- [X] Add lyrics
|
||||
|
||||
#### v2021-04-30
|
||||
|
||||
- [X] Add 'album info.txt'
|
||||
- [X] Fix bug of download video
|
||||
|
||||
#### v2021-04-23
|
||||
|
||||
- [X] Show get-quality
|
||||
- [X] Update language
|
||||
- [X] Update settings: usePlaylistFolder
|
||||
|
||||
#### v2021-03-24
|
||||
|
||||
- [X] Fix bug of download video
|
||||
- [X] Fix bug of 'Command line download'
|
||||
|
||||
#### v2021-02-20
|
||||
|
||||
- [X] Add log
|
||||
|
||||
#### v2020-12-17
|
||||
|
||||
- [X] Show DOLBY_ATMOS flag [A]
|
||||
- [X] Fix bug of "Connection aborted"(Linux platform)
|
||||
- [X] Fix bug of download failed "stat: path should be string, bytes, os.PathLike or integer, not list"
|
||||
|
||||
#### v2020-12-10
|
||||
|
||||
- [X] Add feature: set the accessToken manually
|
||||
|
||||
#### v2020-12-01
|
||||
|
||||
- [X] Fix bug of settings-path
|
||||
- [X] Ability to download multiple urls at a time.
|
||||
|
||||
#### v2020-11-13
|
||||
|
||||
- [X] Change settings-file save path: XDG_CONFIG_HOME or HOME
|
||||
- [X] Fix bug of multiThreadDownload
|
||||
- [X] Choice: logout
|
||||
|
||||
#### v2020-11-09
|
||||
|
||||
- [X] New login-method: get the accessToken by opening the link, accessToken good for one week and auto refresh
|
||||
|
||||
#### v2020-10-22
|
||||
|
||||
- [X] Settings: album folder format、track file format
|
||||
- [X] Settings: show progress
|
||||
- [X] Support language: german
|
||||
- [X] Tag: composer
|
||||
- [X] Add command opts: username\password\accessToken\quality\resolution
|
||||
|
||||
#### v2020-09-26
|
||||
|
||||
- [X] Fix: download video failed. Resolution parse error.
|
||||
- [X] Windows: auto get accessToken from tidal-desktop cache
|
||||
- [X] Download playlist to playlist folder
|
||||
- [X] Fix: check exist
|
||||
- [X] Support language vietnamese
|
||||
- [X] Fix: download cover error (no album-cover)
|
||||
- [X] Settings: usePlaylistFolder、 multiThreadDownload
|
||||
- [X] Support language french
|
||||
|
||||
#### v2020-09-06
|
||||
|
||||
- usage by command: tidal-dl --help
|
||||
|
||||
#### v2020-08-30
|
||||
|
||||
- support language portuguese
|
||||
- multithreading download a track
|
||||
|
||||
#### v2020-08-24
|
||||
|
||||
- add errmessage when downloading failed
|
||||
- fix: macos - download failed
|
||||
|
||||
#### v2020-08-22
|
||||
|
||||
- support language spanish\croatian
|
||||
|
||||
#### v2020-08-21
|
||||
|
||||
- fix: get album path
|
||||
- support download by file
|
||||
- support language arabic\czech\itlian\russian\turkish\filipino
|
||||
|
||||
#### v2020-08-20
|
||||
|
||||
- fix: download playlist
|
||||
- fix: settings
|
||||
- fix: lack of multi-language module
|
||||
|
||||
#### v2020-08-19
|
||||
|
||||
- code rebuild
|
||||
- multi-language
|
||||
|
||||
#### v2020-07-16
|
||||
|
||||
- Enter 10:Set AccessToken(authorization)
|
||||
|
||||
#### v2020-07-03
|
||||
|
||||
- Add label [E] before albumtitle #264
|
||||
- Volume to CD
|
||||
- Fix bug of ssl
|
||||
|
||||
#### v2020-06-28
|
||||
|
||||
- Fix bug of download-playlist
|
||||
- ArtistName before title(settings)
|
||||
- AlbumID before AlbumFolderName(settings)
|
||||
- Add require-libs
|
||||
- Add errmessage when download err
|
||||
|
||||
#### v2020-06-14
|
||||
|
||||
- Reduce the number of logins
|
||||
- Use another login method(from Redsea)
|
||||
- Download Dolby Atmos(AC4 Codec\Low Quality\Mp4 format)
|
||||
- Download SONY_360RA(MHA1 Codec\Low Quality\Mp4 format)
|
||||
- Skip convert to mp4 if File-Codec is AC4 or MHA1
|
||||
- Fixed the bug of Download-HIRES
|
||||
|
||||
#### v2020-05-31
|
||||
|
||||
- Use CDN request
|
||||
- Fix bug of redownload(download artist-albums)
|
||||
- Add errmessage when login-err
|
||||
- Fix bug of save-cover MacOs
|
||||
|
||||
#### v2020-05-19
|
||||
|
||||
- by Command(eg. tidal-dl https://tidal.com/browse/track/70973230)
|
||||
- Add label [M] before albumtitle
|
||||
- Update token
|
||||
|
||||
#### v2020-05-15
|
||||
|
||||
- Cloud token
|
||||
|
||||
#### v2020-05-14
|
||||
|
||||
- Update token
|
||||
|
||||
#### v2020-05-04
|
||||
|
||||
- Hide password
|
||||
|
||||
#### v2020-03-23
|
||||
|
||||
- Fix downloading redirects that can be obtained through the
|
||||
/playbackinfopostpaywall method.
|
||||
- When downloading, download to a .part file, which is then
|
||||
either decrypted or renamed into place, to avoid leaving broken files.
|
||||
|
||||
#### v2020-3-17
|
||||
|
||||
- Fix bug of download ArtistAlbum
|
||||
|
||||
#### v2020-03-11
|
||||
|
||||
- Fix bug of 'Asset is not ready for playback'
|
||||
|
||||
#### v2020-03-10
|
||||
|
||||
- Update token
|
||||
|
||||
#### v2020-02-28
|
||||
|
||||
- Fix bug of savepath
|
||||
- Add Year: before/After
|
||||
- save covers(settings)
|
||||
- Flac: add isrc
|
||||
- Fix:no version in Tag
|
||||
|
||||
#### v2020-02-14
|
||||
|
||||
- Fix bug of download track
|
||||
- ByUrl: add artist
|
||||
- ByUrl: support 'https://tidal.com/browse/'
|
||||
|
||||
#### v2020-01-22
|
||||
|
||||
- Download artist album include singles(settings)
|
||||
- Download by file include artist
|
||||
- Fix english typos
|
||||
- Fix bug of tracknumber(download playlist)
|
||||
|
||||
#### v2020-01-17
|
||||
|
||||
- Artists hyphen ';' to ', '
|
||||
- Fix bug of download playlist
|
||||
- Fix bug of download artwork
|
||||
- Added Explicit to the file name(settings)
|
||||
- Playlist organized with artist folder(settings)
|
||||
- Playlist: add tracknum before tracktitle
|
||||
|
||||
#### v2019-10-26
|
||||
|
||||
- Download playlist by url
|
||||
- Config 'AddYear' before album dir
|
||||
- Download playlist track-picture
|
||||
|
||||
#### v2019-09-27
|
||||
|
||||
- Add skip switch when download atrist/file
|
||||
- Fix bug of download playlist
|
||||
|
||||
#### v2019-09-10
|
||||
|
||||
- Fix bug of download videos
|
||||
- Add version to title
|
||||
- Add hyphen between number and title(settings)
|
||||
|
||||
#### v2019-09-02
|
||||
|
||||
- Fix bug of parse link
|
||||
- Download by file
|
||||
|
||||
#### v2019-08-19
|
||||
|
||||
- Show Config
|
||||
- Tag: add composer
|
||||
|
||||
#### v2019-08-17
|
||||
|
||||
- Download ArtistAlbum: Add EP&Singles
|
||||
|
||||
#### v2019-08-12
|
||||
|
||||
- Fix bug of tag
|
||||
- Add setting-showprogress (Only enable when threadnum=1)
|
||||
|
||||
#### v2019-08-11
|
||||
|
||||
- Fix tag of title
|
||||
- Download album videos
|
||||
|
||||
#### v2019-08-07
|
||||
|
||||
- Fix Bug: login;threadnum
|
||||
|
||||
#### v2019-08-05
|
||||
|
||||
- Support python 2.7
|
||||
|
||||
#### v2019-07-30
|
||||
|
||||
- Add Setting-OnlyM4a(auto covert mp4 To m4a)
|
||||
- Fix some bug when first login
|
||||
- Check ffmpeg status
|
||||
|
||||
#### v2019-07-23
|
||||
|
||||
- CLI: add a serial number before the file name
|
||||
|
||||
#### v2019-07-22
|
||||
|
||||
- Fix Some Bug
|
||||
|
||||
#### v2019-07-18
|
||||
|
||||
- Fix Bug: Set Metadata
|
||||
|
||||
#### v2019-07-12
|
||||
|
||||
- Fix Some Bug
|
||||
|
||||
#### v2019-07-11
|
||||
|
||||
- Add Func:Download By Url
|
||||
|
||||
#### v2019-07-01
|
||||
|
||||
- Add HI_RES Quality
|
||||
|
||||
#### v2019-06-24
|
||||
|
||||
- Fix Bug When Downloading Playlist
|
||||
|
||||
#### v2019-06-16
|
||||
|
||||
- Fix Bug Of Track Tag
|
||||
|
||||
#### v2019-06-01
|
||||
|
||||
- Fix Encoding BUG
|
||||
- Add Cover To Track
|
||||
|
||||
#### v2019-05-08
|
||||
|
||||
- Update FFmpegTool
|
||||
|
||||
#### v2019-05-06
|
||||
|
||||
- Change 'Track' TargetDir
|
||||
- Download 'Playlist'&'Track' Image
|
||||
- Fuc: Download ArtistAlbums
|
||||
|
||||
#### v2019-04-23
|
||||
|
||||
- Add 'Resolution' To Config
|
||||
- Change Playlist Items TrackNum
|
||||
|
||||
#### v2019-04-22
|
||||
|
||||
- Download Album: Track Title Append Version
|
||||
|
||||
#### v2019-04-16
|
||||
|
||||
- Change Album TargetDir
|
||||
- Add 'ReleaseDate' to Track Metadata
|
||||
- Remove BUG:Playlist Path
|
||||
|
||||
#### v2019-04-11
|
||||
|
||||
- Remove BUG:Download Playlist Video
|
||||
|
||||
#### v2019-04-08
|
||||
|
||||
- Change Tmp File Flag
|
||||
|
||||
#### v2019-04-02
|
||||
|
||||
- Highlight(Only Linux)
|
||||
|
||||
#### v2019-04-01
|
||||
|
||||
- Remove Encoding Err
|
||||
|
||||
#### v2019-03-29
|
||||
|
||||
- Dl Album:If Exist TrackFile. Support ReDownload Or Ignore
|
||||
|
||||
#### v2019-03-28
|
||||
|
||||
- Check After Set Metadata
|
||||
|
||||
#### v2019-03-13
|
||||
|
||||
- Deal Err: Get pip version failed
|
||||
|
||||
#### v2019-03-11
|
||||
|
||||
- Check Files After Download Playlist
|
||||
- Show Last Version
|
||||
|
||||
#### v2019-03-06
|
||||
|
||||
- Add Config 'ThreadNum'
|
||||
- Support Linux
|
||||
- Add 'requirements.txt'
|
||||
- Show Tool Version
|
||||
- Set Metadata in Linux
|
||||
|
||||
#### v2019-03-04
|
||||
|
||||
- Simplified Code
|
||||
|
||||
#### v2019-02-27
|
||||
|
||||
- Download FavoriteVideos
|
||||
|
||||
#### v2019-02-26
|
||||
|
||||
- Download Playlist:Deal with err 'Too Big Page'
|
||||
|
||||
#### v2019-02-25
|
||||
|
||||
- Playlist LimitNum = 9999
|
||||
- Download FavoriteTracks
|
||||
|
||||
#### v2019-02-19
|
||||
|
||||
- Print more err message
|
||||
|
||||
#### v2019-02-19
|
||||
|
||||
- Download AlbumCover
|
||||
- Set Track Metadata
|
||||
|
||||
#### v2019-02-14
|
||||
|
||||
- Set music-filetype by StreamUrlInfo
|
||||
|
||||
#### v2019-01-28
|
||||
|
||||
- Add decryption.py -- Download LOSSLESS music
|
||||
|
||||
#### v2018-12-28
|
||||
|
||||
- Add Progressbar - Download Video
|
||||
|
||||
#### v2018-12-19
|
||||
|
||||
- Update ffmpegHelper
|
||||
- Simplified Code
|
||||
|
||||
#### v2018-12-11
|
||||
|
||||
- Fuc: Download Playlist Video
|
||||
|
||||
#### v2018-12-01
|
||||
|
||||
- Optimized Code
|
||||
- Multithreading Download Video
|
||||
- Fuc: Download Playlist
|
||||
|
||||
#### v2018-11-22
|
||||
|
||||
- Multithreading Download
|
||||
- Fuc: Download Track
|
||||
- Fuc: Download Video
|
||||
|
||||
#### v2018-11-21
|
||||
|
||||
- Func: Download Album
|
||||
- Func: Get SessionID By Account
|
||||
- Upload Version To PIP Server : pip install tidal-dl
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
REM cd to workdir
|
||||
cd %~dp0
|
||||
|
||||
REM remove old dir
|
||||
rmdir /s/q dist
|
||||
rmdir /s/q build
|
||||
rmdir /s/q exe
|
||||
rmdir /s/q tidal_dl.egg-info
|
||||
mkdir exe
|
||||
|
||||
REM pack
|
||||
python setup.py sdist bdist_wheel
|
||||
|
||||
REM creat exe file
|
||||
pyinstaller -F tidal_dl/__main__.py
|
||||
|
||||
REM rename exe name
|
||||
cd dist
|
||||
ren __main__.exe tidal-dl.exe
|
||||
move tidal-dl.exe ../exe/
|
||||
cd ..
|
||||
|
||||
pip uninstall -y tidal-dl
|
||||
REM python setup.py install
|
||||
|
||||
REM upload version to pip server
|
||||
twine upload dist/*
|
||||
@@ -1,34 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29709.97
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TIDALDL-UI", "TIDALDL-UI\TIDALDL-UI.csproj", "{87F39F78-056F-4747-A835-12BA03FE575A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
CD_ROM|Any CPU = CD_ROM|Any CPU
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
DVD-5|Any CPU = DVD-5|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
SingleImage|Any CPU = SingleImage|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{87F39F78-056F-4747-A835-12BA03FE575A}.CD_ROM|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{87F39F78-056F-4747-A835-12BA03FE575A}.CD_ROM|Any CPU.Build.0 = Release|Any CPU
|
||||
{87F39F78-056F-4747-A835-12BA03FE575A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{87F39F78-056F-4747-A835-12BA03FE575A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{87F39F78-056F-4747-A835-12BA03FE575A}.DVD-5|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{87F39F78-056F-4747-A835-12BA03FE575A}.DVD-5|Any CPU.Build.0 = Debug|Any CPU
|
||||
{87F39F78-056F-4747-A835-12BA03FE575A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{87F39F78-056F-4747-A835-12BA03FE575A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{87F39F78-056F-4747-A835-12BA03FE575A}.SingleImage|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{87F39F78-056F-4747-A835-12BA03FE575A}.SingleImage|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {EE9828BC-5446-4422-83D6-9103517072A3}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="ICSharpCode.SharpZipLib" publicKeyToken="1b03e6acf1164f73" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.2.0.246" newVersion="1.2.0.246" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
Binary file not shown.
@@ -1,17 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace TIDALDL_UI
|
||||
{
|
||||
/// <summary>
|
||||
/// App.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -1,277 +0,0 @@
|
||||
using AIGS.Helper;
|
||||
using NPinyin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TIDALDL_UI.Else
|
||||
{
|
||||
public class CloudMusicArtist
|
||||
{
|
||||
public int id { get; set; }
|
||||
public string name { get; set; }
|
||||
public string picUrl { get; set; }
|
||||
public List<string> alias { get; set; }
|
||||
public List<string> alia { get; set; }
|
||||
public int albumSize { get; set; }
|
||||
public string picId { get; set; }
|
||||
public string img1v1Url { get; set; }
|
||||
public string img1v1 { get; set; }
|
||||
public int mvSize { get; set; }
|
||||
public bool followed { get; set; }
|
||||
public string trans { get; set; }
|
||||
}
|
||||
|
||||
public class CloudMusicAlbum
|
||||
{
|
||||
public int id { get; set; }
|
||||
public string name { get; set; }
|
||||
public string type { get; set; }
|
||||
public int size { get; set; }
|
||||
public string picId { get; set; }
|
||||
public string blurPicUrl { get; set; }
|
||||
public string pic { get; set; }
|
||||
public string picUrl { get; set; }
|
||||
public string publishTime { get; set; }
|
||||
public string description { get; set; }
|
||||
public int companyId { get; set; }
|
||||
public List<string> tags { get; set; }
|
||||
public string company { get; set; }
|
||||
public string briefDesc { get; set; }
|
||||
public CloudMusicArtist artist { get; set; }
|
||||
public List<CloudMusicSong> songs { get; set; }
|
||||
public List<string> alias { get; set; }
|
||||
public int status { get; set; }
|
||||
public int copyrightId { get; set; }
|
||||
public string commentThreadId { get; set; }
|
||||
public List<CloudMusicArtist> artists { get; set; }
|
||||
public string picId_str { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class CloudMusicSong
|
||||
{
|
||||
public string name { get; set; }
|
||||
public int id { get; set; }
|
||||
public bool starred { get; set; }
|
||||
public int starredNum { get; set; }
|
||||
public int playedNum { get; set; }
|
||||
public int dayPlays { get; set; }
|
||||
public int hearTime { get; set; }
|
||||
public double popularity { get; set; }
|
||||
public string mp3Url { get; set; }
|
||||
public string rtUrls { get; set; }
|
||||
public int mark { get; set; }
|
||||
public List<CloudMusicArtist> artists { get; set; }
|
||||
public List<string> alias { get; set; }
|
||||
public int mvid { get; set; }
|
||||
public int duration { get; set; }
|
||||
public int position { get; set; }
|
||||
}
|
||||
|
||||
public class DoubanMusicRecord
|
||||
{
|
||||
public string alt_title { get; set; }
|
||||
public string image { get; set; }
|
||||
public string mobile_link { get; set; }
|
||||
public string title { get; set; }
|
||||
public string alt { get; set; }
|
||||
public string id { get; set; }
|
||||
public DoubanMusicAttr attrs { get; set; }
|
||||
public DoubanMusicRating rating { get; set; }
|
||||
public List<DoubanMusicAuthor> author { get; set; }
|
||||
public List<DoubanMusicTag> tags { get; set; }
|
||||
}
|
||||
|
||||
public class DoubanMusicRating
|
||||
{
|
||||
public int max { get; set; }
|
||||
public int min { get; set; }
|
||||
public int numRaters { get; set; }
|
||||
public string average { get; set; }
|
||||
}
|
||||
|
||||
public class DoubanMusicAuthor
|
||||
{
|
||||
public string name { get; set; }
|
||||
}
|
||||
|
||||
public class DoubanMusicTag
|
||||
{
|
||||
public string name { get; set; }
|
||||
public int count { get; set; }
|
||||
}
|
||||
|
||||
public class DoubanMusicAttr
|
||||
{
|
||||
public List<string> publisher { get; set; }
|
||||
public List<string> singer { get; set; }
|
||||
public List<string> version { get; set; }
|
||||
public List<string> pubdate { get; set; }
|
||||
public List<string> title { get; set; }
|
||||
public List<string> media { get; set; }
|
||||
public List<string> tracks { get; set; }
|
||||
public List<string> discs { get; set; }
|
||||
}
|
||||
|
||||
public class Chinese
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据专辑和歌手获取匹配的网易云专辑
|
||||
/// </summary>
|
||||
/// <param name="sAlbumName">专辑名</param>
|
||||
/// <param name="sArtistName">歌手</param>
|
||||
/// <returns></returns>
|
||||
public static CloudMusicAlbum matchAlbum(string sAlbumName, string sArtistName)
|
||||
{
|
||||
//使用豆瓣接口搜索专辑,支持英文、中文、繁体搜索
|
||||
string serr;
|
||||
string stxt = (string)HttpHelper.GetOrPost("https://api.douban.com/v2/music/search?q=" + sAlbumName, out serr);
|
||||
List<DoubanMusicRecord> pDoubans = JsonHelper.ConverStringToObject<List<DoubanMusicRecord>>(stxt, "musics");
|
||||
|
||||
//使用网易云接口搜索歌手
|
||||
string stxt2 = (string)HttpHelper.GetOrPost(string.Format("http://music.163.com/api/search/pc?s={0}&type=100&limit=10&offset=0", sArtistName), out serr);
|
||||
List<CloudMusicArtist> pClounds = JsonHelper.ConverStringToObject<List<CloudMusicArtist>>(stxt2, "result", "artists");
|
||||
|
||||
//匹配
|
||||
int iIndex1 = -1;
|
||||
int iIndex2 = -1;
|
||||
for (int i = 0; pClounds != null && i < pClounds.Count && iIndex1 == -1; i++)
|
||||
{
|
||||
string skey = pClounds[i].name;
|
||||
for (int j = 0; pDoubans != null && j < pDoubans.Count && iIndex1 == -1; j++)
|
||||
{
|
||||
for (int k = 0; pDoubans[j].author != null && k < pDoubans[j].author.Count; k++)
|
||||
{
|
||||
string stmp = converSimpleChinese(pDoubans[j].author[k].name);
|
||||
if (skey == stmp || skey.Contains(stmp) || stmp.Contains(skey) || stmp == sArtistName)
|
||||
{
|
||||
iIndex1 = i;
|
||||
iIndex2 = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (iIndex1 < 0)
|
||||
return null;
|
||||
|
||||
string sname = converSimpleChinese(pDoubans[iIndex2].title);
|
||||
string stxt3 = (string)HttpHelper.GetOrPost(string.Format("http://music.163.com/api/search/pc?s={0}&type=10&limit=30&offset=0", sname), out serr);
|
||||
List<CloudMusicAlbum> pCloundAlbums = JsonHelper.ConverStringToObject<List<CloudMusicAlbum>>(stxt3, "result", "albums");
|
||||
|
||||
//匹配
|
||||
int iIndex3 = -1;
|
||||
for (int i = 0; pCloundAlbums != null && i < pCloundAlbums.Count; i++)
|
||||
{
|
||||
if (pCloundAlbums[i].artist.name == pClounds[iIndex1].name &&
|
||||
pCloundAlbums[i].name == sname)
|
||||
{
|
||||
iIndex3 = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (iIndex3 < 0)
|
||||
return null;
|
||||
|
||||
string stxt4 = (string)HttpHelper.GetOrPost(string.Format("http://music.163.com/api/album/{0}?ext=true&id={1}&offset=0&total=true&limit=10", pCloundAlbums[iIndex3].id.ToString(), pCloundAlbums[0].id.ToString()), out serr);
|
||||
CloudMusicAlbum pAlbum = JsonHelper.ConverStringToObject<CloudMusicAlbum>(stxt4, "album");
|
||||
return pAlbum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从专辑信息中获取歌曲的中文名
|
||||
/// </summary>
|
||||
/// <param name="sName"></param>
|
||||
/// <param name="pAlbum"></param>
|
||||
/// <returns></returns>
|
||||
public static string convertSongTitle(string sName, CloudMusicAlbum pAlbum)
|
||||
{
|
||||
if (pAlbum == null || pAlbum.songs.Count <= 0)
|
||||
return sName;
|
||||
|
||||
int iIndex = -1;
|
||||
int iWeight = 0;
|
||||
for (int i = 0; i < pAlbum.songs.Count; i++)
|
||||
{
|
||||
int iTmp = calcWeight(sName, pAlbum.songs[i].name);
|
||||
if (iTmp > iWeight)
|
||||
{
|
||||
iIndex = i;
|
||||
iWeight = iTmp;
|
||||
}
|
||||
}
|
||||
if (iIndex < 0)
|
||||
return sName;
|
||||
return pAlbum.songs[iIndex].name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算匹配度权重值
|
||||
/// </summary>
|
||||
/// <param name="sEngName"></param>
|
||||
/// <param name="sChnName"></param>
|
||||
/// <returns></returns>
|
||||
static int calcWeight(string sEngName, string sChnName)
|
||||
{
|
||||
//转拼音
|
||||
StringBuilder sPinyinName = new StringBuilder();
|
||||
for (int i = 0; i < sChnName.Length; i++)
|
||||
{
|
||||
if (StringHelper.IsChinese(sChnName[i]))
|
||||
sPinyinName.Append(Pinyin.GetPinyin(sChnName[i]) + ' ');
|
||||
else
|
||||
sPinyinName.Append(sChnName[i]);
|
||||
}
|
||||
|
||||
int iRet = 0;
|
||||
//删除括号
|
||||
if (sEngName.IndexOf('(') >= 0)
|
||||
sEngName = sEngName.Substring(0, sEngName.IndexOf('('));
|
||||
if (sChnName.IndexOf('(') >= 0)
|
||||
sChnName = sChnName.Substring(0, sChnName.IndexOf('('));
|
||||
sEngName = sEngName.Trim().ToLower();
|
||||
sChnName = sPinyinName.ToString().Trim().ToLower();
|
||||
if (sEngName.Contains(sChnName) || sChnName.Contains(sEngName))
|
||||
iRet += 100;
|
||||
|
||||
string[] sArr1 = sEngName.Split(' ');
|
||||
string[] sArr2 = sChnName.ToString().Trim().ToLower().Split(' ');
|
||||
for (int i = 0; i < sArr1.Count() && i < sArr2.Count(); i++)
|
||||
{
|
||||
string sitem = sArr1[i];
|
||||
string sitem2 = sArr2[i];
|
||||
for (int j = 0; j < sitem.Length && j < sitem2.Length; j++)
|
||||
{
|
||||
if (sitem[j] == sitem2[j])
|
||||
iRet++;
|
||||
}
|
||||
}
|
||||
|
||||
if (iRet <= 0)
|
||||
return 0;
|
||||
if (sArr1.Count() == sArr2.Count())
|
||||
iRet += 100;
|
||||
return iRet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 繁体转简体
|
||||
/// </summary>
|
||||
static string converSimpleChinese(string str)
|
||||
{
|
||||
StringBuilder ret = new StringBuilder();
|
||||
for (int i = 0; i < str.Length; i++)
|
||||
{
|
||||
if (StringHelper.IsChinese(str[i]))
|
||||
ret.Append(Microsoft.VisualBasic.Strings.StrConv(str[i].ToString(), Microsoft.VisualBasic.VbStrConv.SimplifiedChinese, 0));
|
||||
else
|
||||
ret.Append(str[i]);
|
||||
}
|
||||
return ret.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,355 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AIGS.Common;
|
||||
using AIGS.Helper;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace TIDALDL_UI.Else
|
||||
{
|
||||
public class Config
|
||||
{
|
||||
private static string CONFIGPATH = "./tidal-dl.ini";
|
||||
private static string BASEGROUP = "base";
|
||||
private static string HISTORYGROUP = "history";
|
||||
|
||||
private static string SetOrGet(string Key, string SetValue = null, string GetDefault = "", string Group = null)
|
||||
{
|
||||
if (Group.IsBlank())
|
||||
Group = BASEGROUP;
|
||||
if (SetValue.IsBlank())
|
||||
return ConfigHelper.GetValue(Key, GetDefault, Group, CONFIGPATH);
|
||||
else
|
||||
ConfigHelper.SetValue(Key, SetValue, Group, CONFIGPATH);
|
||||
return null;
|
||||
}
|
||||
private static string SetOrGetPrivate(string Key, string SetValue = null, string GetDefault = "", string Group = null)
|
||||
{
|
||||
if (Group.IsBlank())
|
||||
Group = BASEGROUP;
|
||||
if (SetValue.IsBlank())
|
||||
{
|
||||
string sTmp = ConfigHelper.GetValue(Key, GetDefault, Group, CONFIGPATH);
|
||||
return Decode(sTmp);
|
||||
}
|
||||
else
|
||||
ConfigHelper.SetValue(Key, Encode(SetValue), Group, CONFIGPATH);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
#region Base Config
|
||||
public static string Version(string Setvalue = null)
|
||||
{
|
||||
return SetOrGet("version", Setvalue, "null");
|
||||
}
|
||||
|
||||
public static string OutputDir(string Setvalue = null)
|
||||
{
|
||||
return SetOrGet("outputdir", Setvalue, "./");
|
||||
}
|
||||
|
||||
public static bool OnlyM4a(string Setvalue = null)
|
||||
{
|
||||
string sValue = SetOrGet("onlym4a", Setvalue, "true");
|
||||
if (sValue == null || sValue.ToLower() != "true")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool AddExplicitTag(string Setvalue = null)
|
||||
{
|
||||
string sValue = SetOrGet("addexplicit", Setvalue, "false");
|
||||
if (sValue == null || sValue.ToLower() != "true")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IncludeEP(string Setvalue = null)
|
||||
{
|
||||
string sValue = SetOrGet("includesingle", Setvalue, "false");
|
||||
if (sValue == null || sValue.ToLower() != "true")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SaveCovers(string Setvalue = null)
|
||||
{
|
||||
string sValue = SetOrGet("savephoto", Setvalue, "true");
|
||||
if (sValue == null || sValue.ToLower() != "true")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool AddHyphen(string Setvalue = null)
|
||||
{
|
||||
string sValue = SetOrGet("addhyphen", Setvalue, "true");
|
||||
if (sValue == null || sValue.ToLower() != "true")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool UseTrackNumber(string Setvalue = null)
|
||||
{
|
||||
string sValue = SetOrGet("useTrackNumber", Setvalue, "true");
|
||||
if (sValue == null || sValue.ToLower() != "true")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string Quality(string Setvalue = null)
|
||||
{
|
||||
return SetOrGet("quality", Setvalue, "HIGH");
|
||||
}
|
||||
|
||||
public static int AddYear(int Setvalue = -1)
|
||||
{
|
||||
if (Setvalue == -1)
|
||||
{
|
||||
string sValue = SetOrGet("addyear", null, "No").ToLower();
|
||||
if (sValue == "before")
|
||||
return 1;
|
||||
else if (sValue == "after")
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
string sValue = "No";
|
||||
if (Setvalue == 1)
|
||||
sValue = "Before";
|
||||
if (Setvalue == 2)
|
||||
sValue = "After";
|
||||
SetOrGet("addyear", sValue, "No");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<int, string> QualityList()
|
||||
{
|
||||
return AIGS.Common.Convert.ConverEnumToDictionary(typeof(Tidal.eSoundQuality));
|
||||
}
|
||||
|
||||
public static int QualityIndex()
|
||||
{
|
||||
string sValue = Config.Quality();
|
||||
Dictionary<int, string> pList = QualityList();
|
||||
for (int i = 0; i < pList.Count; i++)
|
||||
{
|
||||
if (sValue.ToUpper() == pList.ElementAt(i).Value)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static string ThreadNum(string Setvalue = null)
|
||||
{
|
||||
return SetOrGet("threadnum", Setvalue, "1");
|
||||
//SetOrGet("threadnum", Setvalue, "1");
|
||||
//return "1";
|
||||
}
|
||||
|
||||
public static string SearchNum(string Setvalue = null)
|
||||
{
|
||||
return SetOrGet("searchnum", Setvalue, "30");
|
||||
}
|
||||
|
||||
public static string Username(string Setvalue = null)
|
||||
{
|
||||
return SetOrGet("username", Setvalue, "");
|
||||
}
|
||||
|
||||
public static string Password(string Setvalue = null)
|
||||
{
|
||||
return SetOrGetPrivate("password", Setvalue, "");
|
||||
}
|
||||
|
||||
public static string Sessionid(string Setvalue = null)
|
||||
{
|
||||
return SetOrGet("sessionid", Setvalue, "");
|
||||
}
|
||||
|
||||
public static string Countrycode(string Setvalue = null)
|
||||
{
|
||||
return SetOrGet("countrycode", Setvalue, "");
|
||||
}
|
||||
|
||||
public static string Userid(string Setvalue = null)
|
||||
{
|
||||
return SetOrGet("userid", Setvalue, "");
|
||||
}
|
||||
|
||||
public static bool Remember(string Setvalue = null)
|
||||
{
|
||||
string sRet = SetOrGet("remember", Setvalue, "true");
|
||||
if (sRet.IsNotBlank() && sRet.ToLower() == "true")
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ToChinese(string Setvalue = null)
|
||||
{
|
||||
string sRet = SetOrGet("tochinese", Setvalue, "false");
|
||||
if (sRet.IsNotBlank() && sRet.ToLower() == "true")
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool CheckExist(string Setvalue = null)
|
||||
{
|
||||
string sRet = SetOrGet("checkexist", Setvalue, "false");
|
||||
if (sRet.IsNotBlank() && sRet.ToLower() == "true")
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ArtistBeforeTitle(string Setvalue = null)
|
||||
{
|
||||
string sRet = SetOrGet("artistbeforetitle", Setvalue, "false");
|
||||
if (sRet.IsNotBlank() && sRet.ToLower() == "true")
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool AutoLogin(string Setvalue = null)
|
||||
{
|
||||
string sRet = SetOrGet("autologin", Setvalue, "true");
|
||||
if (sRet.IsNotBlank() && sRet.ToLower() == "true")
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string Resolution(string Setvalue = null)
|
||||
{
|
||||
return SetOrGet("resolution", Setvalue, "e720P");
|
||||
}
|
||||
|
||||
public static bool ProxyEnable(string Setvalue = null)
|
||||
{
|
||||
string sRet = SetOrGet("proxyenable", Setvalue, "false");
|
||||
if (sRet.IsNotBlank() && sRet.ToLower() == "true")
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string ProxyHost(string Setvalue = null)
|
||||
{
|
||||
return SetOrGet("proxyhost", Setvalue, "");
|
||||
}
|
||||
|
||||
public static int ProxyPort(string Setvalue = null)
|
||||
{
|
||||
string sValue = SetOrGet("proxyport", Setvalue, "");
|
||||
return AIGS.Common.Convert.ConverStringToInt(sValue, 0);
|
||||
}
|
||||
|
||||
public static string ProxyUser(string Setvalue = null)
|
||||
{
|
||||
return SetOrGet("proxyuser", Setvalue, "");
|
||||
}
|
||||
|
||||
public static string ProxyPwd(string Setvalue = null)
|
||||
{
|
||||
return SetOrGet("proxypwd", Setvalue, "");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region History Account
|
||||
/// <summary>
|
||||
/// Get History Account List
|
||||
/// </summary>
|
||||
public static List<Property> HistoryAccounts()
|
||||
{
|
||||
List<Property> pRet = new List<Property>();
|
||||
string sValue = SetOrGet("historyusernum", null, "", HISTORYGROUP);
|
||||
int iNum = AIGS.Common.Convert.ConverStringToInt(sValue, 0);
|
||||
for (int i = 0; i < iNum; i++)
|
||||
{
|
||||
string sUser = SetOrGet("historyuser" + i, null, "", HISTORYGROUP);
|
||||
string sPwd = SetOrGetPrivate("historypwd" + i, null, "", HISTORYGROUP);
|
||||
if (sUser.IsNotBlank() && pRet.FindIndex((Property user) => user.Key.ToString() == sUser) < 0)
|
||||
pRet.Add(new Property(sUser, sPwd));
|
||||
}
|
||||
return pRet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add Account To Config File
|
||||
/// </summary>
|
||||
public static void AddHistoryAccount(string sUsername, string sPassword)
|
||||
{
|
||||
List<Property> pArray = HistoryAccounts();
|
||||
int iIndex = pArray.FindIndex((Property user) => user.Key.ToString() == sUsername);
|
||||
if (iIndex >= 0)
|
||||
pArray.RemoveAt(iIndex);
|
||||
|
||||
pArray.Insert(0, new Property(sUsername, sPassword));
|
||||
for (int i = 0; i < pArray.Count; i++)
|
||||
{
|
||||
SetOrGet("historyuser" + i, pArray[i].Key.ToString(), "", HISTORYGROUP);
|
||||
SetOrGetPrivate("historypwd" + i, pArray[i].Value.ToString(), "", HISTORYGROUP);
|
||||
}
|
||||
SetOrGet("historyusernum", pArray.Count.ToString(), "", HISTORYGROUP);
|
||||
Username(sUsername);
|
||||
Password(sPassword);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region History Search
|
||||
/// <summary>
|
||||
/// Get History Search List
|
||||
/// </summary>
|
||||
public static ObservableCollection<string> HistorySearchs()
|
||||
{
|
||||
ObservableCollection<string> pRet = new ObservableCollection<string>();
|
||||
string sValue = SetOrGet("historysearchnum", null, "", HISTORYGROUP);
|
||||
int iNum = AIGS.Common.Convert.ConverStringToInt(sValue, 0);
|
||||
for (int i = 0; i < iNum; i++)
|
||||
{
|
||||
string sStr = SetOrGet("historysearch" + i, null, "", HISTORYGROUP);
|
||||
if (sStr.IsNotBlank() && pRet.IndexOf(sStr) < 0)
|
||||
pRet.Add(sStr);
|
||||
}
|
||||
return pRet;
|
||||
}
|
||||
/// <summary>
|
||||
/// Add Search To Config File
|
||||
/// </summary>
|
||||
public static void AddHistorySearch(string sNewStr)
|
||||
{
|
||||
ObservableCollection<string> pArray = HistorySearchs();
|
||||
int iIndex = pArray.IndexOf(sNewStr);
|
||||
if (iIndex >= 0)
|
||||
pArray.RemoveAt(iIndex);
|
||||
|
||||
pArray.Insert(0, sNewStr);
|
||||
for (int i = 0; i < pArray.Count; i++)
|
||||
SetOrGet("historysearch" + i, pArray[i], "", HISTORYGROUP);
|
||||
SetOrGet("historysearchnum", pArray.Count.ToString(), "", HISTORYGROUP);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Encryption
|
||||
private static string EncryptionFlag = "Ax*~!9";
|
||||
private static string Encode(string sStr)
|
||||
{
|
||||
if (sStr.IsBlank())
|
||||
return sStr;
|
||||
string sTmp = EncryptHelper.Encode(sStr, Tidal.TidalTool.USER_INFO_KEY);
|
||||
return EncryptionFlag + sTmp;
|
||||
}
|
||||
private static string Decode(string data)
|
||||
{
|
||||
if (data.IsBlank())
|
||||
return data;
|
||||
if (data.IndexOf(EncryptionFlag) != 0)
|
||||
return data;
|
||||
string sTmp = data.Substring(EncryptionFlag.Length);
|
||||
return EncryptHelper.Decode(sTmp, Tidal.TidalTool.USER_INFO_KEY);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,282 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Tidal;
|
||||
using AIGS.Common;
|
||||
using AIGS.Helper;
|
||||
using Stylet;
|
||||
using TagLib;
|
||||
using System.IO;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace TIDALDL_UI.Else
|
||||
{
|
||||
public class DownloadItem : Screen
|
||||
{
|
||||
public Playlist TidalPlaylist { get; set; }
|
||||
public Album TidalAlbum { get; set; }
|
||||
public Track TidalTrack { get; set; }
|
||||
public Video TidalVideo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Item Para - OutputDir | FilePath | Track Quality | Title | Type
|
||||
/// </summary>
|
||||
public string OutputDir { get; set; }
|
||||
public string FilePath { get; set; }
|
||||
public eSoundQuality Quality { get; set; }
|
||||
public eResolution Resolution { get; set; }
|
||||
public int Index { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string sType { get; set; }
|
||||
public int ErrlabelHeight { get; set; }
|
||||
public bool OnlyM4a { get; set; }
|
||||
public bool AddHyphen { get; set; }
|
||||
public bool UseTrackNumber { get; set; }
|
||||
public string Own { get; set; }
|
||||
public bool ToChinese { get; set; }
|
||||
public bool CheckExist { get; set; }
|
||||
public bool ArtistBeforeTitle { get; set; }
|
||||
public bool AddExplict { get; set; }
|
||||
public int AddYear { get; set; }
|
||||
|
||||
///// <summary>
|
||||
///// Progress
|
||||
///// </summary>
|
||||
public ProgressHelper Progress { get; set; }
|
||||
|
||||
public DownloadItem(int index, Track track = null, Video video = null, Album album = null, Playlist plist = null)
|
||||
{
|
||||
TidalPlaylist = plist;
|
||||
TidalAlbum = album;
|
||||
TidalVideo = video;
|
||||
TidalTrack = track;
|
||||
Quality = TidalTool.getQuality(Config.Quality());
|
||||
Resolution = TidalTool.getResolution(Config.Resolution());
|
||||
OutputDir = Config.OutputDir();
|
||||
Index = index;
|
||||
Progress = new ProgressHelper();
|
||||
OnlyM4a = Config.OnlyM4a();
|
||||
AddHyphen = Config.AddHyphen();
|
||||
UseTrackNumber = Config.UseTrackNumber();
|
||||
Own = album == null?null : album.Title;
|
||||
ToChinese = Config.ToChinese();
|
||||
CheckExist = Config.CheckExist();
|
||||
ArtistBeforeTitle = Config.ArtistBeforeTitle();
|
||||
AddExplict = Config.AddExplicitTag();
|
||||
AddYear = Config.AddYear();
|
||||
|
||||
if (TidalTrack != null)
|
||||
{
|
||||
Title = track.Title;
|
||||
sType = "MusicCircle";
|
||||
}
|
||||
else
|
||||
{
|
||||
Title = video.Title;
|
||||
sType = "PlayCircle";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region Method
|
||||
public void Start()
|
||||
{
|
||||
//Add to threadpool
|
||||
ThreadTool.AddWork((object[] data) =>
|
||||
{
|
||||
if (Progress.GetStatus() != ProgressHelper.STATUS.WAIT)
|
||||
return;
|
||||
|
||||
ErrlabelHeight = 0;
|
||||
Progress.SetStatus(ProgressHelper.STATUS.RUNNING);
|
||||
if (TidalTrack != null)
|
||||
DownloadTrack();
|
||||
else
|
||||
DownloadVideo();
|
||||
});
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
if (Progress.GetStatus() != ProgressHelper.STATUS.COMPLETE)
|
||||
Progress.SetStatus(ProgressHelper.STATUS.CANCLE);
|
||||
}
|
||||
|
||||
public void Restart()
|
||||
{
|
||||
ProgressHelper.STATUS status = Progress.GetStatus();
|
||||
if (status == ProgressHelper.STATUS.CANCLE || status == ProgressHelper.STATUS.ERROR)
|
||||
{
|
||||
Progress.Clear();
|
||||
Start();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region DownloadVideo
|
||||
public bool ProgressNotify(long lCurSize, long lAllSize)
|
||||
{
|
||||
Progress.Update(lCurSize, lAllSize);
|
||||
if (Progress.GetStatus() != ProgressHelper.STATUS.RUNNING)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void DownloadVideo()
|
||||
{
|
||||
//GetStream
|
||||
Progress.StatusMsg = "GetStream...";
|
||||
string Errlabel = "";
|
||||
string[] TidalVideoUrls = TidalTool.getVideoDLUrls(TidalVideo.ID.ToString(), Resolution, out Errlabel);
|
||||
if (Errlabel.IsNotBlank())
|
||||
goto ERR_RETURN;
|
||||
string TsFilePath = TidalTool.getVideoPath(OutputDir, TidalVideo, TidalAlbum, ".ts", hyphen: AddHyphen, plist: TidalPlaylist, artistBeforeTitle:ArtistBeforeTitle, addYear:AddYear);
|
||||
|
||||
//Download
|
||||
Progress.StatusMsg = "Start...";
|
||||
if(!(bool)M3u8Helper.Download(TidalVideoUrls, TsFilePath, ProgressNotify, Proxy:TidalTool.PROXY))
|
||||
{
|
||||
Errlabel = "Download failed!";
|
||||
goto ERR_RETURN;
|
||||
}
|
||||
|
||||
//Convert
|
||||
FilePath = TidalTool.getVideoPath(OutputDir, TidalVideo, TidalAlbum, hyphen:AddHyphen, plist:TidalPlaylist, artistBeforeTitle: ArtistBeforeTitle, addYear: AddYear);
|
||||
if(!FFmpegHelper.IsExist())
|
||||
{
|
||||
Errlabel = "FFmpeg is not exist!";
|
||||
goto ERR_RETURN;
|
||||
}
|
||||
if (!FFmpegHelper.Convert(TsFilePath, FilePath))
|
||||
{
|
||||
Errlabel = "Convert failed!";
|
||||
goto ERR_RETURN;
|
||||
}
|
||||
System.IO.File.Delete(TsFilePath);
|
||||
Progress.SetStatus(ProgressHelper.STATUS.COMPLETE);
|
||||
return;
|
||||
|
||||
ERR_RETURN:
|
||||
if (Progress.GetStatus() == ProgressHelper.STATUS.CANCLE)
|
||||
return;
|
||||
|
||||
ErrlabelHeight = 15;
|
||||
Progress.SetStatus(ProgressHelper.STATUS.ERROR);
|
||||
Progress.Errmsg = Errlabel;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region DownloadTrack
|
||||
public void DownloadTrack()
|
||||
{
|
||||
string Errlabel = "";
|
||||
|
||||
//GetStream
|
||||
Progress.StatusMsg = "GetStream...";
|
||||
StreamUrl TidalStream = TidalTool.getStreamUrl(TidalTrack.ID.ToString(), Quality, out Errlabel);
|
||||
if (Errlabel.IsNotBlank())
|
||||
goto ERR_RETURN;
|
||||
|
||||
//Get path
|
||||
FilePath = TidalTool.getTrackPath(OutputDir, TidalAlbum, TidalTrack, TidalStream.Url,
|
||||
AddHyphen, TidalPlaylist, artistBeforeTitle: ArtistBeforeTitle, addexplicit: AddExplict,
|
||||
addYear: AddYear, useTrackNumber: UseTrackNumber);
|
||||
|
||||
|
||||
//Check if song is downloaded already
|
||||
string CheckName = OnlyM4a ? FilePath.Replace(".mp4", ".m4a") : FilePath;
|
||||
if (CheckExist && System.IO.File.Exists(CheckName))
|
||||
{
|
||||
Progress.Update(100, 100);
|
||||
Progress.SetStatus(ProgressHelper.STATUS.COMPLETE);
|
||||
return;
|
||||
}
|
||||
|
||||
//Get contributors
|
||||
ObservableCollection<Contributor> pContributors = TidalTool.getTrackContributors(TidalTrack.ID.ToString(), out Errlabel);
|
||||
|
||||
//To chinese
|
||||
if (ToChinese)
|
||||
{
|
||||
CloudMusicAlbum cloalbum = Chinese.matchAlbum(TidalAlbum.Title, TidalAlbum.Artist.Name);
|
||||
string chnname = Chinese.convertSongTitle(TidalTrack.Title, cloalbum);
|
||||
if (chnname != TidalTrack.Title)
|
||||
{
|
||||
FilePath = TidalTool.getTrackPath(OutputDir, TidalPlaylist != null ? null : TidalAlbum, TidalTrack, TidalStream.Url,
|
||||
AddHyphen, TidalPlaylist, chnname, artistBeforeTitle: ArtistBeforeTitle, addexplicit: AddExplict,
|
||||
addYear: AddYear, useTrackNumber: UseTrackNumber);
|
||||
TidalTrack.Title = chnname;
|
||||
}
|
||||
}
|
||||
|
||||
//Download
|
||||
Progress.StatusMsg = "Start...";
|
||||
for (int i = 0; i < 100 && Progress.GetStatus() != ProgressHelper.STATUS.CANCLE; i++)
|
||||
{
|
||||
if ((bool)DownloadFileHepler.Start(TidalStream.Url, FilePath, Timeout: 5 * 1000, UpdateFunc: UpdateDownloadNotify, ErrFunc: ErrDownloadNotify, Proxy:TidalTool.PROXY))
|
||||
{
|
||||
//Decrypt
|
||||
if (!TidalTool.DecryptTrackFile(TidalStream, FilePath))
|
||||
{
|
||||
Errlabel = "Decrypt failed!";
|
||||
goto ERR_RETURN;
|
||||
}
|
||||
|
||||
if(OnlyM4a)
|
||||
{
|
||||
string sNewName;
|
||||
if (!TidalTool.ConvertMp4ToM4a(FilePath, out sNewName))
|
||||
{
|
||||
Errlabel = "Convert mp4 to m4a failed!";
|
||||
goto ERR_RETURN;
|
||||
}
|
||||
else
|
||||
FilePath = sNewName;
|
||||
}
|
||||
|
||||
//SetMetaData
|
||||
if (TidalAlbum == null && TidalTrack.Album != null)
|
||||
{
|
||||
string sErrcode = null;
|
||||
TidalAlbum = TidalTool.getAlbum(TidalTrack.Album.ID.ToString(), out sErrcode);
|
||||
}
|
||||
string sLabel = TidalTool.SetMetaData(FilePath, TidalAlbum, TidalTrack, TidalTool.getAlbumCoverPath(OutputDir, TidalAlbum, AddYear), pContributors);
|
||||
if (sLabel.IsNotBlank())
|
||||
{
|
||||
Errlabel = "Set metadata failed!";
|
||||
goto ERR_RETURN;
|
||||
}
|
||||
|
||||
Progress.SetStatus(ProgressHelper.STATUS.COMPLETE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Errlabel = "Download failed!";
|
||||
|
||||
ERR_RETURN:
|
||||
if (Progress.GetStatus() == ProgressHelper.STATUS.CANCLE)
|
||||
return;
|
||||
|
||||
ErrlabelHeight = 15;
|
||||
Progress.SetStatus(ProgressHelper.STATUS.ERROR);
|
||||
Progress.Errmsg = Errlabel;
|
||||
}
|
||||
|
||||
public void ErrDownloadNotify(long lTotalSize, long lAlreadyDownloadSize, string sErrMsg, object data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public bool UpdateDownloadNotify(long lTotalSize, long lAlreadyDownloadSize, long lIncreSize, object data)
|
||||
{
|
||||
Progress.Update(lAlreadyDownloadSize, lTotalSize);
|
||||
if (Progress.GetStatus() != ProgressHelper.STATUS.RUNNING)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AIGS.Helper;
|
||||
using AIGS.Common;
|
||||
using System.Threading;
|
||||
|
||||
namespace TIDALDL_UI.Else
|
||||
{
|
||||
public class ThreadTool
|
||||
{
|
||||
private static ThreadPoolManager Pool = new ThreadPoolManager(1);
|
||||
|
||||
public static void SetThreadNum(int iNum)
|
||||
{
|
||||
if (iNum < 1)
|
||||
iNum = 1;
|
||||
Pool.SetPoolSize(iNum);
|
||||
}
|
||||
|
||||
public static int GetThreadNum()
|
||||
{
|
||||
if (Pool == null)
|
||||
return 0;
|
||||
return Pool.GetPoolSize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add Download
|
||||
/// </summary>
|
||||
public static bool AddWork(ThreadPoolManager.EventFunc Func, object[] data=null)
|
||||
{
|
||||
if (Pool == null)
|
||||
return false;
|
||||
Pool.AddWork(Func, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End
|
||||
/// </summary>
|
||||
public static void Close()
|
||||
{
|
||||
if (Pool == null)
|
||||
return;
|
||||
Pool.CloseAll(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<PropertyChanged/>
|
||||
<Costura>
|
||||
<ExcludeAssemblies>
|
||||
Foo
|
||||
Bar
|
||||
</ExcludeAssemblies>
|
||||
</Costura>
|
||||
</Weavers>
|
||||
@@ -1,140 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
|
||||
<xs:element name="Weavers">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="PropertyChanged" minOccurs="0" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="InjectOnPropertyNameChanged" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to control if the On_PropertyName_Changed feature is enabled.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="EventInvokerNames" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="CheckForEquality" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="CheckForEqualityUsingBaseEquals" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to control if equality checks should use the Equals method resolved from the base class.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="UseStaticEqualsFromBase" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to control if equality checks should use the static Equals method resolved from the base class.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="DisableCompression" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="DisableCleanup" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="ExcludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="IncludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="PreloadOrder" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
<xs:attribute name="VerifyAssembly" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="GenerateXsd" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
@@ -1,47 +0,0 @@
|
||||
<Window x:Class="TIDALDL_UI.Pages.AboutView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:local="clr-namespace:TIDALDL_UI"
|
||||
xmlns:pages="clr-namespace:TIDALDL_UI.Pages"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
Width="335"
|
||||
Height="400"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
WindowStyle="None"
|
||||
Background="{x:Null}"
|
||||
AllowsTransparency="True"
|
||||
ShowInTaskbar="False"
|
||||
d:DataContext="{d:DesignInstance pages:AboutViewModel}">
|
||||
<materialDesign:Card Name="m_CMainCard" materialDesign:ShadowAssist.ShadowDepth="Depth3" VerticalAlignment="Stretch" BorderThickness="3" BorderBrush="#FF171616" Margin="20,20,20,20">
|
||||
<materialDesign:DialogHost Identifier="RootDialog" SnackbarMessageQueue="{Binding ElementName=MainSnackbar, Path=MessageQueue}" Background="{x:Null}">
|
||||
<Grid Margin="8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="50" />
|
||||
<RowDefinition Height="240*" />
|
||||
<RowDefinition Height="47"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Label Content="About" Grid.Row="0" FontSize="30" VerticalAlignment="Top" Height="50" HorizontalContentAlignment="Center" BorderThickness="0,0,0,1" BorderBrush="#FFDEDEDE"/>
|
||||
<Grid Height="282" Grid.Row="1">
|
||||
<Image Margin="94,13,93,177" Source="pack://application:,,,/resource/tidal.jpg" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
<Label Content="TIDAL-GUI" Margin="103,105,102,151" HorizontalAlignment="Center" FontWeight="Bold" Width="74"/>
|
||||
<Label Content="Copyright 2019-2020 Yaron Inc." Margin="54,131,57,124" HorizontalAlignment="Center" Width="168"/>
|
||||
<Label Content="All Rights Reserved." Margin="77,158,77,100" HorizontalAlignment="Center" Width="125"/>
|
||||
<Label Content="{Binding Version}" Margin="77,182,77,76" HorizontalAlignment="Center" Width="125" HorizontalContentAlignment="Center"/>
|
||||
<Button Margin="127,211,122,41" HorizontalAlignment="Center"
|
||||
Style="{StaticResource MaterialDesignFloatingActionAccentButton}"
|
||||
Background="White"
|
||||
BorderBrush="#FFEA0000"
|
||||
Command="{s:Action GotoProject}" Width="30" Height="Auto">
|
||||
<materialDesign:PackIcon Kind="GithubCircle" Height="24" Width="24"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
<Button Command="{s:Action Confirm}" s:View.ActionTarget="{Binding}" Grid.Row="2" IsDefault="True" Style="{DynamicResource MaterialDesignRaisedButton}" Content="OK" Margin="10,0,10,10" Height="27" VerticalAlignment="Bottom"/>
|
||||
</Grid>
|
||||
</materialDesign:DialogHost>
|
||||
</materialDesign:Card>
|
||||
</Window>
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
/// <summary>
|
||||
/// Password.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class AboutView : Window
|
||||
{
|
||||
public AboutView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Stylet;
|
||||
using AIGS.Helper;
|
||||
using TIDALDL_UI.Properties;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
public class AboutViewModel:Screen
|
||||
{
|
||||
public string Version { get; set; } = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||
|
||||
public void Confirm()
|
||||
{
|
||||
RequestClose();
|
||||
}
|
||||
|
||||
public void GotoProject()
|
||||
{
|
||||
NetHelper.OpenWeb("https://github.com/yaronzz/Tidal-Media-Downloader");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
<Window x:Class="TIDALDL_UI.Pages.DllistView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:TIDALDL_UI.Pages"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextElement.FontWeight="Regular"
|
||||
TextElement.FontSize="13"
|
||||
TextOptions.TextFormattingMode="Ideal"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
WindowStyle="None"
|
||||
Background="{x:Null}"
|
||||
AllowsTransparency="True"
|
||||
Width="920"
|
||||
Height="540"
|
||||
ShowInTaskbar="False"
|
||||
mc:Ignorable="d"
|
||||
Title="FilelistView"
|
||||
d:DataContext="{d:DesignInstance local:DllistViewModel}">
|
||||
<materialDesign:Card Name="m_CMainCard" materialDesign:ShadowAssist.ShadowDepth="Depth3" VerticalAlignment="Stretch" BorderThickness="3" BorderBrush="#FF171616" Margin="20,20,20,20">
|
||||
<materialDesign:DialogHost Identifier="RootDialog" SnackbarMessageQueue="{Binding ElementName=MainSnackbar, Path=MessageQueue}" Background="{x:Null}">
|
||||
<Grid Margin="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="50" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="47" />
|
||||
</Grid.RowDefinitions>
|
||||
<!--head-->
|
||||
<Label Content="DownloadList" Grid.Row="0" FontSize="30" VerticalAlignment="Top" Height="50" HorizontalContentAlignment="Center" BorderThickness="0,0,0,1" BorderBrush="#FFDEDEDE"/>
|
||||
<!--body-->
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="359*"/>
|
||||
<ColumnDefinition Width="50"/>
|
||||
<ColumnDefinition Width="439*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox Text="{Binding Text}" Grid.Column="0" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" Background="Gainsboro" VerticalContentAlignment="Top"/>
|
||||
<Button Command="{s:Action Convert}" Grid.Column="1" s:View.ActionTarget="{Binding}" Style="{DynamicResource MaterialDesignRaisedButton}" VerticalAlignment="Center" Margin="3,170,7,169" Padding="2,0" HorizontalAlignment="Center" Width="40">
|
||||
<materialDesign:PackIcon Kind="ArrowRightBold" Foreground="White" Height="32" Width="32"/>
|
||||
</Button>
|
||||
<DataGrid Grid.Column="2" ItemsSource="{Binding Items}" CanUserSortColumns="False" CanUserAddRows="False" AutoGenerateColumns="False" Background="White"
|
||||
materialDesign:DataGridAssist.CellPadding="4 2 2 2" SelectionUnit="FullRow"
|
||||
materialDesign:DataGridAssist.ColumnHeaderPadding="4 2 2 2" GridLinesVisibility="Horizontal" BorderBrush="#FFDEDEDE"
|
||||
VerticalGridLinesBrush="#FFDEDEDE" RowHeaderWidth="80" BorderThickness="1" Height="Auto">
|
||||
<DataGrid.Columns>
|
||||
<!--<DataGridCheckBoxColumn Binding="{Binding Check}" Header="Check" ElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnStyle}" EditingElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnEditingStyle}"/>-->
|
||||
<DataGridTextColumn Header="#" Binding="{Binding Number}" IsReadOnly="True"/>
|
||||
<DataGridTextColumn Header="ID/URL" Binding="{Binding Name}" IsReadOnly="True"/>
|
||||
<DataGridTextColumn Header="Type" Binding="{Binding Type}" IsReadOnly="True"/>
|
||||
<DataGridTextColumn Header="Status" Binding="{Binding Status}" IsReadOnly="True"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
</Grid>
|
||||
<!--button-->
|
||||
<materialDesign:Badged Badge="{Binding Errlabel}" Grid.Row="2" Margin="414,10,0,0" Width="197" BadgePlacementMode="TopLeft">
|
||||
<Button Command="{s:Action Confirm}" s:View.ActionTarget="{Binding}" Style="{DynamicResource MaterialDesignRaisedButton}" Content="OK" Height="27" VerticalAlignment="Bottom" Width="197"/>
|
||||
</materialDesign:Badged>
|
||||
<Button Command="{s:Action Cancel}" s:View.ActionTarget="{Binding}" Grid.Row="2" IsDefault="True" Style="{DynamicResource MaterialDesignRaisedButton}" Content="CANCEL" Margin="0,0,10,10" Height="27" VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="197"/>
|
||||
</Grid>
|
||||
</materialDesign:DialogHost>
|
||||
</materialDesign:Card>
|
||||
</Window>
|
||||
@@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
/// <summary>
|
||||
/// DllistView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class DllistView : Window
|
||||
{
|
||||
public DllistView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TIDALDL_UI.Properties;
|
||||
using Tidal;
|
||||
using AIGS.Common;
|
||||
using AIGS.Helper;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using Stylet;
|
||||
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
public class DllistItem : Screen
|
||||
{
|
||||
public bool Check { get; set; }
|
||||
public int Number { get; set; }
|
||||
public string Name { get; set; }
|
||||
public eObjectType Type { get; set; }
|
||||
public string Status { get; set; } //wait-parse-err-success
|
||||
public object Data { get; set; }
|
||||
public DllistItem(int number, string name, eObjectType type)
|
||||
{
|
||||
Number = number;
|
||||
Check = true;
|
||||
Name = name;
|
||||
Type = type;
|
||||
Status = "Wait";
|
||||
Data = null;
|
||||
}
|
||||
}
|
||||
|
||||
public class DllistViewModel : Screen
|
||||
{
|
||||
public string Errlabel { get; set; }
|
||||
public string Text { get; set; } = Resources.DllistExample;
|
||||
public ObservableCollection<DllistItem> Items { get; set; } = new ObservableCollection<DllistItem>();
|
||||
private Thread ThreadHandle;
|
||||
|
||||
#region Button
|
||||
|
||||
public void Convert()
|
||||
{
|
||||
if (Text.IsBlank())
|
||||
return;
|
||||
|
||||
Dllist plist = Tidal.TidalTool.getDllist(Text);
|
||||
for (int i = 0; i < plist.AlbumIds.Count; i++)
|
||||
{
|
||||
AddToItems(Items.Count, plist.AlbumIds[i], eObjectType.ALBUM);
|
||||
}
|
||||
for (int i = 0; i < plist.TrackIds.Count; i++)
|
||||
{
|
||||
AddToItems(Items.Count, plist.TrackIds[i], eObjectType.TRACK);
|
||||
}
|
||||
for (int i = 0; i < plist.VideoIds.Count; i++)
|
||||
{
|
||||
AddToItems(Items.Count, plist.VideoIds[i], eObjectType.VIDEO);
|
||||
}
|
||||
for (int i = 0; i < plist.Urls.Count; i++)
|
||||
{
|
||||
AddToItems(Items.Count, plist.Urls[i], eObjectType.None);
|
||||
}
|
||||
for (int i = 0; i < plist.ArtistIds.Count; i++)
|
||||
{
|
||||
AddToItems(Items.Count, plist.ArtistIds[i], eObjectType.ARTIST);
|
||||
}
|
||||
|
||||
if (ThreadHandle == null)
|
||||
ThreadHandle = ThreadHelper.Start(ThreadFunc);
|
||||
}
|
||||
|
||||
public void Confirm()
|
||||
{
|
||||
Errlabel = null;
|
||||
for (int i = 0; i < Items.Count; i++)
|
||||
{
|
||||
if(Items[i].Status == "Wait" || Items[i].Status == "Parse")
|
||||
{
|
||||
Errlabel = "Some items in parsing.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
ThreadHelper.Abort(ThreadHandle);
|
||||
ThreadHandle = null;
|
||||
RequestClose();
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
Errlabel = null;
|
||||
Items.Clear();
|
||||
ThreadHelper.Abort(ThreadHandle);
|
||||
ThreadHandle = null;
|
||||
RequestClose();
|
||||
}
|
||||
#endregion
|
||||
|
||||
~DllistViewModel()
|
||||
{
|
||||
ThreadHelper.Abort(ThreadHandle);
|
||||
ThreadHandle = null;
|
||||
}
|
||||
|
||||
private void AddToItems(int iNumber, string sName, eObjectType sType)
|
||||
{
|
||||
for (int i = 0; i < Items.Count; i++)
|
||||
{
|
||||
if (sName == Items[i].Name)
|
||||
return;
|
||||
}
|
||||
Items.Add(new DllistItem(iNumber, sName, sType));
|
||||
}
|
||||
|
||||
public void ThreadFunc(object[] data)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
for (int i = 0; i < Items.Count; i++)
|
||||
{
|
||||
if (Items[i].Status != "Wait")
|
||||
continue;
|
||||
Items[i].Status = "Parse";
|
||||
|
||||
//Get
|
||||
eObjectType eType;
|
||||
object Data = TidalTool.tryGet(Items[i].Name, out eType, Items[i].Type);
|
||||
|
||||
//Result
|
||||
if (eType == eObjectType.None || Data == null)
|
||||
Items[i].Status = "Err";
|
||||
else
|
||||
{
|
||||
Items[i].Type = eType;
|
||||
Items[i].Data = Data;
|
||||
Items[i].Status = "Success";
|
||||
}
|
||||
}
|
||||
Thread.Sleep(3000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
<Window x:Class="TIDALDL_UI.Pages.InfoView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:local="clr-namespace:TIDALDL_UI"
|
||||
xmlns:pages="clr-namespace:TIDALDL_UI.Pages"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextElement.FontWeight="Regular"
|
||||
TextElement.FontSize="13"
|
||||
TextOptions.TextFormattingMode="Ideal"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
|
||||
Width="620"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
WindowStyle="None"
|
||||
Background="{x:Null}"
|
||||
AllowsTransparency="True"
|
||||
Height="540"
|
||||
ShowInTaskbar="False"
|
||||
d:DataContext="{d:DesignInstance pages:InfoViewModel}">
|
||||
|
||||
<materialDesign:Card Name="m_CMainCard" materialDesign:ShadowAssist.ShadowDepth="Depth3" VerticalAlignment="Stretch" BorderThickness="3" BorderBrush="#FF171616" Margin="20,20,20,20">
|
||||
<materialDesign:DialogHost Identifier="RootDialog" SnackbarMessageQueue="{Binding ElementName=MainSnackbar, Path=MessageQueue}" Background="{x:Null}">
|
||||
|
||||
<Grid Margin="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="50" />
|
||||
<RowDefinition Height="180" />
|
||||
<RowDefinition Height="47*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Content="{Binding Header}" Grid.Row="0" FontSize="30" VerticalAlignment="Top" Height="50" HorizontalContentAlignment="Center" BorderThickness="0,0,0,1" BorderBrush="#FFDEDEDE"/>
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image Source="{Binding Cover}" Margin="0,10,0,0"/>
|
||||
<Label Content="{Binding Title}" FontSize="28" VerticalAlignment="Top" Grid.Column="1" Height="45" FontWeight="ExtraBlack" />
|
||||
<Label Content="{Binding Intro}" FontSize="13" VerticalAlignment="Top" Margin="0,45,0,0" Grid.Column="1" Height="25" />
|
||||
<Label Content="{Binding ReleaseDate}" FontSize="13" VerticalAlignment="Top" Margin="0,70,0,0" Grid.Column="1" Height="25" />
|
||||
|
||||
<Button Grid.Column="1" IsDefault="True" Style="{DynamicResource MaterialDesignRaisedButton}"
|
||||
Command="{s:Action Confirm}"
|
||||
Content="Download"
|
||||
Height="27" VerticalAlignment="Bottom" Margin="5,0,189,8"/>
|
||||
<Button Grid.Column="1" IsDefault="True" Style="{DynamicResource MaterialDesignRaisedButton}"
|
||||
Command="{s:Action Cancel}"
|
||||
Content="Cancel"
|
||||
Height="27" VerticalAlignment="Bottom" Margin="184,0,23,8"/>
|
||||
|
||||
</Grid>
|
||||
|
||||
<!--<ListView Grid.Row="3" ItemsSource="{Binding ItemList}" ScrollViewer.HorizontalScrollBarVisibility="Hidden" >
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Header="#" Width="40" DisplayMemberBinding="{Binding Number}"/>
|
||||
<GridViewColumn Header="TITLE" Width="230" DisplayMemberBinding="{Binding Title}"/>
|
||||
<GridViewColumn Header="ALBUM" Width="130" DisplayMemberBinding="{Binding AlbumTitle}"/>
|
||||
<GridViewColumn Header="TIME" DisplayMemberBinding="{Binding Duration}"/>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>-->
|
||||
<DataGrid Grid.Row="3" ItemsSource="{Binding ItemList}" CanUserSortColumns="False" CanUserAddRows="False" AutoGenerateColumns="False" Background="White"
|
||||
materialDesign:DataGridAssist.CellPadding="12 6 8 4" RowHeight="32" SelectionUnit="FullRow"
|
||||
materialDesign:DataGridAssist.ColumnHeaderPadding="4" GridLinesVisibility="Horizontal"
|
||||
VerticalGridLinesBrush="#FFDEDEDE" RowHeaderWidth="80" BorderThickness="0" Height="Auto">
|
||||
<DataGrid.Columns>
|
||||
<DataGridCheckBoxColumn Binding="{Binding Check}" Header="#" ElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnStyle}" EditingElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnEditingStyle}"/>
|
||||
<DataGridTextColumn Header="#" Width="40" Binding="{Binding Number}" IsReadOnly="True"/>
|
||||
<DataGridTextColumn Header="#" Width="40" Binding="{Binding Flag}" IsReadOnly="True"/>
|
||||
<DataGridTextColumn Header="TITLE" Width="205" Binding="{Binding Title}" IsReadOnly="True"/>
|
||||
<DataGridTextColumn Header="ALBUM" Width="115" Binding="{Binding AlbumTitle}" IsReadOnly="True"/>
|
||||
<DataGridTextColumn Header="TIME" Binding="{Binding Duration}" IsReadOnly="True"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</Grid>
|
||||
</materialDesign:DialogHost>
|
||||
</materialDesign:Card>
|
||||
</Window>
|
||||
|
||||
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
using AIGS.Helper;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
/// <summary>
|
||||
/// AlbumInfo.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class InfoView : Window
|
||||
{
|
||||
public InfoView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Tidal;
|
||||
using AIGS.Helper;
|
||||
using AIGS.Common;
|
||||
using System.Collections.ObjectModel;
|
||||
using TIDALDL_UI.Else;
|
||||
using Stylet;
|
||||
using System.Windows;
|
||||
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
public class InfoItem : Screen
|
||||
{
|
||||
public int Number { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string Flag { get; set; }
|
||||
public string Duration { get; set; }
|
||||
public string AlbumTitle { get; set; }
|
||||
public bool Check { get; set; }
|
||||
public object Data { get; set; }
|
||||
|
||||
public InfoItem(int number, string title, string duration, string albumtitle,object data = null, string type="TRACK", string flag = "")
|
||||
{
|
||||
Check = true;
|
||||
Number = number;
|
||||
Flag = flag;
|
||||
Title = title;
|
||||
Type = type;
|
||||
Duration = duration;
|
||||
AlbumTitle = albumtitle;
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
|
||||
public class InfoViewModel:Screen
|
||||
{
|
||||
public string Header { get; private set; }
|
||||
public string Title { get; private set; }
|
||||
public string Intro { get; private set; }
|
||||
public string ReleaseDate { get; private set; }
|
||||
public BitmapImage Cover { get; private set; }
|
||||
public bool Result { get; set; }
|
||||
public object Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Item List
|
||||
/// </summary>
|
||||
public ObservableCollection<InfoItem> ItemList { get; private set; }
|
||||
|
||||
#region Button
|
||||
public void Confirm()
|
||||
{
|
||||
Result = RemoveItems();
|
||||
RequestClose();
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
Result = false;
|
||||
RequestClose();
|
||||
}
|
||||
#endregion
|
||||
|
||||
public object Load(object data)
|
||||
{
|
||||
Data = data;
|
||||
if (data.GetType() == typeof(Playlist))
|
||||
{
|
||||
Playlist plist = (Playlist)data;
|
||||
Header = "PLAYLISTINFO";
|
||||
Title = plist.Title;
|
||||
//Intro = string.Format("by {0}-{1} Tracks-{2} Videos-{3}", plist.Created, TimeHelper.ConverIntToString(plist.Duration), plist.NumberOfTracks, plist.NumberOfVideos);
|
||||
Intro = string.Format("{0} Tracks-{1} Videos-{2}", TimeHelper.ConverIntToString(plist.Duration), plist.NumberOfTracks, plist.NumberOfVideos);
|
||||
Cover = AIGS.Common.Convert.ConverByteArrayToBitmapImage(plist.CoverData);
|
||||
ReleaseDate = "";
|
||||
ItemList = new ObservableCollection<InfoItem>();
|
||||
if (plist.Tracks != null)
|
||||
{
|
||||
foreach (Track item in plist.Tracks)
|
||||
ItemList.Add(new InfoItem(plist.Tracks.IndexOf(item) + 1, item.Title, TimeHelper.ConverIntToString(item.Duration), item.Album.Title, item, flag:TidalTool.getFlag(item)));
|
||||
}
|
||||
if (plist.Videos != null)
|
||||
{
|
||||
foreach (Video item in plist.Videos)
|
||||
ItemList.Add(new InfoItem(plist.Tracks.Count + plist.Videos.IndexOf(item) + 1, item.Title, TimeHelper.ConverIntToString(item.Duration), item.Title, item, "VIDEO"));
|
||||
}
|
||||
}
|
||||
else if (data.GetType() == typeof(Artist))
|
||||
{
|
||||
Artist artist = (Artist)data;
|
||||
Header = "ARTISTINFO";
|
||||
Title = artist.Name;
|
||||
Intro = string.Format("by {0} Albums-{1}", artist.Name, artist.Albums.Count);
|
||||
Cover = AIGS.Common.Convert.ConverByteArrayToBitmapImage(artist.CoverData);
|
||||
ReleaseDate = "";
|
||||
ItemList = new ObservableCollection<InfoItem>();
|
||||
if (artist.Albums != null)
|
||||
{
|
||||
foreach (Album item in artist.Albums)
|
||||
ItemList.Add(new InfoItem(artist.Albums.IndexOf(item) + 1, item.Title, TimeHelper.ConverIntToString(item.Duration), item.Title, item, "ALBUM", flag: TidalTool.getFlag(item)));
|
||||
}
|
||||
}
|
||||
else if (data.GetType() == typeof(Album))
|
||||
{
|
||||
Album album = (Album)data;
|
||||
Header = "ALBUMINFO";
|
||||
Title = album.Title;
|
||||
Intro = string.Format("by {0}-{1} Tracks-{2} Videos-{3}", album.Artist.Name, TimeHelper.ConverIntToString(album.Duration), album.NumberOfTracks, album.NumberOfVideos);
|
||||
Cover = AIGS.Common.Convert.ConverByteArrayToBitmapImage(album.CoverData);
|
||||
ReleaseDate = "Release date " + album.ReleaseDate;
|
||||
ItemList = new ObservableCollection<InfoItem>();
|
||||
if (album.Tracks != null)
|
||||
{
|
||||
foreach (Track item in album.Tracks)
|
||||
ItemList.Add(new InfoItem(item.TrackNumber, item.Title, TimeHelper.ConverIntToString(item.Duration), item.Album.Title, item, flag: TidalTool.getFlag(item)));
|
||||
}
|
||||
if (album.Videos != null)
|
||||
{
|
||||
foreach (Video item in album.Videos)
|
||||
ItemList.Add(new InfoItem(item.TrackNumber, item.Title, TimeHelper.ConverIntToString(item.Duration), item.Album.Title, item, "VIDEO"));
|
||||
}
|
||||
}
|
||||
else if (data.GetType() == typeof(Video))
|
||||
{
|
||||
Video video = (Video)data;
|
||||
Header = "VIDEOINFO";
|
||||
Title = video.Title;
|
||||
Cover = AIGS.Common.Convert.ConverByteArrayToBitmapImage(video.CoverData);
|
||||
Intro = string.Format("by {0}-{1}", video.Artist.Name, TimeHelper.ConverIntToString(video.Duration));
|
||||
ReleaseDate = "Release date " + video.ReleaseDate;
|
||||
ItemList = new ObservableCollection<InfoItem>();
|
||||
ItemList.Add(new InfoItem(0, video.Title, TimeHelper.ConverIntToString(video.Duration), video.Album == null ? "" : video.Album.Title, data, "VIDEO"));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private bool RemoveItems()
|
||||
{
|
||||
for (int i = 0; i < ItemList.Count; i++)
|
||||
{
|
||||
if (ItemList[i].Check)
|
||||
continue;
|
||||
|
||||
if (Data.GetType() == typeof(Video) || Data.GetType() == typeof(Track))
|
||||
return false;
|
||||
if (Data.GetType() == typeof(Album))
|
||||
{
|
||||
Album album = (Album)Data;
|
||||
if (ItemList[i].Type == "TRACK")
|
||||
album.Tracks.Remove((Track)ItemList[i].Data);
|
||||
else
|
||||
album.Videos.Remove((Video)ItemList[i].Data);
|
||||
}
|
||||
if (Data.GetType() == typeof(Playlist))
|
||||
{
|
||||
Playlist plist = (Playlist)Data;
|
||||
if (ItemList[i].Type == "TRACK")
|
||||
plist.Tracks.Remove((Track)ItemList[i].Data);
|
||||
else
|
||||
plist.Videos.Remove((Video)ItemList[i].Data);
|
||||
}
|
||||
if (Data.GetType() == typeof(Artist))
|
||||
{
|
||||
Artist artist = (Artist)Data;
|
||||
artist.Albums.Remove((Album)ItemList[i].Data);
|
||||
}
|
||||
}
|
||||
|
||||
if (Data.GetType() == typeof(Album))
|
||||
{
|
||||
Album album = (Album)Data;
|
||||
if (album.Tracks.Count <= 0 && album.Videos.Count <= 0)
|
||||
return false;
|
||||
}
|
||||
if (Data.GetType() == typeof(Artist))
|
||||
{
|
||||
Artist artist = (Artist)Data;
|
||||
if (artist.Albums.Count <= 0)
|
||||
return false;
|
||||
}
|
||||
if (Data.GetType() == typeof(Playlist))
|
||||
{
|
||||
Playlist plist = (Playlist)Data;
|
||||
if (plist.Tracks.Count <= 0 && plist.Videos.Count <= 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
<Window x:Class="TIDALDL_UI.Pages.LoginView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:local="clr-namespace:TIDALDL_UI"
|
||||
xmlns:pages="clr-namespace:TIDALDL_UI.Pages"
|
||||
xmlns:else="clr-namespace:TIDALDL_UI.Else"
|
||||
xmlns:aigsc="clr-namespace:AIGS.Control;assembly=AIGS"
|
||||
xmlns:aigs="clr-namespace:AIGS.Common;assembly=AIGS"
|
||||
mc:Ignorable="d"
|
||||
TextElement.FontWeight="Regular"
|
||||
TextElement.FontSize="13"
|
||||
TextOptions.TextFormattingMode="Ideal"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
|
||||
Title="Tidal-gui"
|
||||
Width="515"
|
||||
Height="415" WindowStyle="None" AllowsTransparency="True" Background="{x:Null}"
|
||||
d:DataContext="{d:DesignInstance pages:LoginViewModel}">
|
||||
|
||||
<Grid>
|
||||
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth3" VerticalAlignment="Top" HorizontalAlignment="Left" Width="430" BorderThickness="3" BorderBrush="#FF171616" Margin="45,40,0,0" Height="330">
|
||||
<materialDesign:DialogHost Identifier="RootDialog" SnackbarMessageQueue="{Binding ElementName=MainSnackbar, Path=MessageQueue}">
|
||||
<Grid Height="329" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="182"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!--Cover Grid-->
|
||||
<Grid Background="Black" MouseLeftButtonDown="Grid_MouseLeftButtonDown" Margin="0,-10,0,124" Grid.RowSpan="2" Grid.ColumnSpan="2">
|
||||
<Image Margin="-10,-10,0,0" Source="pack://application:,,,/resource/tidal.jpg" />
|
||||
<!--<Button Command="{s:Action RequestClose}" s:View.ActionTarget="{Binding}" Margin="404,0,0,180" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="26" Padding="0" Height="25" BorderBrush="{x:Null}" Background="{x:Null}">
|
||||
<materialDesign:PackIcon Kind="Close" Height="22" Width="26" Foreground="White" />
|
||||
</Button>
|
||||
<Button Command="{s:Action Setting}" s:View.ActionTarget="{Binding}" Margin="380,0,0,180" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="24" Padding="0" Height="25" BorderBrush="{x:Null}" Background="{x:Null}">
|
||||
<materialDesign:PackIcon Kind="CloudSync" Height="22" Width="26" Foreground="White" />
|
||||
</Button>-->
|
||||
</Grid>
|
||||
|
||||
<!--Login Page-->
|
||||
<Grid Grid.Row="1" Background="White" Grid.ColumnSpan="2">
|
||||
<ComboBox Margin="115,10,0,0" materialDesign:HintAssist.Hint=" UserName" Background="White" IsEditable="True" VerticalAlignment="Top" BorderThickness="1" Height="28" Width="195" HorizontalAlignment="Left"
|
||||
Text="{Binding Username, UpdateSourceTrigger=PropertyChanged}"
|
||||
DisplayMemberPath="Key"
|
||||
SelectedValuePath="Key"
|
||||
SelectedIndex="{Binding SelectIndex, UpdateSourceTrigger=PropertyChanged}"
|
||||
SelectionChanged="{s:Action SelectChange}"
|
||||
ItemsSource="{Binding PersonList, UpdateSourceTrigger=PropertyChanged}" Padding="2,6,0,6" BorderBrush="#899C9494"/>
|
||||
<PasswordBox Margin="115,38,0,0" materialDesign:HintAssist.Hint=" Password" Background="White" Height="28" Width="195" aigsc:PasswordBoxHelper.Attach="True" aigsc:PasswordBoxHelper.Password="{Binding Path=Password,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" BorderThickness="1,1,1,1" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="#899C9494" />
|
||||
<CheckBox Content="Remember" Margin="115,66,0,56" HorizontalAlignment="Left" Width="90" IsChecked="{Binding Remember,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<CheckBox Content="AutoLogin" Margin="216,66,0,56" HorizontalAlignment="Left" Width="94" IsChecked="{Binding AutoLogin,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<materialDesign:Badged Badge="{Binding Errlabel, UpdateSourceTrigger=PropertyChanged}" Margin="115,96,0,0">
|
||||
<Button Command="{s:Action Confirm}" s:View.ActionTarget="{Binding}" Name="m_CLogin" Content="LOG IN" HorizontalAlignment="Left" Width="195" Height="30" IsDefault="True"/>
|
||||
</materialDesign:Badged>
|
||||
</Grid>
|
||||
|
||||
<!--Wait Page-->
|
||||
<Grid Grid.Row="1" Background="White" Name="m_CWaitPage" Visibility="{Binding WaitVisibility, UpdateSourceTrigger=PropertyChanged}" Grid.ColumnSpan="2">
|
||||
<materialDesign:Chip
|
||||
Background="LightGray"
|
||||
Content="{Binding Username, UpdateSourceTrigger=PropertyChanged}"
|
||||
IconBackground="{DynamicResource PrimaryHueDarkBrush}"
|
||||
IconForeground="{DynamicResource PrimaryHueDarkForegroundBrush}" Margin="105,38,0,74" Height="Auto" Width="215">
|
||||
<materialDesign:Chip.Icon>
|
||||
<materialDesign:PackIcon Kind="AccountCircle" Height="25" Width="30" />
|
||||
</materialDesign:Chip.Icon>
|
||||
</materialDesign:Chip>
|
||||
<Button Command="{s:Action Cancle}" Content="CANCLE" Margin="115,0,0,24" HorizontalAlignment="Left" Width="195" Height="27" VerticalAlignment="Bottom"/>
|
||||
</Grid>
|
||||
|
||||
<!--Proxy Page-->
|
||||
<Grid Grid.RowSpan="2" Background="LightGray" Visibility="{Binding ProxyViewShow,UpdateSourceTrigger=PropertyChanged,Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="29*"/>
|
||||
<ColumnDefinition Width="57*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="HttpProxy" FontSize="15" VerticalAlignment="Top" HorizontalContentAlignment="Right" Height="30" Margin="0,95,0,0" />
|
||||
<Label Content="Host" FontSize="15" VerticalAlignment="Top" HorizontalContentAlignment="Right" Height="30" Margin="0,125,0,0" />
|
||||
<Label Content="Port" FontSize="15" VerticalAlignment="Top" HorizontalContentAlignment="Right" Height="30" Margin="0,155,0,0" />
|
||||
<Label Content="Username" FontSize="15" VerticalAlignment="Top" HorizontalContentAlignment="Right" Height="30" Margin="0,185,0,0" />
|
||||
<Label Content="Password" FontSize="15" VerticalAlignment="Top" HorizontalContentAlignment="Right" Height="30" Margin="0,215,0,0" />
|
||||
<ToggleButton Grid.Column="1" IsChecked="{Binding ProxyEnable}" Style="{StaticResource MaterialDesignSwitchToggleButton}" Margin="0,95,220,204" Height="30"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding ProxyHost}" IsEnabled="{Binding ProxyEnable}" Margin="10,126,80,173" Height="30"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding ProxyPort}" IsEnabled="{Binding ProxyEnable}" Margin="10,154,80,145" Height="30"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding ProxyUser}" IsEnabled="{Binding ProxyEnable}" Margin="10,184,80,115" Height="30"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding ProxyPwd}" IsEnabled="{Binding ProxyEnable}" Margin="10,214,80,85" Height="30"/>
|
||||
</Grid>
|
||||
|
||||
<Button Command="{s:Action RequestClose}" s:View.ActionTarget="{Binding}" VerticalAlignment="Top" HorizontalAlignment="Right" Width="26" Padding="0" Height="25" BorderBrush="{x:Null}" Background="{x:Null}">
|
||||
<materialDesign:PackIcon Kind="Close" Height="22" Width="26" Foreground="White" />
|
||||
</Button>
|
||||
<Button Command="{s:Action Setting}" s:View.ActionTarget="{Binding}" VerticalAlignment="Top" Width="24" Padding="0" Height="25" BorderBrush="{x:Null}" Background="{x:Null}" Margin="375,0,31,0">
|
||||
<materialDesign:PackIcon Kind="CloudSync" Height="22" Width="26" Foreground="White" />
|
||||
</Button>
|
||||
|
||||
</Grid>
|
||||
</materialDesign:DialogHost>
|
||||
</materialDesign:Card>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,29 +0,0 @@
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
public partial class LoginView
|
||||
{
|
||||
public LoginView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
DragMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using Stylet;
|
||||
using System.ComponentModel;
|
||||
using System.Collections.ObjectModel;
|
||||
using AIGS.Common;
|
||||
using AIGS.Helper;
|
||||
using Tidal;
|
||||
using System.Windows;
|
||||
using TIDALDL_UI.Else;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
public class LoginViewModel: Screen
|
||||
{
|
||||
public string Errlabel { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public bool Remember { get; set; }
|
||||
public bool AutoLogin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// History AccountList
|
||||
/// </summary>
|
||||
public ObservableCollection<Property> PersonList { get; private set; }
|
||||
public int SelectIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Show Wait Page
|
||||
/// </summary>
|
||||
public Visibility WaitVisibility { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Proxy
|
||||
/// </summary>
|
||||
public bool ProxyViewShow { get;set; } = false;
|
||||
public bool ProxyEnable { get;set; } = Config.ProxyEnable();
|
||||
public string ProxyHost { get; set; } = Config.ProxyHost();
|
||||
public int ProxyPort { get; set; } = Config.ProxyPort();
|
||||
public string ProxyUser { get; set; } = Config.ProxyUser();
|
||||
public string ProxyPwd { get; set; } = Config.ProxyPwd();
|
||||
|
||||
/// <summary>
|
||||
/// View
|
||||
/// </summary>
|
||||
private IWindowManager Manager;
|
||||
private MainViewModel VMMain;
|
||||
|
||||
public LoginViewModel(IWindowManager manager, MainViewModel vmmain)
|
||||
{
|
||||
Manager = manager;
|
||||
VMMain = vmmain;
|
||||
|
||||
PersonList = new ObservableCollection<Property>();
|
||||
Remember = Config.Remember();
|
||||
AutoLogin = Config.AutoLogin();
|
||||
ShowMainPage(true);
|
||||
|
||||
//Read History Account
|
||||
List<Property> pList = Config.HistoryAccounts();
|
||||
for (int i = 0; i < pList.Count; i++)
|
||||
PersonList.Add(pList[i]);
|
||||
|
||||
//If AutoLogin
|
||||
if(AutoLogin && pList.Count > 0)
|
||||
{
|
||||
Username = pList[0].Key.ToString();
|
||||
Password = pList[0].Value.ToString();
|
||||
Confirm();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#region Common
|
||||
public void SelectChange()
|
||||
{
|
||||
if (SelectIndex >= 0 && SelectIndex <= PersonList.Count)
|
||||
Password = PersonList[SelectIndex].Value.ToString();
|
||||
}
|
||||
|
||||
public void ShowMainPage(bool bFlag)
|
||||
{
|
||||
WaitVisibility = bFlag ? Visibility.Hidden : Visibility.Visible;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Button
|
||||
public async void Confirm()
|
||||
{
|
||||
Errlabel = "";
|
||||
if (Username.IsBlank() || Password.IsBlank())
|
||||
{
|
||||
Errlabel = "Username or password is err!";
|
||||
return;
|
||||
}
|
||||
Config.AddHistoryAccount(Username, Password);
|
||||
|
||||
ShowMainPage(false);
|
||||
//Proxy
|
||||
TidalTool.PROXY = ProxyEnable ? new HttpHelper.ProxyInfo(ProxyHost, ProxyPort, ProxyUser, ProxyPwd) : null;
|
||||
bool bRet = await Task.Run(() => { return TidalTool.login(Username, Password);});
|
||||
if (!bRet)
|
||||
Errlabel = "Login Err! " + TidalTool.loginErrlabel;
|
||||
else
|
||||
{
|
||||
//DEBUG
|
||||
//eObjectType eType = eObjectType.None;
|
||||
//object obj = Tidal.TidalTool.tryGet("19297475", out eType, eObjectType.ALBUM);
|
||||
//Artist obj = (Artist)Tidal.TidalTool.tryGet("eason chan", out eType, eObjectType.ARTIST);
|
||||
|
||||
VMMain.SetLogViewModel(this);
|
||||
Manager.ShowWindow(VMMain);
|
||||
RequestClose();
|
||||
}
|
||||
|
||||
ShowMainPage(true);
|
||||
return;
|
||||
}
|
||||
|
||||
public void Cancle()
|
||||
{
|
||||
ShowMainPage(true);
|
||||
}
|
||||
|
||||
public void Setting()
|
||||
{
|
||||
if(!ProxyViewShow)
|
||||
{
|
||||
ProxyViewShow = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProxyViewShow = false;
|
||||
Config.ProxyEnable(ProxyEnable.ToString());
|
||||
Config.ProxyHost(ProxyHost);
|
||||
Config.ProxyPort(ProxyPort.ToString());
|
||||
Config.ProxyUser(ProxyUser);
|
||||
Config.ProxyPwd(ProxyPwd);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
<UserControl x:Class="TIDALDL_UI.Pages.MainListItemView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:TIDALDL_UI"
|
||||
xmlns:pages="clr-namespace:TIDALDL_UI.Pages"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
Background="Red"
|
||||
d:DataContext="{d:DesignInstance pages:MainListItemViewModel}">
|
||||
<Border Padding="0" BorderThickness="0 0 0 1" BorderBrush="{DynamicResource MaterialDesignDivider}">
|
||||
<Expander ExpandDirection="Down" Padding="0" IsExpanded="True">
|
||||
<Expander.Header>
|
||||
<Grid Height="64" Margin="-20,-8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- Thumbnail -->
|
||||
<Image Grid.Column="0" Source="{Binding Cover}" Width="64" Margin="0"/>
|
||||
<!-- Title -->
|
||||
<StackPanel Margin="8 0 0 0" Grid.Column="1">
|
||||
<TextBlock Text="{Binding Title}" FontSize="15" FontWeight="Bold" TextTrimming="CharacterEllipsis"/>
|
||||
<TextBlock Text="{Binding Desc}" FontSize="12" />
|
||||
</StackPanel>
|
||||
<!-- Progress and completion status -->
|
||||
<!--<TextBlock Grid.Column="2" Margin="4" Width="80" VerticalAlignment="Center"
|
||||
Text="{Binding Progress.Status, UpdateSourceTrigger=PropertyChanged}"
|
||||
Foreground="{Binding Progress.StatusColor,UpdateSourceTrigger=PropertyChanged}"/>-->
|
||||
<!-- Button -->
|
||||
<StackPanel Grid.Column="3" Margin="4" VerticalAlignment="Center" Orientation="Horizontal">
|
||||
<Button Command="{s:Action CancelAndRestart}" Padding="4,0,4,0" ToolTip="{Binding ButtonTip}" VerticalAlignment="Center" Style="{DynamicResource MaterialDesignFlatButton}">
|
||||
<materialDesign:PackIcon Width="24" Height="24" Kind="{Binding ButtonKind}" />
|
||||
</Button>
|
||||
<Button Command="{s:Action Delete}" Padding="4,0,4,0" ToolTip="Delete" VerticalAlignment="Center" Style="{DynamicResource MaterialDesignFlatButton}">
|
||||
<materialDesign:PackIcon Width="24" Height="24" Kind="TrashCircle" />
|
||||
</Button>
|
||||
<Button Command="{s:Action OpenBasePath}" Padding="4,0,4,0" VerticalAlignment="Center" ToolTip="Open" Style="{DynamicResource MaterialDesignFlatButton}">
|
||||
<materialDesign:PackIcon Width="24" Height="24 " Kind="FileFind" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Expander.Header>
|
||||
|
||||
<!-- Download List -->
|
||||
<Grid Background="{DynamicResource {x:Static SystemColors.InactiveBorderBrushKey}}" >
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" Visibility="{Binding DLItemList.Count, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
|
||||
<ItemsControl ItemsSource="{Binding DLItemList}" Grid.IsSharedSizeScope="True">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate >
|
||||
<Border Padding="0" BorderThickness="0 1 0 1" BorderBrush="{DynamicResource MaterialDesignDivider}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="39*"/>
|
||||
<RowDefinition Height="{Binding ErrlabelHeight,UpdateSourceTrigger=PropertyChanged}"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="{Binding Index}" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" Width="30"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding Title}" FontWeight="Bold" VerticalAlignment="Center"/>
|
||||
<TextBlock Grid.Column="2" Text="{Binding Own}" VerticalAlignment="Center" Padding="5,0" FontStretch="Expanded" FontStyle="Italic"/>
|
||||
<!--<TextBlock Grid.Column="3" Text="{Binding sType}" VerticalAlignment="Center" Padding="5,0"/>-->
|
||||
<materialDesign:PackIcon Grid.Column="3" Width="24" Height="24" Kind="{Binding sType}" VerticalAlignment="Center" Margin="5,0"/>
|
||||
<ProgressBar Grid.Column="4" Width="200" Height="10" Margin="0,13,0,13"
|
||||
Maximum="100"
|
||||
Value="{Binding Progress.Value,Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBlock Grid.Column="5" Margin="4" Width="80" VerticalAlignment="Center"
|
||||
Text="{Binding Progress.StatusMsg,UpdateSourceTrigger=PropertyChanged}"
|
||||
Foreground="{Binding Progress.StatusColor,UpdateSourceTrigger=PropertyChanged}"/>
|
||||
</Grid>
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding Progress.Errmsg,UpdateSourceTrigger=PropertyChanged}" Width="Auto" Margin="30,0,157,0" Foreground="#FFF72A2A"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Expander>
|
||||
</Border>
|
||||
</UserControl>
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
/// <summary>
|
||||
/// MainListItemView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class MainListItemView : UserControl
|
||||
{
|
||||
public MainListItemView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AIGS.Helper;
|
||||
using AIGS.Common;
|
||||
using Stylet;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Tidal;
|
||||
using System.Diagnostics;
|
||||
using TIDALDL_UI.Else;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Windows;
|
||||
using System.IO;
|
||||
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
public class MainListItemViewModel : Screen
|
||||
{
|
||||
public string Title { get; private set; }
|
||||
public string Desc { get; set; }
|
||||
public BitmapImage Cover { get; private set; }
|
||||
public string BasePath { get; private set; }
|
||||
public int AddYear { get; set; }
|
||||
public ObservableCollection<DownloadItem> DLItemList { get; set; }
|
||||
private BindableCollection<MainListItemViewModel> Parents { get; set; }
|
||||
|
||||
public string ButtonKind { get; set; } = "CloseCircle";
|
||||
public string ButtonTip { get; set; } = "Cancel";
|
||||
|
||||
public MainListItemViewModel(object data, BindableCollection<MainListItemViewModel> parents)
|
||||
{
|
||||
AddYear = Config.AddYear();
|
||||
Parents = parents;
|
||||
DLItemList = new ObservableCollection<DownloadItem>();
|
||||
if (data.GetType() == typeof(Album))
|
||||
{
|
||||
Album album = (Album)data;
|
||||
Title = album.Title;
|
||||
BasePath = TidalTool.getAlbumFolder(Config.OutputDir(), album, AddYear);
|
||||
Desc = string.Format("by {0}-{1} Tracks-{2} Videos-{3}", album.Artist.Name, TimeHelper.ConverIntToString(album.Duration), album.NumberOfTracks, album.NumberOfVideos);
|
||||
Cover = AIGS.Common.Convert.ConverByteArrayToBitmapImage(album.CoverData);
|
||||
|
||||
AddAlbum(album);
|
||||
}
|
||||
else if (data.GetType() == typeof(Video))
|
||||
{
|
||||
Video video = (Video)data;
|
||||
Title = video.Title;
|
||||
BasePath = TidalTool.getVideoFolder(Config.OutputDir());
|
||||
Desc = string.Format("by {0}-{1}", video.Artist.Name, TimeHelper.ConverIntToString(video.Duration));
|
||||
Cover = AIGS.Common.Convert.ConverByteArrayToBitmapImage(video.CoverData);
|
||||
DLItemList.Add(new DownloadItem(DLItemList.Count + 1, null, video, null));
|
||||
}
|
||||
else if(data.GetType() == typeof(Artist))
|
||||
{
|
||||
Artist artist = (Artist)data;
|
||||
Title = artist.Name;
|
||||
BasePath = TidalTool.getArtistFolder(Config.OutputDir(), artist);
|
||||
Desc = string.Format("by {0} Albums-{1}", artist.Name, artist.Albums.Count);
|
||||
Cover = AIGS.Common.Convert.ConverByteArrayToBitmapImage(artist.CoverData);
|
||||
|
||||
foreach (var item in artist.Albums)
|
||||
AddAlbum(item);
|
||||
}
|
||||
else if(data.GetType() == typeof(Playlist))
|
||||
{
|
||||
Playlist plist = (Playlist)data;
|
||||
Title = plist.Title;
|
||||
BasePath = TidalTool.getPlaylistFolder(Config.OutputDir(), plist);
|
||||
//Desc = string.Format("by {0}-{1} Tracks-{2} Videos-{3}", plist.Created, TimeHelper.ConverIntToString(plist.Duration), plist.NumberOfTracks, plist.NumberOfVideos);
|
||||
Desc = string.Format("{0} Tracks-{1} Videos-{2}", TimeHelper.ConverIntToString(plist.Duration), plist.NumberOfTracks, plist.NumberOfVideos);
|
||||
Cover = AIGS.Common.Convert.ConverByteArrayToBitmapImage(plist.CoverData);
|
||||
foreach (Track item in plist.Tracks)
|
||||
DLItemList.Add(new DownloadItem(DLItemList.Count + 1, item, null, album: null, plist:plist));
|
||||
foreach (Video item in plist.Videos)
|
||||
DLItemList.Add(new DownloadItem(DLItemList.Count + 1, null, item, album: null, plist: plist));
|
||||
}
|
||||
|
||||
PathHelper.Mkdirs(BasePath);
|
||||
}
|
||||
|
||||
private void AddAlbum(Album album)
|
||||
{
|
||||
if (Config.SaveCovers())
|
||||
{
|
||||
string CoverPath = TidalTool.getAlbumCoverPath(Config.OutputDir(), album, AddYear);
|
||||
FileHelper.Write(album.CoverData, true, CoverPath);
|
||||
}
|
||||
|
||||
foreach (Track item in album.Tracks)
|
||||
DLItemList.Add(new DownloadItem(DLItemList.Count +1, item, null, album: album));
|
||||
foreach (Video item in album.Videos)
|
||||
DLItemList.Add(new DownloadItem(DLItemList.Count + 1, null, item, album: album));
|
||||
}
|
||||
|
||||
public void StartWork()
|
||||
{
|
||||
foreach (DownloadItem item in DLItemList)
|
||||
item.Start();
|
||||
}
|
||||
|
||||
#region Button
|
||||
public void CancelAndRestart()
|
||||
{
|
||||
if (ButtonKind == "CloseCircle")
|
||||
{
|
||||
foreach (DownloadItem item in DLItemList)
|
||||
item.Cancel();
|
||||
ButtonKind = "Restart";
|
||||
ButtonTip = "Restart";
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (DownloadItem item in DLItemList)
|
||||
item.Restart();
|
||||
ButtonKind = "CloseCircle";
|
||||
ButtonTip = "Cancel";
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
foreach (DownloadItem item in DLItemList)
|
||||
item.Cancel();
|
||||
Parents.Remove(this);
|
||||
}
|
||||
|
||||
public void OpenBasePath()
|
||||
{
|
||||
Process.Start(BasePath);
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
<Window x:Class="TIDALDL_UI.Pages.MainView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:local="clr-namespace:TIDALDL_UI"
|
||||
xmlns:pages="clr-namespace:TIDALDL_UI.Pages"
|
||||
xmlns:aigs="clr-namespace:AIGS.Common;assembly=AIGS"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
WindowStyle="None"
|
||||
Background="{x:Null}"
|
||||
AllowsTransparency="True"
|
||||
Title="Tidal-gui" Height="710" Width="1060"
|
||||
d:DataContext="{d:DesignInstance pages:MainViewModel}">
|
||||
|
||||
<Window.Resources>
|
||||
<aigs:UnBoolConverter x:Key="ConverterUnbool" />
|
||||
<aigs:StringNotEmptyToBallConverter x:Key="ConverterStringNotEmpty" />
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth3" VerticalAlignment="Stretch" BorderThickness="3" BorderBrush="#FF171616" Margin="20,20,20,20">
|
||||
<materialDesign:DialogHost Identifier="RootDialog" SnackbarMessageQueue="{Binding ElementName=MainSnackbar, Path=MessageQueue}" Background="{x:Null}">
|
||||
<Grid>
|
||||
<!--Head Part-->
|
||||
<materialDesign:ColorZone Mode="PrimaryMid" Padding="10" MouseLeftButtonDown="ColorZone_MouseLeftButtonDown" >
|
||||
<DockPanel>
|
||||
<Button DockPanel.Dock="Right" Command="{s:Action WindowClose}" s:View.ActionTarget="{Binding}" Padding="0" Width="24" Height="24" Background="Red">
|
||||
<materialDesign:PackIcon Kind="Close" Height="22" Width="22" Foreground="White" />
|
||||
</Button>
|
||||
<Button DockPanel.Dock="Right" Command="{s:Action WindowMax}" s:View.ActionTarget="{Binding}" Padding="0" Width="24" Height="24" Background="{x:Null}">
|
||||
<materialDesign:PackIcon Kind="WindowMaximize" Height="22" Width="22" />
|
||||
</Button>
|
||||
<Button DockPanel.Dock="Right" Command="{s:Action WindowMin}" s:View.ActionTarget="{Binding}" Padding="0" Width="24" Height="24" Background="{x:Null}">
|
||||
<materialDesign:PackIcon Kind="WindowMinimize" Height="22" Width="22" />
|
||||
</Button>
|
||||
<materialDesign:PopupBox DockPanel.Dock="Right" PlacementMode="BottomAndAlignRightEdges" Padding="0" Height="24" Width="35">
|
||||
<StackPanel>
|
||||
<Button Content="Logout" Click="{s:Action Logout}"></Button>
|
||||
<Button Content="Setting" Click="{s:Action Setting}"></Button>
|
||||
<Button Content="About" Click="{s:Action About}"></Button>
|
||||
<Button Content="FeedBack" Click="{s:Action FeedBack}"></Button>
|
||||
</StackPanel>
|
||||
</materialDesign:PopupBox>
|
||||
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" materialDesign:RippleAssist.IsCentered="True">
|
||||
<materialDesign:PackIcon Kind="MusicCircleOutline" Height="Auto" Width="30" HorizontalAlignment="Left" Padding="0,4" VerticalAlignment="Stretch"/>
|
||||
<TextBlock Text="TIDAL-GUI" FontWeight="Bold" VerticalAlignment="Center" Margin="0 0 0 0" FontSize="18" Padding="4,0,0,0"/>
|
||||
<materialDesign:ColorZone IsEnabled="{Binding Path=InSearch, Converter={StaticResource ConverterUnbool}}" Mode="Standard" Padding="4 0 4 0" Panel.ZIndex="1" Margin="16 0 0 0" materialDesign:ShadowAssist.ShadowDepth="Depth1" Width="673">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="26" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="0" Style="{DynamicResource MaterialDesignToolButton}" ToolTip="{Binding SearchHelperTip}">
|
||||
<materialDesign:PackIcon Kind="QuestionMarkCircle" Opacity=".56" />
|
||||
</Button>
|
||||
<TextBox Grid.Column="1"
|
||||
Margin="2,4,26,4"
|
||||
Text="{Binding SearchStr, UpdateSourceTrigger=PropertyChanged}"
|
||||
materialDesign:HintAssist.Hint="Enter ID\Title\Url"
|
||||
materialDesign:TextFieldAssist.DecorationVisibility="Hidden"
|
||||
BorderThickness="0"
|
||||
MinWidth="200"
|
||||
PreviewMouseDoubleClick="TextBox_PreviewMouseDoubleClick"
|
||||
VerticalAlignment="Center" Grid.ColumnSpan="2" />
|
||||
<Button Grid.Column="2" Command="{s:Action Search}" s:View.ActionTarget="{Binding}" Style="{DynamicResource MaterialDesignToolButton}" IsDefault="True" Margin="0,2,31,2" HorizontalAlignment="Right" Width="29">
|
||||
<materialDesign:PackIcon Kind="Magnify" Opacity=".56" />
|
||||
</Button>
|
||||
<Button Grid.Column="2" Command="{s:Action OpenDllist}" s:View.ActionTarget="{Binding}" Style="{DynamicResource MaterialDesignToolButton}" Margin="0,2" HorizontalAlignment="Right" Width="31">
|
||||
<materialDesign:PackIcon Kind="FileDocumentBoxOutline" Opacity=".56" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</materialDesign:ColorZone>
|
||||
<ProgressBar Style="{StaticResource MaterialDesignCircularProgressBar}" Visibility="{Binding InSearch, Converter={x:Static s:BoolToVisibilityConverter.Instance}}" Value="0" IsIndeterminate="True" Height="22" Width="20" Foreground="#FFFDFEFF" Margin="5,0,0,0" BorderBrush="#FFF9F7F7" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</materialDesign:ColorZone>
|
||||
|
||||
<!--Content-->
|
||||
<Grid Margin="0,52,0,35">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"
|
||||
Visibility="{Binding ItemList.Count, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
|
||||
<ItemsControl Padding="8" Background="{DynamicResource MaterialDesignCardBackground}"
|
||||
ItemsSource="{Binding ItemList}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl Margin="0,0,0,8" s:View.Model="{Binding}" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
<!--Err Label IsActive="{Binding ShowErrlabel}"-->
|
||||
<materialDesign:Snackbar IsActive='{Binding Path=Errlabel, Converter={StaticResource ConverterStringNotEmpty}}' Margin="230,0,230,35" Width="560">
|
||||
<materialDesign:SnackbarMessage Content="{Binding Errlabel}" ActionContent="OK" ActionClick="{s:Action CloseErrlabel}"/>
|
||||
</materialDesign:Snackbar>
|
||||
<StatusBar HorizontalAlignment="Left" Height="35" Margin="0,635,0,0" VerticalAlignment="Bottom" Width="1020" Background="White" BorderThickness="0,1,0,0" BorderBrush="#FF999191">
|
||||
<materialDesign:PackIcon Kind="Music" />
|
||||
<ComboBox ItemsSource="{Binding QualityList}"
|
||||
SelectedIndex="{Binding SelectQualityIndex , UpdateSourceTrigger=PropertyChanged}"
|
||||
SelectionChanged="{s:Action QualityChanged}"
|
||||
VerticalAlignment="Top" Height="30" Padding="6,6,0,6"/>
|
||||
<materialDesign:PackIcon Kind="VideoFilm" />
|
||||
<ComboBox ItemsSource="{Binding ResolutionList}"
|
||||
SelectedIndex="{Binding SelectResolutionIndex , UpdateSourceTrigger=PropertyChanged}"
|
||||
SelectionChanged="{s:Action ResolutionChanged}"
|
||||
VerticalAlignment="Top" Height="30" Padding="6,6,0,6"/>
|
||||
</StatusBar>
|
||||
</Grid>
|
||||
</materialDesign:DialogHost>
|
||||
</materialDesign:Card>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,39 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
using AIGS.Helper;
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
/// <summary>
|
||||
/// MainView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class MainView
|
||||
{
|
||||
public MainView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void ColorZone_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
DragMove();
|
||||
}
|
||||
|
||||
private void TextBox_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
TextBox ctrl = (TextBox)sender;
|
||||
ctrl.SelectAll();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,275 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Stylet;
|
||||
using AIGS.Common;
|
||||
using AIGS.Helper;
|
||||
using Tidal;
|
||||
using TIDALDL_UI.Else;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
public class MainViewModel : Screen
|
||||
{
|
||||
public string Errlabel { get; set; }
|
||||
public string SearchStr { get; set; }
|
||||
public bool InSearch { get; set; }
|
||||
|
||||
public string SearchHelperTip { get; set; } =
|
||||
"You can search album\\track\\video\\artist\\playlist! Example:\n\n" +
|
||||
"ID : 71121869 (from https://listen.tidal.com/albums/71121869) \n" +
|
||||
"Title: Adele (or track\\video\\album title) \n" +
|
||||
"Url : https://listen.tidal.com/albums/71121869";
|
||||
|
||||
/// <summary>
|
||||
/// Download Items
|
||||
/// </summary>
|
||||
public BindableCollection<MainListItemViewModel> ItemList { get; } = new BindableCollection<MainListItemViewModel>();
|
||||
public Thread UpdateThread;
|
||||
|
||||
/// <summary>
|
||||
/// Combox
|
||||
/// </summary>
|
||||
public List<string> QualityList { get; set; }
|
||||
public int SelectQualityIndex { get; set; }
|
||||
public List<string> ResolutionList { get; set; }
|
||||
public int SelectResolutionIndex { get; set; }
|
||||
|
||||
private IWindowManager Manager;
|
||||
private LoginViewModel VMLogin;
|
||||
private SettingViewModel VMSetting;
|
||||
private AboutViewModel VMAbout;
|
||||
private InfoViewModel VMInfo;
|
||||
private SearchViewModel VMSearch;
|
||||
private DllistViewModel VMDllist;
|
||||
|
||||
public MainViewModel(IWindowManager manager,
|
||||
SettingViewModel setting,
|
||||
AboutViewModel about,
|
||||
InfoViewModel albuminfo,
|
||||
SearchViewModel search,
|
||||
DllistViewModel dllist)
|
||||
{
|
||||
Manager = manager;
|
||||
VMSetting = setting;
|
||||
VMAbout = about;
|
||||
VMInfo = albuminfo;
|
||||
VMSearch = search;
|
||||
VMDllist = dllist;
|
||||
ThreadTool.SetThreadNum(int.Parse(Config.ThreadNum()));
|
||||
|
||||
UpdateThread = new Thread(ThreadUpdateFunc);
|
||||
UpdateThread.IsBackground = true;
|
||||
UpdateThread.Start();
|
||||
|
||||
QualityList = TidalTool.getQualityList();
|
||||
SelectQualityIndex = QualityList.IndexOf(Config.Quality().ToUpper());
|
||||
if (SelectQualityIndex < 0)
|
||||
SelectQualityIndex = 0;
|
||||
|
||||
ResolutionList = TidalTool.getResolutionList();
|
||||
SelectResolutionIndex = ResolutionList.IndexOf(Config.Resolution().ToUpper());
|
||||
if (SelectResolutionIndex < 0)
|
||||
SelectResolutionIndex = 0;
|
||||
|
||||
TidalTool.SetSearchMaxNum(int.Parse(Config.SearchNum()));
|
||||
|
||||
//test
|
||||
//VMDllist.Convert();
|
||||
//return;
|
||||
}
|
||||
|
||||
public void SetLogViewModel(LoginViewModel model)
|
||||
{
|
||||
VMLogin = model;
|
||||
}
|
||||
|
||||
public void WindowClose()
|
||||
{
|
||||
ThreadTool.Close();
|
||||
ThreadHelper.Abort(UpdateThread);
|
||||
RequestClose();
|
||||
}
|
||||
|
||||
//protected override void OnInitialActivate()
|
||||
//{
|
||||
// //show about page
|
||||
// if (Config.Version() != VersionHelper.GetSelfVersion())
|
||||
// {
|
||||
// Config.Version(VersionHelper.GetSelfVersion());
|
||||
// Manager.ShowDialog(VMAbout);
|
||||
// }
|
||||
//}
|
||||
|
||||
public void QualityChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
Config.Quality(QualityList[SelectQualityIndex].ToLower());
|
||||
}
|
||||
|
||||
public void ResolutionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
Config.Resolution(ResolutionList[SelectResolutionIndex]);
|
||||
}
|
||||
|
||||
#region Button
|
||||
public async void Search()
|
||||
{
|
||||
if (InSearch)
|
||||
return;
|
||||
if (SearchStr.IsBlank())
|
||||
{
|
||||
Errlabel = "Search string is empty!";
|
||||
return;
|
||||
}
|
||||
|
||||
//Search
|
||||
InSearch = true;
|
||||
eObjectType SearchType = eObjectType.None;
|
||||
object SearchObj = await Task.Run(() => { return TidalTool.tryGet(SearchStr, out SearchType); });
|
||||
InSearch = false;
|
||||
|
||||
if (SearchType == eObjectType.None)
|
||||
{
|
||||
Errlabel = "Search Err!";
|
||||
return;
|
||||
}
|
||||
if (SearchType == Tidal.eObjectType.SEARCH)
|
||||
{
|
||||
VMSearch.Load((Tidal.SearchResult)SearchObj);
|
||||
Manager.ShowDialog(VMSearch);
|
||||
SearchType = VMSearch.ResultType;
|
||||
SearchObj = VMSearch.ResultObject;
|
||||
if (SearchType == eObjectType.None)
|
||||
return;
|
||||
}
|
||||
|
||||
SearchObj = VMInfo.Load(SearchObj);
|
||||
Manager.ShowDialog(VMInfo);
|
||||
if (VMInfo.Result)
|
||||
{
|
||||
MainListItemViewModel newNode = new MainListItemViewModel(SearchObj, ItemList);
|
||||
ItemList.Add(newNode);
|
||||
newNode.StartWork();
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenDllist()
|
||||
{
|
||||
VMDllist.Items.Clear();
|
||||
Manager.ShowDialog(VMDllist);
|
||||
for (int i = 0; i < VMDllist.Items.Count; i++)
|
||||
{
|
||||
if (VMDllist.Items[i].Type == eObjectType.None)
|
||||
continue;
|
||||
MainListItemViewModel newNode = new MainListItemViewModel(VMDllist.Items[i].Data, ItemList);
|
||||
ItemList.Add(newNode);
|
||||
newNode.StartWork();
|
||||
}
|
||||
}
|
||||
public void Logout()
|
||||
{
|
||||
TidalTool.logout();
|
||||
Manager.ShowWindow(VMLogin);
|
||||
WindowClose();
|
||||
}
|
||||
public void Setting()
|
||||
{
|
||||
VMSetting.RefreshSetting();
|
||||
Manager.ShowDialog(VMSetting);
|
||||
string sValue = Config.ThreadNum();
|
||||
ThreadTool.SetThreadNum(int.Parse(sValue));
|
||||
|
||||
SelectQualityIndex = QualityList.IndexOf(Config.Quality().ToUpper());
|
||||
SelectResolutionIndex = ResolutionList.IndexOf(Config.Resolution().ToUpper());
|
||||
}
|
||||
public void About()
|
||||
{
|
||||
Manager.ShowDialog(VMAbout);
|
||||
}
|
||||
public void FeedBack()
|
||||
{
|
||||
NetHelper.OpenWeb("https://github.com/yaronzz/Tidal-Media-Downloader/issues");
|
||||
}
|
||||
public void CloseErrlabel()
|
||||
{
|
||||
Errlabel = null;
|
||||
}
|
||||
public void WindowMin()
|
||||
{
|
||||
((MainView)this.View).WindowState = WindowState.Minimized;
|
||||
}
|
||||
public void WindowMax()
|
||||
{
|
||||
ScreenShotHelper.MaxWindow((Window)this.View);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Version Update Thread
|
||||
public void ThreadUpdateFunc()
|
||||
{
|
||||
string PATH = Path.GetFullPath("./tidal_new/");
|
||||
string VERF = PATH + "version";
|
||||
string BATF = PATH + "update.bat";
|
||||
string sSelfVer = VersionHelper.GetSelfVersion();
|
||||
|
||||
//Replace new version
|
||||
string sDlVer = FileHelper.Read(VERF);
|
||||
if (sDlVer.IsNotBlank() && VersionHelper.Compare(sSelfVer, sDlVer) < 0 && File.Exists(PATH + "tidal-gui.exe") && File.Exists(BATF))
|
||||
{
|
||||
MessageBoxResult ret = MessageBox.Show("Update new version?", "Info", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
if (ret == MessageBoxResult.No)
|
||||
return;
|
||||
|
||||
if (Application.Current != null)
|
||||
{
|
||||
Application.Current.Dispatcher.BeginInvoke((Action)delegate ()
|
||||
{
|
||||
CmdHelper.StartExe(BATF, null, IsShowWindow: false);
|
||||
WindowClose();
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//Get github new version
|
||||
string sLastVer = GithubHelper.getLastReleaseVersion("yaronzz", "Tidal-Media-Downloader");
|
||||
if (VersionHelper.Compare(sSelfVer, sLastVer) >= 0)
|
||||
return;
|
||||
|
||||
if (Directory.Exists(PATH))
|
||||
Directory.Delete(PATH, true);
|
||||
PathHelper.Mkdirs(PATH);
|
||||
if (GithubHelper.getLastReleaseFile("yaronzz", "Tidal-Media-Downloader", "tidal-gui.zip", PATH + "tidal-gui.zip"))
|
||||
{
|
||||
FastZip fz = new FastZip();
|
||||
try
|
||||
{
|
||||
fz.ExtractZip(PATH + "tidal-gui.zip", PATH, null);
|
||||
if (File.Exists(PATH + "tidal-gui.exe"))
|
||||
{
|
||||
string sBat = "ping -n 5 127.0.0.1\n";
|
||||
sBat += string.Format("move {0}tidal-gui.exe {0}..\\tidal-gui.exe\n", PATH);
|
||||
sBat += string.Format("start {0}..\\tidal-gui.exe\n", PATH);
|
||||
FileHelper.Write(sBat, true, BATF);
|
||||
FileHelper.Write(sLastVer, true, VERF);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
<Window x:Class="TIDALDL_UI.Pages.SearchView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:local="clr-namespace:TIDALDL_UI"
|
||||
xmlns:pages="clr-namespace:TIDALDL_UI.Pages"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:aigsc="clr-namespace:AIGS.Control;assembly=AIGS"
|
||||
mc:Ignorable="d"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextElement.FontWeight="Regular"
|
||||
TextElement.FontSize="13"
|
||||
TextOptions.TextFormattingMode="Ideal"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
|
||||
Width="850"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
WindowStyle="None"
|
||||
Background="{x:Null}"
|
||||
AllowsTransparency="True"
|
||||
Height="575"
|
||||
ShowInTaskbar="False"
|
||||
d:DataContext="{d:DesignInstance pages:SearchViewModel}">
|
||||
|
||||
<materialDesign:Card Name="m_CMainCard" materialDesign:ShadowAssist.ShadowDepth="Depth3" VerticalAlignment="Stretch" BorderThickness="3" BorderBrush="#FF171616" Margin="20,20,20,20">
|
||||
<materialDesign:DialogHost Identifier="RootDialog" SnackbarMessageQueue="{Binding ElementName=MainSnackbar, Path=MessageQueue}" Background="{x:Null}">
|
||||
|
||||
<Grid Margin="16,16,16,10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="50" />
|
||||
<RowDefinition Height="44" />
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="44" />
|
||||
|
||||
</Grid.RowDefinitions>
|
||||
<Label Content="{Binding Header}" Grid.Row="0" FontSize="30" VerticalAlignment="Top" Height="50" HorizontalContentAlignment="Center" BorderThickness="0,0,0,1" BorderBrush="#FFDEDEDE"/>
|
||||
<materialDesign:ColorZone Mode="PrimaryMid" Grid.Row="1">
|
||||
<StackPanel Orientation="Horizontal" Margin="2">
|
||||
<RadioButton Content="ALBUM" IsChecked="{Binding bCheckAlbum}" Style="{StaticResource MaterialDesignTabRadioButton}" Margin="4"/>
|
||||
<RadioButton Content="TRACK" IsChecked="{Binding bCheckTrack}" Style="{StaticResource MaterialDesignTabRadioButton}" Margin="4"/>
|
||||
<RadioButton Content="VIDEO" IsChecked="{Binding bCheckVideo}" Style="{StaticResource MaterialDesignTabRadioButton}" Margin="4"/>
|
||||
<RadioButton Content="ARTIST" IsChecked="{Binding bCheckArtist}" Style="{StaticResource MaterialDesignTabRadioButton}" Margin="4"/>
|
||||
<RadioButton Content="PLAYLIST" IsChecked="{Binding bCheckPlaylist}" Style="{StaticResource MaterialDesignTabRadioButton}" Margin="4"/>
|
||||
</StackPanel>
|
||||
</materialDesign:ColorZone>
|
||||
|
||||
<Grid Grid.Row="2" Background="WhiteSmoke">
|
||||
<ListView Grid.Row="2" ItemsSource="{Binding BindList}" SelectedIndex="{Binding SelectIndex}" ScrollViewer.HorizontalScrollBarVisibility="Hidden" SelectionMode="Single" >
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Header="#" Width="50" DisplayMemberBinding="{Binding Index}"/>
|
||||
<GridViewColumn Header="#" Width="30" DisplayMemberBinding="{Binding Flag}"/>
|
||||
<GridViewColumn Header="TITLE" Width="350" DisplayMemberBinding="{Binding Title}"/>
|
||||
<GridViewColumn Header="ARTIST" Width="260" DisplayMemberBinding="{Binding Artist}"/>
|
||||
<GridViewColumn Header="TIME" DisplayMemberBinding="{Binding Duration}"/>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
</Grid>
|
||||
<Grid Grid.Row="3">
|
||||
<Button IsDefault="True" Style="{DynamicResource MaterialDesignRaisedButton}"
|
||||
Command="{s:Action Confirm}"
|
||||
Content="Confirm"
|
||||
Height="27" VerticalAlignment="Bottom" Margin="380,0,214,7"/>
|
||||
<Button IsDefault="True" Style="{DynamicResource MaterialDesignRaisedButton}"
|
||||
Command="{s:Action Cancel}"
|
||||
Content="Cancel"
|
||||
Height="27" VerticalAlignment="Bottom" Margin="584,0,10,7"/>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="2" Grid.RowSpan="2" Background="White" Visibility="{Binding ShowWait}">
|
||||
<ProgressBar Style="{StaticResource MaterialDesignCircularProgressBar}" IsIndeterminate="True" Value="60" Height="Auto" Margin="280,98,284,209" Width="Auto"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</materialDesign:DialogHost>
|
||||
</materialDesign:Card>
|
||||
</Window>
|
||||
@@ -1,30 +0,0 @@
|
||||
using AIGS.Helper;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
/// <summary>
|
||||
/// AlbumInfo.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class SearchView : Window
|
||||
{
|
||||
public SearchView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media.Imaging;
|
||||
using AIGS.Helper;
|
||||
using AIGS.Common;
|
||||
using System.Collections.ObjectModel;
|
||||
using TIDALDL_UI.Else;
|
||||
using Stylet;
|
||||
using System.Windows;
|
||||
using Tidal;
|
||||
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
public class SearchItem
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string Artist { get; set; }
|
||||
public string Duration { get; set; }
|
||||
public int Index { get; set; }
|
||||
public string Flag { get; set; }//Quality or else
|
||||
public SearchItem(int index, string title, string artist, string duration, string flag=null)
|
||||
{
|
||||
Index = index;
|
||||
Title = title;
|
||||
Artist = artist;
|
||||
Duration = duration;
|
||||
Flag = flag;
|
||||
}
|
||||
}
|
||||
|
||||
public class SearchViewModel : Screen
|
||||
{
|
||||
public string Header { get; private set; } = "SEARCH";
|
||||
public int SelectIndex { get; set; } = 0;
|
||||
public bool bCheckPlaylist { get; set; } = false;
|
||||
public bool bCheckArtist { get; set; } = false;
|
||||
public bool bCheckAlbum { get; set; } = true;
|
||||
public bool bCheckTrack { get; set; } = false;
|
||||
public bool bCheckVideo { get; set; } = false;
|
||||
public Visibility ShowWait { get; set; } = Visibility.Hidden;
|
||||
public List<SearchItem> PlayList { get; set; } = new List<SearchItem>();
|
||||
public List<SearchItem> ArtistList { get; set; } = new List<SearchItem>();
|
||||
public List<SearchItem> AlbumList { get; set; } = new List<SearchItem>();
|
||||
public List<SearchItem> TrackList { get; set; } = new List<SearchItem>();
|
||||
public List<SearchItem> VideoList { get; set; } = new List<SearchItem>();
|
||||
public List<SearchItem> BindList
|
||||
{
|
||||
set { return; }
|
||||
get
|
||||
{
|
||||
if (bCheckPlaylist) return PlayList;
|
||||
if (bCheckArtist) return ArtistList;
|
||||
if (bCheckAlbum) return AlbumList;
|
||||
if (bCheckTrack) return TrackList;
|
||||
return VideoList;
|
||||
}
|
||||
}
|
||||
public SearchResult SearchInfo = null;
|
||||
public eObjectType ResultType = eObjectType.None;
|
||||
public object ResultObject = null;
|
||||
|
||||
#region Button
|
||||
public async void Confirm()
|
||||
{
|
||||
string ResultID = null;
|
||||
if (SelectIndex >= 0)
|
||||
{
|
||||
if (bCheckPlaylist && SearchInfo.Playlists.Count > 0)
|
||||
{
|
||||
ResultID = SearchInfo.Playlists[SelectIndex].UUID.ToString();
|
||||
ResultType = eObjectType.PLAYLIST;
|
||||
}
|
||||
if (bCheckArtist && SearchInfo.Artists.Count > 0)
|
||||
{
|
||||
ResultID = SearchInfo.Artists[SelectIndex].ID.ToString();
|
||||
ResultType = eObjectType.ARTIST;
|
||||
}
|
||||
if (bCheckAlbum && SearchInfo.Albums.Count > 0)
|
||||
{
|
||||
ResultID = SearchInfo.Albums[SelectIndex].ID.ToString();
|
||||
ResultType = eObjectType.ALBUM;
|
||||
}
|
||||
if (bCheckTrack && SearchInfo.Tracks.Count > 0)
|
||||
{
|
||||
ResultID = SearchInfo.Tracks[SelectIndex].ID.ToString();
|
||||
ResultType = eObjectType.TRACK;
|
||||
}
|
||||
if (bCheckVideo && SearchInfo.Videos.Count > 0)
|
||||
{
|
||||
ResultID = SearchInfo.Videos[SelectIndex].ID.ToString();
|
||||
ResultType = eObjectType.VIDEO;
|
||||
}
|
||||
|
||||
ShowWait = Visibility.Visible;
|
||||
await Task.Run(() =>
|
||||
{
|
||||
ResultObject = TidalTool.tryGet(ResultID, out ResultType, ResultType);
|
||||
});
|
||||
}
|
||||
RequestClose();
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
ResultType = eObjectType.None;
|
||||
RequestClose();
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void Load(SearchResult SearchInfo)
|
||||
{
|
||||
ShowWait = Visibility.Hidden;
|
||||
PlayList = new List<SearchItem>();
|
||||
ArtistList = new List<SearchItem>();
|
||||
AlbumList = new List<SearchItem>();
|
||||
TrackList = new List<SearchItem>();
|
||||
VideoList = new List<SearchItem>();
|
||||
this.SearchInfo = SearchInfo;
|
||||
foreach (Playlist item in SearchInfo.Playlists)
|
||||
PlayList.Add(new SearchItem(SearchInfo.Playlists.IndexOf(item) + 1, item.Title, item.Title, TimeHelper.ConverIntToString(item.Duration), TidalTool.getFlag(item)));
|
||||
foreach (Artist item in SearchInfo.Artists)
|
||||
ArtistList.Add(new SearchItem(SearchInfo.Artists.IndexOf(item) + 1, item.Name, item.Name, ""));
|
||||
foreach (Album item in SearchInfo.Albums)
|
||||
AlbumList.Add(new SearchItem(SearchInfo.Albums.IndexOf(item) + 1, item.Title, item.Artists[0].Name, TimeHelper.ConverIntToString(item.Duration), TidalTool.getFlag(item)));
|
||||
foreach (Track item in SearchInfo.Tracks)
|
||||
TrackList.Add(new SearchItem(SearchInfo.Tracks.IndexOf(item) + 1, item.Title, item.Artists[0].Name, TimeHelper.ConverIntToString(item.Duration), TidalTool.getFlag(item)));
|
||||
foreach (Video item in SearchInfo.Videos)
|
||||
VideoList.Add(new SearchItem(SearchInfo.Videos.IndexOf(item) + 1, item.Title, item.Artists[0].Name, TimeHelper.ConverIntToString(item.Duration), TidalTool.getFlag(item)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
<Window x:Class="TIDALDL_UI.Pages.SettingView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:local="clr-namespace:TIDALDL_UI"
|
||||
xmlns:pages="clr-namespace:TIDALDL_UI.Pages"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
Width="575"
|
||||
Height="415"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
WindowStyle="None"
|
||||
Background="{x:Null}"
|
||||
AllowsTransparency="True"
|
||||
d:DataContext="{d:DesignInstance pages:SettingViewModel}" ShowInTaskbar="False">
|
||||
<materialDesign:Card Name="m_CMainCard" materialDesign:ShadowAssist.ShadowDepth="Depth3" VerticalAlignment="Stretch" BorderThickness="3" BorderBrush="#FF171616" Margin="20,20,20,20">
|
||||
<materialDesign:DialogHost Identifier="RootDialog" SnackbarMessageQueue="{Binding ElementName=MainSnackbar, Path=MessageQueue}" Background="{x:Null}">
|
||||
<Grid Margin="8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="50" />
|
||||
<RowDefinition Height="240*" />
|
||||
<RowDefinition Height="47"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Label Content="SETTINGS" Grid.Row="0" FontSize="30" VerticalAlignment="Top" Height="50" HorizontalContentAlignment="Center" BorderThickness="0,0,0,1" BorderBrush="#FFDEDEDE"/>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="105"/>
|
||||
<ColumnDefinition Width="382*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border BorderThickness="0,0,1,0" BorderBrush="#FFDEDEDE">
|
||||
<StackPanel >
|
||||
<RadioButton Content="COMMON" IsChecked="{Binding CheckCommon}" Style="{StaticResource MaterialDesignTabRadioButton}" HorizontalContentAlignment="Right" BorderBrush="#FF0C2C53"/>
|
||||
<RadioButton Content="TRACK" IsChecked="{Binding CheckTrack}" Style="{StaticResource MaterialDesignTabRadioButton}" HorizontalContentAlignment="Right" BorderBrush="#FF0C2C53"/>
|
||||
<RadioButton Content="VIDEO" IsChecked="{Binding CheckVideo}" Style="{StaticResource MaterialDesignTabRadioButton}" HorizontalContentAlignment="Right" BorderBrush="#FF0C2C53"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!--Common config Visibility="{Binding CheckCommon, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"-->
|
||||
<Grid Grid.Column="1" Visibility="{Binding CheckCommon, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
|
||||
<Label Content="OutputDir" FontSize="15" VerticalAlignment="Top" HorizontalContentAlignment="Right" Margin="10,33,312,0" />
|
||||
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
||||
Name="m_CPath"
|
||||
ToolTip="Choose Path"
|
||||
Content="{Binding OutputDir, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Click="{s:Action SetOutputDir}"
|
||||
FontSize="15"
|
||||
Margin="107,32,22,0"
|
||||
HorizontalContentAlignment="Left"
|
||||
VerticalAlignment="Top" Height="30" Padding="0,4,16,4" BorderThickness="0,0,0,1" BorderBrush="#89000000"/>
|
||||
<Label Content="ThreadNum" FontSize="15" VerticalAlignment="Top" HorizontalContentAlignment="Right" Margin="10,67,307,0" Height="30" />
|
||||
<Label Content="SearchNum" FontSize="15" VerticalAlignment="Top" HorizontalContentAlignment="Right" Margin="10,97,307,0" Height="30" />
|
||||
<ComboBox SelectedIndex="{Binding ThreadNum, UpdateSourceTrigger=PropertyChanged}" Margin="107,67,22,168">
|
||||
<ComboBoxItem>1</ComboBoxItem>
|
||||
<ComboBoxItem>2</ComboBoxItem>
|
||||
<ComboBoxItem>3</ComboBoxItem>
|
||||
</ComboBox>
|
||||
<ComboBox SelectedIndex="{Binding SearchNum, UpdateSourceTrigger=PropertyChanged}" Margin="107,94,22,141">
|
||||
<ComboBoxItem>10</ComboBoxItem>
|
||||
<ComboBoxItem>20</ComboBoxItem>
|
||||
<ComboBoxItem>30</ComboBoxItem>
|
||||
<ComboBoxItem>40</ComboBoxItem>
|
||||
<ComboBoxItem>50</ComboBoxItem>
|
||||
</ComboBox>
|
||||
|
||||
<Label Content="AddYear" FontSize="15" VerticalAlignment="Top" HorizontalContentAlignment="Right" Margin="10,127,307,0" Height="30" />
|
||||
<ComboBox SelectedIndex="{Binding AddYearIndex, UpdateSourceTrigger=PropertyChanged}" Margin="107,126,22,109">
|
||||
<ComboBoxItem>No</ComboBoxItem>
|
||||
<ComboBoxItem>Before</ComboBoxItem>
|
||||
<ComboBoxItem>After</ComboBoxItem>
|
||||
</ComboBox>
|
||||
|
||||
<Label Content="Artist-Title" FontSize="15" VerticalAlignment="Top" HorizontalContentAlignment="Right" Margin="0,157,312,0" Height="30" />
|
||||
<ToggleButton Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="{Binding ArtistBeforeTitle, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Height="30" VerticalAlignment="Top" Margin="107,157,262,0"/>
|
||||
<Label Content="IncludeSingle" FontSize="15" VerticalAlignment="Top" HorizontalContentAlignment="Right" Margin="0,187,307,0" Height="30" />
|
||||
<ToggleButton Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="{Binding IncludeEPSingle, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Height="30" VerticalAlignment="Top" Margin="107,187,262,0"/>
|
||||
<Label Content="SaveCovers" FontSize="15" VerticalAlignment="Top" HorizontalContentAlignment="Right" Margin="0,217,307,0" Height="30" />
|
||||
<ToggleButton Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="{Binding SaveCovers, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Height="30" VerticalAlignment="Top" Margin="107,217,262,0"/>
|
||||
</Grid>
|
||||
|
||||
<!--Track config Visibility="{Binding CheckTrack, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"-->
|
||||
<Grid Grid.Column="1" Visibility="{Binding CheckTrack, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="30"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="Quality" FontSize="15" VerticalAlignment="Center" HorizontalContentAlignment="Right"/>
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="OnlyM4a" FontSize="15" VerticalAlignment="Center" HorizontalContentAlignment="Right"/>
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="AddHyphen" FontSize="15" VerticalAlignment="Center" HorizontalContentAlignment="Right"/>
|
||||
<Label Grid.Row="3" Grid.Column="0" Content="CheckExist" FontSize="15" VerticalAlignment="Center" HorizontalContentAlignment="Right"/>
|
||||
<Label Grid.Row="4" Grid.Column="0" Content="AddExplicit" FontSize="15" VerticalAlignment="Center" HorizontalContentAlignment="Right"/>
|
||||
<Label Grid.Row="5" Grid.Column="0" Content="Use Track number" FontSize="15" VerticalAlignment="Center" HorizontalContentAlignment="Right"/>
|
||||
|
||||
<ComboBox Grid.Row="0" Grid.Column="1" ItemsSource="{Binding QualityList}"
|
||||
SelectedIndex="{Binding SelectQualityIndex , UpdateSourceTrigger=PropertyChanged}"
|
||||
VerticalAlignment="Center" Padding="6,6,0,6"/>
|
||||
|
||||
<ToggleButton Grid.Row="1" Grid.Column="1" Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="{Binding OnlyM4a, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
|
||||
<ToggleButton Grid.Row="2" Grid.Column="1" Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="{Binding AddHyphen, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
|
||||
<ToggleButton Grid.Row="3" Grid.Column="1" Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="{Binding CheckExist, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
|
||||
<ToggleButton Grid.Row="4" Grid.Column="1" Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="{Binding AddExplicitTag, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
|
||||
<ToggleButton Grid.Row="5" Grid.Column="1" Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="{Binding UseTrackNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
|
||||
|
||||
|
||||
</Grid>
|
||||
|
||||
<!--Video config-->
|
||||
<Grid Grid.Column="1" Visibility="{Binding CheckVideo, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
|
||||
<Label Content="Resolution" FontSize="15" VerticalAlignment="Top" HorizontalContentAlignment="Right" Margin="10,33,312,0" />
|
||||
<ComboBox ItemsSource="{Binding ResolutionList}"
|
||||
SelectedIndex="{Binding SelectResolutionIndex , UpdateSourceTrigger=PropertyChanged}"
|
||||
Margin="107,32,87,0" VerticalAlignment="Top" Height="30" Padding="6,6,0,6">
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Button Command="{s:Action Confirm}" s:View.ActionTarget="{Binding}" Grid.Row="2" IsDefault="True" Style="{DynamicResource MaterialDesignRaisedButton}" Content="OK" Margin="10,0,10,10" Height="27" VerticalAlignment="Bottom"/>
|
||||
</Grid>
|
||||
|
||||
</materialDesign:DialogHost>
|
||||
</materialDesign:Card>
|
||||
</Window>
|
||||
@@ -1,29 +0,0 @@
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
/// <summary>
|
||||
/// Password.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class SettingView : Window
|
||||
{
|
||||
public SettingView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TIDALDL_UI.Else;
|
||||
using AIGS.Common;
|
||||
using System.IO;
|
||||
using Tidal;
|
||||
using System.Windows.Forms;
|
||||
using AIGS.Helper;
|
||||
|
||||
namespace TIDALDL_UI.Pages
|
||||
{
|
||||
public class SettingViewModel: Stylet.Screen
|
||||
{
|
||||
public string OutputDir { get; set; }
|
||||
public int ThreadNum { get; set; }
|
||||
public int SearchNum { get; set; }
|
||||
public int SelectQualityIndex { get; set; }
|
||||
public int SelectResolutionIndex { get; set; }
|
||||
public bool OnlyM4a { get; set; }
|
||||
public bool AddHyphen { get; set; }
|
||||
public bool UseTrackNumber { get; set; }
|
||||
public bool ToChinese { get; set; }
|
||||
public bool CheckExist { get; set; }
|
||||
public bool ArtistBeforeTitle { get; set; }
|
||||
|
||||
public bool AddExplicitTag { get; set; }
|
||||
public bool IncludeEPSingle { get; set; }
|
||||
public int AddYearIndex { get; set; }
|
||||
public bool SaveCovers { get; set; }
|
||||
|
||||
public bool CheckCommon { get; set; } = true;
|
||||
public bool CheckTrack { get; set; } = false;
|
||||
public bool CheckVideo { get; set; } = false;
|
||||
|
||||
public List<string> QualityList { get; set; }
|
||||
public List<string> ResolutionList { get; set; }
|
||||
|
||||
public SettingViewModel()
|
||||
{
|
||||
RefreshSetting();
|
||||
}
|
||||
|
||||
public void RefreshSetting()
|
||||
{
|
||||
OutputDir = Config.OutputDir();
|
||||
OnlyM4a = Config.OnlyM4a();
|
||||
AddExplicitTag = Config.AddExplicitTag();
|
||||
IncludeEPSingle = Config.IncludeEP();
|
||||
AddHyphen = Config.AddHyphen();
|
||||
SaveCovers = Config.SaveCovers();
|
||||
ToChinese = Config.ToChinese();
|
||||
CheckExist = Config.CheckExist();
|
||||
ArtistBeforeTitle = Config.ArtistBeforeTitle();
|
||||
AddYearIndex = Config.AddYear();
|
||||
ThreadNum = AIGS.Common.Convert.ConverStringToInt(Config.ThreadNum()) - 1;
|
||||
SearchNum = AIGS.Common.Convert.ConverStringToInt(Config.SearchNum()) / 10 - 1;
|
||||
QualityList = TidalTool.getQualityList();
|
||||
ResolutionList = TidalTool.getResolutionList();
|
||||
SelectQualityIndex = QualityList.IndexOf(Config.Quality().ToUpper());
|
||||
SelectResolutionIndex = ResolutionList.IndexOf(Config.Resolution().ToUpper());
|
||||
UseTrackNumber = Config.UseTrackNumber();
|
||||
|
||||
if (SelectQualityIndex < 0)
|
||||
SelectQualityIndex = 0;
|
||||
if (SelectResolutionIndex < 0)
|
||||
SelectResolutionIndex = 0;
|
||||
if (ThreadNum < 0)
|
||||
ThreadNum = 0;
|
||||
if (SearchNum < 0 || SearchNum > 5)
|
||||
SearchNum = 0;
|
||||
}
|
||||
|
||||
public void SetOutputDir()
|
||||
{
|
||||
FolderBrowserDialog openFileDialog = new FolderBrowserDialog();
|
||||
if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
||||
OutputDir = openFileDialog.SelectedPath;
|
||||
}
|
||||
|
||||
public void Confirm()
|
||||
{
|
||||
Config.ThreadNum((ThreadNum + 1).ToString());
|
||||
Config.SearchNum(((SearchNum + 1)*10).ToString());
|
||||
Config.OnlyM4a(OnlyM4a.ToString());
|
||||
Config.AddExplicitTag(AddExplicitTag.ToString());
|
||||
Config.SaveCovers(SaveCovers.ToString());
|
||||
Config.IncludeEP(IncludeEPSingle.ToString());
|
||||
Config.ToChinese(ToChinese.ToString());
|
||||
Config.CheckExist(CheckExist.ToString());
|
||||
Config.ArtistBeforeTitle(ArtistBeforeTitle.ToString());
|
||||
Config.AddHyphen(AddHyphen.ToString());
|
||||
Config.AddYear(AddYearIndex);
|
||||
Config.Quality(QualityList[SelectQualityIndex].ToLower());
|
||||
Config.Resolution(ResolutionList[SelectResolutionIndex]);
|
||||
Config.OutputDir(OutputDir);
|
||||
Config.UseTrackNumber(UseTrackNumber.ToString());
|
||||
|
||||
TidalTool.SetSearchMaxNum(int.Parse(Config.SearchNum()));
|
||||
ThreadTool.SetThreadNum(ThreadNum + 1);
|
||||
RequestClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<UserControl x:Class="TIDALDL_UI.Wait"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
MaxWidth="400" Width="116" Height="116">
|
||||
<Grid Margin="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="70*" />
|
||||
<RowDefinition Height="53" />
|
||||
</Grid.RowDefinitions>
|
||||
<ProgressBar Style="{StaticResource MaterialDesignCircularProgressBar}"
|
||||
Value="0"
|
||||
IsIndeterminate="True" />
|
||||
<Button Grid.Row="1"
|
||||
IsDefault="True" Style="{DynamicResource MaterialDesignFlatButton}"
|
||||
Content="CANCLE"
|
||||
Margin="-2,17,0,0"
|
||||
Click="Button_Click"
|
||||
Height="Auto" VerticalAlignment="Top" HorizontalContentAlignment="Center"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user