tidaler 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. tidaler/__init__.py +145 -0
  2. tidaler/api.py +121 -0
  3. tidaler/cli.py +626 -0
  4. tidaler/config.py +293 -0
  5. tidaler/constants.py +102 -0
  6. tidaler/dialog.py +360 -0
  7. tidaler/download.py +1797 -0
  8. tidaler/gui.py +2626 -0
  9. tidaler/helper/__init__.py +0 -0
  10. tidaler/helper/camelot.py +395 -0
  11. tidaler/helper/cli.py +45 -0
  12. tidaler/helper/decorator.py +22 -0
  13. tidaler/helper/decryption.py +63 -0
  14. tidaler/helper/exceptions.py +14 -0
  15. tidaler/helper/gui.py +225 -0
  16. tidaler/helper/path.py +691 -0
  17. tidaler/helper/tidal.py +278 -0
  18. tidaler/helper/wrapper.py +26 -0
  19. tidaler/logger.py +65 -0
  20. tidaler/metadata.py +226 -0
  21. tidaler/model/__init__.py +0 -0
  22. tidaler/model/cfg.py +147 -0
  23. tidaler/model/downloader.py +24 -0
  24. tidaler/model/gui_data.py +50 -0
  25. tidaler/model/meta.py +14 -0
  26. tidaler/ui/__init__.py +0 -0
  27. tidaler/ui/default_album_image.png +0 -0
  28. tidaler/ui/dialog_login.py +119 -0
  29. tidaler/ui/dialog_login.ui +195 -0
  30. tidaler/ui/dialog_settings.py +660 -0
  31. tidaler/ui/dialog_settings.ui +846 -0
  32. tidaler/ui/dialog_version.py +161 -0
  33. tidaler/ui/dialog_version.ui +227 -0
  34. tidaler/ui/dummy_register.py +33 -0
  35. tidaler/ui/dummy_wiggly.py +68 -0
  36. tidaler/ui/icon.icns +0 -0
  37. tidaler/ui/icon.ico +0 -0
  38. tidaler/ui/icon16.png +0 -0
  39. tidaler/ui/icon256.png +0 -0
  40. tidaler/ui/icon32.png +0 -0
  41. tidaler/ui/icon48.png +0 -0
  42. tidaler/ui/icon512.png +0 -0
  43. tidaler/ui/icon64.png +0 -0
  44. tidaler/ui/main.py +607 -0
  45. tidaler/ui/main.ui +823 -0
  46. tidaler/ui/spinner.py +221 -0
  47. tidaler/worker.py +34 -0
  48. tidaler-0.1.0.dist-info/METADATA +256 -0
  49. tidaler-0.1.0.dist-info/RECORD +52 -0
  50. tidaler-0.1.0.dist-info/WHEEL +4 -0
  51. tidaler-0.1.0.dist-info/entry_points.txt +6 -0
  52. tidaler-0.1.0.dist-info/licenses/LICENSE +661 -0
