yutipy 2.2.10__py3-none-any.whl → 2.2.12__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.
Potentially problematic release.
This version of yutipy might be problematic. Click here for more details.
- yutipy/base_clients.py +2 -2
- yutipy/deezer.py +2 -2
- yutipy/itunes.py +9 -12
- yutipy/lastfm.py +1 -1
- yutipy/utils/helpers.py +80 -13
- {yutipy-2.2.10.dist-info → yutipy-2.2.12.dist-info}/METADATA +1 -3
- {yutipy-2.2.10.dist-info → yutipy-2.2.12.dist-info}/RECORD +11 -11
- {yutipy-2.2.10.dist-info → yutipy-2.2.12.dist-info}/WHEEL +1 -1
- {yutipy-2.2.10.dist-info → yutipy-2.2.12.dist-info}/entry_points.txt +0 -0
- {yutipy-2.2.10.dist-info → yutipy-2.2.12.dist-info}/licenses/LICENSE +0 -0
- {yutipy-2.2.10.dist-info → yutipy-2.2.12.dist-info}/top_level.txt +0 -0
yutipy/base_clients.py
CHANGED
|
@@ -172,7 +172,7 @@ class BaseClient:
|
|
|
172
172
|
self._token_expires_in = token_info.get("expires_in")
|
|
173
173
|
self._token_requested_at = token_info.get("requested_at")
|
|
174
174
|
else:
|
|
175
|
-
logger.
|
|
175
|
+
logger.debug("The access token is still valid, no need to refresh.")
|
|
176
176
|
except TypeError:
|
|
177
177
|
logger.debug(
|
|
178
178
|
f"token requested at: {self._token_requested_at} | token expires in: {self._token_expires_in}"
|
|
@@ -419,7 +419,7 @@ class BaseAuthClient:
|
|
|
419
419
|
self._token_requested_at = token_info.get("requested_at")
|
|
420
420
|
|
|
421
421
|
else:
|
|
422
|
-
logger.
|
|
422
|
+
logger.debug("The access token is still valid, no need to refresh.")
|
|
423
423
|
except TypeError:
|
|
424
424
|
logger.debug(
|
|
425
425
|
f"token requested at: {self._token_requested_at} | token expires in: {self._token_expires_in}"
|
yutipy/deezer.py
CHANGED
|
@@ -95,7 +95,7 @@ class Deezer:
|
|
|
95
95
|
return None
|
|
96
96
|
|
|
97
97
|
try:
|
|
98
|
-
logger.debug(f"Parsing response JSON
|
|
98
|
+
logger.debug(f"Parsing response JSON.")
|
|
99
99
|
result = response.json()["data"]
|
|
100
100
|
except (IndexError, KeyError, ValueError) as e:
|
|
101
101
|
logger.warning(f"Invalid response structure from Deezer: {e}")
|
|
@@ -159,7 +159,7 @@ class Deezer:
|
|
|
159
159
|
return None
|
|
160
160
|
|
|
161
161
|
try:
|
|
162
|
-
logger.debug(f"Response JSON
|
|
162
|
+
logger.debug(f"Parsing Response JSON.")
|
|
163
163
|
result = response.json()
|
|
164
164
|
except ValueError as e:
|
|
165
165
|
logger.warning(f"Invalid response received from Deezer: {e}")
|
yutipy/itunes.py
CHANGED
|
@@ -95,7 +95,7 @@ class Itunes:
|
|
|
95
95
|
return None
|
|
96
96
|
|
|
97
97
|
try:
|
|
98
|
-
logger.debug(f"Parsing response JSON
|
|
98
|
+
logger.debug(f"Parsing response JSON.")
|
|
99
99
|
result = response.json()["results"]
|
|
100
100
|
except (IndexError, KeyError, ValueError) as e:
|
|
101
101
|
logger.warning(f"Invalid response structure from iTunes: {e}")
|
|
@@ -183,17 +183,14 @@ class Itunes:
|
|
|
183
183
|
tuple
|
|
184
184
|
The extracted album title and type.
|
|
185
185
|
"""
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return result["collectionName"], (
|
|
195
|
-
result["wrapperType"] if guessed_right else guess
|
|
196
|
-
)
|
|
186
|
+
|
|
187
|
+
guess = guess_album_type(result.get("trackCount", 1))
|
|
188
|
+
guessed_right = are_strings_similar(
|
|
189
|
+
result.get("wrapperType", "x"), guess, use_translation=False
|
|
190
|
+
)
|
|
191
|
+
return result["collectionName"], (
|
|
192
|
+
result["wrapperType"] if guessed_right else guess
|
|
193
|
+
)
|
|
197
194
|
|
|
198
195
|
def _format_release_date(self, release_date: str) -> str:
|
|
199
196
|
"""
|
yutipy/lastfm.py
CHANGED
|
@@ -154,7 +154,7 @@ class LastFm:
|
|
|
154
154
|
artists=", ".join(
|
|
155
155
|
separate_artists(result.get("artist", {}).get("#text"))
|
|
156
156
|
),
|
|
157
|
-
id=result.get("mbid"),
|
|
157
|
+
id=result.get("mbid") if result.get("mbid") else None,
|
|
158
158
|
timestamp=result.get("date", {}).get("uts") or time(),
|
|
159
159
|
title=result.get("name"),
|
|
160
160
|
url=result.get("url"),
|
yutipy/utils/helpers.py
CHANGED
|
@@ -5,6 +5,13 @@ from rapidfuzz.utils import default_process
|
|
|
5
5
|
|
|
6
6
|
kakasi = pykakasi.kakasi()
|
|
7
7
|
|
|
8
|
+
TRANSLATION_CACHE = {}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def similarity(str1: str, str2: str, threshold: int = 80):
|
|
12
|
+
similarity_score = fuzz.WRatio(str1, str2, processor=default_process)
|
|
13
|
+
return similarity_score > threshold
|
|
14
|
+
|
|
8
15
|
|
|
9
16
|
def translate_text(
|
|
10
17
|
text: str,
|
|
@@ -76,30 +83,90 @@ def are_strings_similar(
|
|
|
76
83
|
bool: True if the strings are similar, otherwise False.
|
|
77
84
|
"""
|
|
78
85
|
|
|
86
|
+
"""
|
|
87
|
+
note for myself so that it make sense later ~ _(:з)∠)_
|
|
88
|
+
0. Check cached strings for comparision
|
|
89
|
+
a. if found and same, return True.
|
|
90
|
+
1. normalize original strings.
|
|
91
|
+
a. if both same, return True.
|
|
92
|
+
2. translate original string.
|
|
93
|
+
a. if both same, return True.
|
|
94
|
+
3. translate normalized string.
|
|
95
|
+
a. if both same, return True.
|
|
96
|
+
4. return False.
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
# ### Step 0 ####
|
|
100
|
+
cached_str1 = TRANSLATION_CACHE.get(str1, str1)
|
|
101
|
+
cached_str2 = TRANSLATION_CACHE.get(str2, str2)
|
|
102
|
+
similar = similarity(cached_str1, cached_str2, threshold=threshold)
|
|
103
|
+
if similar:
|
|
104
|
+
return True
|
|
105
|
+
# ###############
|
|
106
|
+
|
|
107
|
+
# ### Step 1 ####
|
|
108
|
+
# Transliterate / Normalize Strings
|
|
109
|
+
normalized_str1 = (
|
|
110
|
+
TRANSLATION_CACHE.get(str1)
|
|
111
|
+
or "".join(item["hepburn"] for item in kakasi.convert(str1))
|
|
112
|
+
or str1
|
|
113
|
+
)
|
|
114
|
+
normalized_str2 = (
|
|
115
|
+
TRANSLATION_CACHE.get(str2)
|
|
116
|
+
or "".join(item["hepburn"] for item in kakasi.convert(str2))
|
|
117
|
+
or str2
|
|
118
|
+
)
|
|
119
|
+
similar = similarity(normalized_str1, normalized_str2, threshold=threshold)
|
|
120
|
+
if similar:
|
|
121
|
+
TRANSLATION_CACHE[str1] = normalized_str1
|
|
122
|
+
TRANSLATION_CACHE[str2] = normalized_str2
|
|
123
|
+
return True
|
|
124
|
+
# ###############
|
|
125
|
+
|
|
79
126
|
if use_translation:
|
|
80
|
-
|
|
81
|
-
|
|
127
|
+
# ### Step 2 ####
|
|
128
|
+
original_translated_str1 = (
|
|
129
|
+
TRANSLATION_CACHE.get(str1)
|
|
130
|
+
or translate_text(str1, session=translation_session)["destination-text"]
|
|
82
131
|
if translation_session
|
|
83
132
|
else translate_text(str1)["destination-text"]
|
|
84
133
|
)
|
|
85
|
-
|
|
86
|
-
|
|
134
|
+
original_translated_str2 = (
|
|
135
|
+
TRANSLATION_CACHE.get(str2)
|
|
136
|
+
or translate_text(str2, session=translation_session)["destination-text"]
|
|
87
137
|
if translation_session
|
|
88
138
|
else translate_text(str2)["destination-text"]
|
|
89
139
|
)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
translated_str1, translated_str2, processor=default_process
|
|
140
|
+
similar = similarity(
|
|
141
|
+
original_translated_str1, original_translated_str2, threshold=threshold
|
|
93
142
|
)
|
|
94
|
-
if
|
|
143
|
+
if similar:
|
|
144
|
+
TRANSLATION_CACHE[str1] = original_translated_str1
|
|
145
|
+
TRANSLATION_CACHE[str2] = original_translated_str2
|
|
95
146
|
return True
|
|
147
|
+
# ###############
|
|
96
148
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
149
|
+
normalized_translated_str1 = (
|
|
150
|
+
TRANSLATION_CACHE.get(str1)
|
|
151
|
+
or translate_text(str1, session=translation_session)["destination-text"]
|
|
152
|
+
if translation_session
|
|
153
|
+
else translation_session(str1)["destination-text"]
|
|
154
|
+
)
|
|
155
|
+
normalized_translated_str2 = (
|
|
156
|
+
TRANSLATION_CACHE.get(str2)
|
|
157
|
+
or translate_text(str2, session=translation_session)["destination-text"]
|
|
158
|
+
if translation_session
|
|
159
|
+
else translate_text(str2)["destination-text"]
|
|
160
|
+
)
|
|
161
|
+
similar = similarity(
|
|
162
|
+
normalized_translated_str1, normalized_translated_str2, threshold=threshold
|
|
163
|
+
)
|
|
164
|
+
if similar:
|
|
165
|
+
TRANSLATION_CACHE[str1] = normalized_translated_str1
|
|
166
|
+
TRANSLATION_CACHE[str2] = normalized_translated_str2
|
|
167
|
+
return True
|
|
100
168
|
|
|
101
|
-
|
|
102
|
-
return similarity_score > threshold
|
|
169
|
+
return False
|
|
103
170
|
|
|
104
171
|
|
|
105
172
|
def separate_artists(artists: str, custom_separator: str = None) -> list[str]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: yutipy
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.12
|
|
4
4
|
Summary: A simple Python package to interact with various music platforms APIs.
|
|
5
5
|
Author: Cheap Nightbot
|
|
6
6
|
Author-email: Cheap Nightbot <hi@cheapnightbot.slmail.me>
|
|
@@ -30,8 +30,6 @@ Requires-Dist: python-dotenv==1.1.0
|
|
|
30
30
|
Requires-Dist: rapidfuzz==3.13.0
|
|
31
31
|
Requires-Dist: requests==2.32.3
|
|
32
32
|
Requires-Dist: ytmusicapi==1.10.3
|
|
33
|
-
Provides-Extra: dev
|
|
34
|
-
Requires-Dist: pytest; extra == "dev"
|
|
35
33
|
Dynamic: license-file
|
|
36
34
|
|
|
37
35
|
<p align="center">
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
yutipy/__init__.py,sha256=Zrw3cr_6khXp1IgQdZxGcUM9A64GYgPs-6rlqSukW5Q,294
|
|
2
|
-
yutipy/base_clients.py,sha256=
|
|
3
|
-
yutipy/deezer.py,sha256=
|
|
2
|
+
yutipy/base_clients.py,sha256=FHCyCUQ-qE2Jo5JH-DZCxupoZTlb5ADs8XKDbHDVHwA,21687
|
|
3
|
+
yutipy/deezer.py,sha256=ZI1C5gam8NiNznyyagn5r0Potpg25MXja8UXg-9i9ug,10463
|
|
4
4
|
yutipy/exceptions.py,sha256=zz0XyyZr5xRcmRyw3hdTGaVRcwRn_RSYZdmwmuO0sEM,1379
|
|
5
|
-
yutipy/itunes.py,sha256=
|
|
5
|
+
yutipy/itunes.py,sha256=FAHZDUn6Mvk2t5Ws5rF0hQMzIKZAIflR49lhEPIUyLs,7317
|
|
6
6
|
yutipy/kkbox.py,sha256=Pfx-ZgAI9F1cbxjr7MCsMi-QulNt67t60L7y9lNmo5g,11503
|
|
7
|
-
yutipy/lastfm.py,sha256=
|
|
7
|
+
yutipy/lastfm.py,sha256=hOFQOZdf51Gp2m02b4NjKRmQ9yQZ9Yas6MaM78c-oCg,5970
|
|
8
8
|
yutipy/logger.py,sha256=GyLBlfQZ6pLNJ5MbyQSvcD_PkxmFdX41DPq5aeG1z68,1316
|
|
9
9
|
yutipy/models.py,sha256=45M-bNHusaAan_Ta_E9DyvsWujsT-ivbJqIfy2-i3R8,2343
|
|
10
10
|
yutipy/musicyt.py,sha256=n3yaH9qyGlsW2HKPAmqYQNGzhuDH4s5Gh0R5v4JPoeg,9472
|
|
@@ -14,10 +14,10 @@ yutipy/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
14
14
|
yutipy/cli/config.py,sha256=e5RIq6RxVxxzx30nKVMa06gwyQ258s7U0WA1xvJuR_0,4543
|
|
15
15
|
yutipy/cli/search.py,sha256=8SQw0bjRzRqAg-FuVz9aWjB2KBZqmCf38SyKAQ3rx5E,3025
|
|
16
16
|
yutipy/utils/__init__.py,sha256=AZaqvs6AJwnqwJuodbGnHu702WSUqc8plVC16SppOcU,239
|
|
17
|
-
yutipy/utils/helpers.py,sha256
|
|
18
|
-
yutipy-2.2.
|
|
19
|
-
yutipy-2.2.
|
|
20
|
-
yutipy-2.2.
|
|
21
|
-
yutipy-2.2.
|
|
22
|
-
yutipy-2.2.
|
|
23
|
-
yutipy-2.2.
|
|
17
|
+
yutipy/utils/helpers.py,sha256=-iH0bx_sxW3Y3jjl6eTbY6QOBoG5t4obRcp7GGyw3ro,7476
|
|
18
|
+
yutipy-2.2.12.dist-info/licenses/LICENSE,sha256=_89JsS2QnBG8tAb5-VWbJDj_uJ002zPJAYBJJdh3DPY,1071
|
|
19
|
+
yutipy-2.2.12.dist-info/METADATA,sha256=OY5NoPGtT3vZZGs_5oleKfzPlwFQuTlk1SH5c2zbFJI,6369
|
|
20
|
+
yutipy-2.2.12.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
|
21
|
+
yutipy-2.2.12.dist-info/entry_points.txt,sha256=BrgmanaPjQqKQ3Ip76JLcsPgGANtrBSURf5CNIxl1HA,106
|
|
22
|
+
yutipy-2.2.12.dist-info/top_level.txt,sha256=t2A5V2_mUcfnHkbCy6tAQlb3909jDYU5GQgXtA4756I,7
|
|
23
|
+
yutipy-2.2.12.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|