tidaler/__init__.py ADDED
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env python
2
+ import importlib.metadata
3
+ from pathlib import Path
4
+ from urllib.parse import urlparse
5
+
6
+ import requests
7
+ import toml
8
+
9
+ from tidaler.constants import REQUESTS_TIMEOUT_SEC
10
+ from tidaler.model.meta import ProjectInformation, ReleaseLatest
11
+
12
+
13
+ def metadata_project() -> ProjectInformation:
14
+ result: ProjectInformation
15
+ file_path: Path = Path(__file__)
16
+ tmp_result: dict = {}
17
+
18
+ paths: list[Path] = [
19
+ file_path.parent,
20
+ file_path.parent.parent,
21
+ file_path.parent.parent.parent,
22
+ ]
23
+
24
+ for pyproject_toml_dir in paths:
25
+ pyproject_toml_file: Path = pyproject_toml_dir / "pyproject.toml"
26
+
27
+ if pyproject_toml_file.is_file():
28
+ tmp_result = toml.load(pyproject_toml_file)
29
+
30
+ break
31
+
32
+ if tmp_result:
33
+ result = ProjectInformation(
34
+ version=tmp_result["project"]["version"], repository_url=tmp_result["project"]["urls"]["repository"]
35
+ )
36
+ else:
37
+ try:
38
+ meta_info = importlib.metadata.metadata(name_package())
39
+ repo_url = meta_info["Home-page"]
40
+
41
+ if not repo_url:
42
+ urls = meta_info.get_all("Project-URL")
43
+ # attempt to parse, else use hardcoded fallback
44
+ repo_url = next(
45
+ (url.split(", ")[1] for url in urls if url.startswith("Repository")),
46
+ "https://github.com/exislow/tidal-dl-ng",
47
+ )
48
+
49
+ result = ProjectInformation(version=meta_info["Version"], repository_url=repo_url)
50
+ except Exception:
51
+ result = ProjectInformation(version="0.0.0", repository_url="https://anerroroccur.ed/sorry/for/that")
52
+
53
+ return result
54
+
55
+
56
+ def version_app() -> str:
57
+ metadata: ProjectInformation = metadata_project()
58
+ version: str = metadata.version
59
+
60
+ return version
61
+
62
+
63
+ def repository_url() -> str:
64
+ metadata: ProjectInformation = metadata_project()
65
+ url_repo: str = metadata.repository_url
66
+
67
+ return url_repo
68
+
69
+
70
+ def repository_path() -> str:
71
+ url_repo: str = repository_url()
72
+ url_path: str = urlparse(url_repo).path
73
+
74
+ return url_path
75
+
76
+
77
+ def latest_version_information() -> ReleaseLatest:
78
+ release_info: ReleaseLatest
79
+ repo_path: str = repository_path()
80
+ url: str = f"https://api.github.com/repos{repo_path}/releases/latest"
81
+
82
+ try:
83
+ response = requests.get(url, timeout=REQUESTS_TIMEOUT_SEC)
84
+ response.raise_for_status()
85
+
86
+ release_info_json: dict = response.json()
87
+
88
+ release_info = ReleaseLatest(
89
+ version=release_info_json["tag_name"],
90
+ url=release_info_json["html_url"],
91
+ release_info=release_info_json["body"],
92
+ )
93
+ except (requests.RequestException, KeyError, ValueError):
94
+ release_info = ReleaseLatest(
95
+ version="v0.0.0",
96
+ url=url,
97
+ release_info=f"Something went wrong calling {url}. Check your internet connection.",
98
+ )
99
+
100
+ return release_info
101
+
102
+
103
+ def name_package() -> str:
104
+ package_name: str = __package__ or __name__
105
+
106
+ return package_name
107
+
108
+
109
+ def is_dev_env() -> bool:
110
+ package_name: str = name_package()
111
+ result: bool = False
112
+
113
+ # Check if package is running from source code == dev mode
114
+ # If package is not running in Nuitka environment, try to import it from pip libraries.
115
+ # If this also fails, it is dev mode.
116
+ if "__compiled__" not in globals():
117
+ try:
118
+ importlib.metadata.version(package_name)
119
+ except Exception:
120
+ # If package is not installed
121
+ result = True
122
+
123
+ return result
124
+
125
+
126
+ def name_app() -> str:
127
+ app_name: str = name_package()
128
+ is_dev: bool = is_dev_env()
129
+
130
+ if is_dev:
131
+ app_name += "-dev"
132
+
133
+ return app_name
134
+
135
+
136
+ __name_display__ = name_app()
137
+ __version__ = version_app()
138
+
139
+
140
+ def update_available() -> tuple[bool, ReleaseLatest]:
141
+ latest_info: ReleaseLatest = latest_version_information()
142
+ version_current: str = f"v{__version__}"
143
+
144
+ result = version_current not in [latest_info.version, "v0.0.0"]
145
+ return result, latest_info
tidaler/api.py ADDED
@@ -0,0 +1,121 @@
1
+ import json
2
+
3
+ import requests
4
+
5
+ # See also
6
+ # https://github.com/yaronzz/Tidal-Media-Downloader/commit/1d5b8cd8f65fd1def45d6406778248249d6dfbdf
7
+ # https://github.com/yaronzz/Tidal-Media-Downloader/pull/840
8
+ # https://github.com/nathom/streamrip/tree/main/streamrip
9
+ # https://github.com/arnesongit/plugin.audio.tidal2/blob/e9429d601d0c303d775d05a19a66415b57479d87/resources/lib/tidal2/tidalapi/__init__.py#L86
10
+
11
+ # TODO: Implement this into `Download`: Session should randomize the usage.
12
+ __KEYS_JSON__ = """
13
+ {
14
+ "version": "1.0.1",
15
+ "keys": [
16
+ // Invalid
17
+ {
18
+ "platform": "Fire TV",
19
+ "formats": "Normal/High/HiFi(No Master)",
20
+ "clientId": "OmDtrzFgyVVL6uW56OnFA2COiabqm",
21
+ "clientSecret": "zxen1r3pO0hgtOC7j6twMo9UAqngGrmRiWpV7QC1zJ8=",
22
+ "valid": "False",
23
+ "from": "Fokka-Engineering (https://github.com/Fokka-Engineering/libopenTIDAL/blob/655528e26e4f3ee2c426c06ea5b8440cf27abc4a/README.md#example)"
24
+ },
25
+ // Only max MQA.
26
+ {
27
+ "platform": "Fire TV",
28
+ "formats": "Master-Only(Else Error)",
29
+ "clientId": "7m7Ap0JC9j1cOM3n",
30
+ "clientSecret": "vRAdA108tlvkJpTsGZS8rGZ7xTlbJ0qaZ2K9saEzsgY=",
31
+ "valid": "True",
32
+ "from": "Dniel97 (https://github.com/Dniel97/RedSea/blob/4ba02b88cee33aeb735725cb854be6c66ff372d4/config/settings.example.py#L68)"
33
+ },
34
+ // Invalid
35
+ {
36
+ "platform": "Android TV",
37
+ "formats": "Normal/High/HiFi(No Master)",
38
+ "clientId": "Pzd0ExNVHkyZLiYN",
39
+ "clientSecret": "W7X6UvBaho+XOi1MUeCX6ewv2zTdSOV3Y7qC3p3675I=",
40
+ "valid": "False",
41
+ "from": ""
42
+ },
43
+ // Invalid
44
+ {
45
+ "platform": "TV",
46
+ "formats": "Normal/High/HiFi/Master",
47
+ "clientId": "8SEZWa4J1NVC5U5Y",
48
+ "clientSecret": "owUYDkxddz+9FpvGX24DlxECNtFEMBxipU0lBfrbq60=",
49
+ "valid": "False",
50
+ "from": "morguldir (https://github.com/morguldir/python-tidal/commit/50f1afcd2079efb2b4cf694ef5a7d67fdf619d09)"
51
+ },
52
+ // Invalid
53
+ {
54
+ "platform": "Android Auto",
55
+ "formats": "Normal/High/HiFi/Master",
56
+ "clientId": "zU4XHVVkc2tDPo4t",
57
+ "clientSecret": "VJKhDFqJPqvsPVNBV6ukXTJmwlvbttP7wlMlrc72se4=",
58
+ "valid": "True",
59
+ "from": "1nikolas (https://github.com/yaronzz/Tidal-Media-Downloader/pull/840)"
60
+ }
61
+ ]
62
+ }
63
+ """
64
+ __API_KEYS__ = json.loads(__KEYS_JSON__)
65
+ __ERROR_KEY__ = (
66
+ {
67
+ "platform": "None",
68
+ "formats": "",
69
+ "clientId": "",
70
+ "clientSecret": "",
71
+ "valid": "False",
72
+ },
73
+ )
74
+
75
+ from tidaler.constants import REQUESTS_TIMEOUT_SEC
76
+
77
+
78
+ def getNum():
79
+ return len(__API_KEYS__["keys"])
80
+
81
+
82
+ def getItem(index: int):
83
+ if index < 0 or index >= len(__API_KEYS__["keys"]):
84
+ return __ERROR_KEY__
85
+ return __API_KEYS__["keys"][index]
86
+
87
+
88
+ def isItemValid(index: int):
89
+ item = getItem(index)
90
+ return item["valid"] == "True"
91
+
92
+
93
+ def getItems():
94
+ return __API_KEYS__["keys"]
95
+
96
+
97
+ def getLimitIndexs():
98
+ array = []
99
+ for i in range(len(__API_KEYS__["keys"])):
100
+ array.append(str(i))
101
+ return array
102
+
103
+
104
+ def getVersion():
105
+ return __API_KEYS__["version"]
106
+
107
+
108
+ # Load from gist
109
+ try:
110
+ respond = requests.get(
111
+ "https://api.github.com/gists/48d01f5a24b4b7b37f19443977c22cd6", timeout=REQUESTS_TIMEOUT_SEC
112
+ )
113
+ respond.raise_for_status()
114
+
115
+ if respond.status_code == 200:
116
+ content = respond.json()["files"]["tidal-api-key.json"]["content"]
117
+ __API_KEYS__ = json.loads(content)
118
+ except requests.RequestException as e:
119
+ # Failed to load API keys from gist, will use fallback keys
120
+ print(f"Failed to load API keys from gist: {e}")
121
+ pass