yutipy 2.2.2__py3-none-any.whl → 2.2.4__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/deezer.py CHANGED
@@ -9,11 +9,10 @@ from yutipy.exceptions import (
9
9
  DeezerException,
10
10
  InvalidResponseException,
11
11
  InvalidValueException,
12
- NetworkException,
13
12
  )
13
+ from yutipy.logger import logger
14
14
  from yutipy.models import MusicInfo
15
15
  from yutipy.utils.helpers import are_strings_similar, is_valid_string
16
- from yutipy.logger import logger
17
16
 
18
17
 
19
18
  class Deezer:
@@ -97,17 +96,17 @@ class Deezer:
97
96
  logger.debug(f"Response status code: {response.status_code}")
98
97
  response.raise_for_status()
99
98
  except requests.RequestException as e:
100
- logger.error(f"Network error while fetching music info: {e}")
101
- raise NetworkException(f"Network error occurred: {e}")
99
+ logger.warning(f"Network error while fetching music info: {e}")
100
+ return None
102
101
  except Exception as e:
103
- logger.exception(f"Unexpected error while searching Deezer: {e}")
102
+ logger.warning(f"Unexpected error while searching Deezer: {e}")
104
103
  raise DeezerException(f"An error occurred while searching Deezer: {e}")
105
104
 
106
105
  try:
107
106
  logger.debug(f"Parsing response JSON: {response.json()}")
108
107
  result = response.json()["data"]
109
108
  except (IndexError, KeyError, ValueError) as e:
110
- logger.error(f"Invalid response structure from Deezer: {e}")
109
+ logger.warning(f"Invalid response structure from Deezer: {e}")
111
110
  raise InvalidResponseException(f"Invalid response received: {e}")
112
111
 
113
112
  music_info = self._parse_results(artist, song, result)
@@ -164,17 +163,17 @@ class Deezer:
164
163
  logger.debug(f"Response status code: {response.status_code}")
165
164
  response.raise_for_status()
166
165
  except requests.RequestException as e:
167
- logger.error(f"Error fetching track info: {e}")
168
- raise NetworkException(f"Network error occurred: {e}")
166
+ logger.warning(f"Error fetching track info: {e}")
167
+ return None
169
168
  except Exception as e:
170
- logger.error(f"Error fetching track info: {e}")
169
+ logger.warning(f"Error fetching track info: {e}")
171
170
  raise DeezerException(f"An error occurred while fetching track info: {e}")
172
171
 
173
172
  try:
174
173
  logger.debug(f"Response JSON: {response.json()}")
175
174
  result = response.json()
176
175
  except ValueError as e:
177
- logger.error(f"Invalid response received from Deezer: {e}")
176
+ logger.warning(f"Invalid response received from Deezer: {e}")
178
177
  raise InvalidResponseException(f"Invalid response received: {e}")
179
178
 
180
179
  return {
@@ -205,17 +204,17 @@ class Deezer:
205
204
  logger.info(f"Response status code: {response.status_code}")
206
205
  response.raise_for_status()
207
206
  except requests.RequestException as e:
208
- logger.error(f"Error fetching album info: {e}")
209
- raise NetworkException(f"Network error occurred: {e}")
207
+ logger.warning(f"Error fetching album info: {e}")
208
+ return None
210
209
  except Exception as e:
211
- logger.error(f"Error fetching album info: {e}")
210
+ logger.warning(f"Error fetching album info: {e}")
212
211
  raise DeezerException(f"An error occurred while fetching album info: {e}")
213
212
 
214
213
  try:
215
214
  logger.debug(f"Response JSON: {response.json()}")
216
215
  result = response.json()
217
216
  except ValueError as e:
218
- logger.error(f"Invalid response received from Deezer: {e}")
217
+ logger.warning(f"Invalid response received from Deezer: {e}")
219
218
  raise InvalidResponseException(f"Invalid response received: {e}")
220
219
 
221
220
  return {
@@ -323,6 +322,7 @@ class Deezer:
323
322
 
324
323
  if __name__ == "__main__":
325
324
  import logging
325
+
326
326
  from yutipy.logger import enable_logging
327
327
 
328
328
  enable_logging(level=logging.DEBUG)
yutipy/exceptions.py CHANGED
@@ -2,7 +2,6 @@ __all__ = [
2
2
  "AuthenticationException",
3
3
  "InvalidResponseException",
4
4
  "InvalidValueException",
5
- "NetworkException",
6
5
  "YutipyException",
7
6
  ]
8
7
 
@@ -25,10 +24,6 @@ class InvalidValueException(YutipyException):
25
24
  """Exception raised for invalid values."""
26
25
 
27
26
 
28
- class NetworkException(YutipyException):
29
- """Exception raised for network-related errors."""
30
-
31
-
32
27
  # Service Exceptions
33
28
  class DeezerException(YutipyException):
34
29
  """Exception raised for errors related to the Deezer API."""
yutipy/itunes.py CHANGED
@@ -9,8 +9,7 @@ import requests
9
9
  from yutipy.exceptions import (
10
10
  InvalidResponseException,
11
11
  InvalidValueException,
12
- ItunesException,
13
- NetworkException,
12
+ ItunesException
14
13
  )
15
14
  from yutipy.models import MusicInfo
16
15
  from yutipy.utils.helpers import (
@@ -100,8 +99,8 @@ class Itunes:
100
99
  logger.debug(f"Response status code: {response.status_code}")
101
100
  response.raise_for_status()
102
101
  except requests.RequestException as e:
103
- logger.error(f"Network error while searching iTunes: {e}")
104
- raise NetworkException(f"Network error occurred: {e}")
102
+ logger.warning(f"Network error while searching iTunes: {e}")
103
+ return None
105
104
  except Exception as e:
106
105
  logger.exception(f"Unexpected error while searching iTunes: {e}")
107
106
  raise ItunesException(f"An error occurred while searching iTunes: {e}")
@@ -110,7 +109,7 @@ class Itunes:
110
109
  logger.debug(f"Parsing response JSON: {response.json()}")
111
110
  result = response.json()["results"]
112
111
  except (IndexError, KeyError, ValueError) as e:
113
- logger.error(f"Invalid response structure from iTunes: {e}")
112
+ logger.warning(f"Invalid response structure from iTunes: {e}")
114
113
  raise InvalidResponseException(f"Invalid response received: {e}")
115
114
 
116
115
  music_info = self._parse_result(artist, song, result)
yutipy/kkbox.py CHANGED
@@ -12,10 +12,8 @@ from dotenv import load_dotenv
12
12
 
13
13
  from yutipy.exceptions import (
14
14
  AuthenticationException,
15
- InvalidResponseException,
16
15
  InvalidValueException,
17
16
  KKBoxException,
18
- NetworkException,
19
17
  )
20
18
  from yutipy.logger import logger
21
19
  from yutipy.models import MusicInfo
@@ -91,6 +89,13 @@ class KKBox:
91
89
  self.__access_token = token_info.get("access_token")
92
90
  self.__token_expires_in = token_info.get("expires_in")
93
91
  self.__token_requested_at = token_info.get("requested_at")
92
+
93
+ try:
94
+ self.save_access_token(token_info)
95
+ except NotImplementedError:
96
+ logger.warning(
97
+ "`save_access_token` is not implemented, falling back to in-memory storage. Access token will not be saved."
98
+ )
94
99
  else:
95
100
  logger.warning(
96
101
  "`defer_load` is set to `True`. Make sure to call `load_token_after_init()`."
@@ -135,6 +140,13 @@ class KKBox:
135
140
  self.__token_expires_in = token_info.get("expires_in")
136
141
  self.__token_requested_at = token_info.get("requested_at")
137
142
 
143
+ try:
144
+ self.save_access_token(token_info)
145
+ except NotImplementedError:
146
+ logger.warning(
147
+ "`save_access_token` is not implemented, falling back to in-memory storage. Access token will not be saved."
148
+ )
149
+
138
150
  def __authorization_header(self) -> dict:
139
151
  """
140
152
  Generates the authorization header for Spotify API requests.
@@ -173,15 +185,15 @@ class KKBox:
173
185
  logger.debug(f"Authentication response status code: {response.status_code}")
174
186
  response.raise_for_status()
175
187
  except requests.RequestException as e:
176
- logger.error(f"Network error during KKBOX authentication: {e}")
177
- raise NetworkException(f"Network error occurred: {e}")
188
+ logger.warning(f"Network error during KKBOX authentication: {e}")
189
+ return None
178
190
 
179
191
  if response.status_code == 200:
180
192
  response_json = response.json()
181
193
  response_json["requested_at"] = time()
182
194
  return response_json
183
195
  else:
184
- raise InvalidResponseException(
196
+ raise AuthenticationException(
185
197
  f"Invalid response received: {response.json()}"
186
198
  )
187
199
 
@@ -305,7 +317,7 @@ class KKBox:
305
317
  logger.debug(f"Parsing response JSON: {response.json()}")
306
318
  response.raise_for_status()
307
319
  except requests.RequestException as e:
308
- raise NetworkException(f"Network error occurred: {e}")
320
+ return None
309
321
 
310
322
  if response.status_code != 200:
311
323
  raise KKBoxException(f"Failed to search for music: {response.json()}")
yutipy/lastfm.py CHANGED
@@ -95,7 +95,7 @@ class LastFm:
95
95
  response = self.__session.get(query_url, timeout=30)
96
96
  response.raise_for_status()
97
97
  except requests.RequestException as e:
98
- logger.error(f"Failed to fetch user profile: {e}")
98
+ logger.warning(f"Failed to fetch user profile: {e}")
99
99
  return None
100
100
 
101
101
  response_json = response.json()
@@ -110,6 +110,7 @@ class LastFm:
110
110
  album_title=result.get("album", {}).get("#text"),
111
111
  artists=", ".join(separate_artists(result.get("artist", {}).get("#text"))),
112
112
  id=result.get("mbid"),
113
+ timestamp=result.get("date", {}).get("uts"),
113
114
  title=result.get("name"),
114
115
  url=result.get("url"),
115
116
  is_playing=result.get("@attr", {}).get("nowplaying", False),
yutipy/logger.py CHANGED
@@ -2,7 +2,7 @@ import logging
2
2
 
3
3
  # Create a logger for the library
4
4
  logger = logging.getLogger("yutipy")
5
- logger.setLevel(logging.WARNING)
5
+ logger.setLevel(logging.CRITICAL)
6
6
 
7
7
 
8
8
  def enable_logging(level=logging.INFO, handler=None):
@@ -37,6 +37,6 @@ def enable_logging(level=logging.INFO, handler=None):
37
37
 
38
38
  def disable_logging():
39
39
  """Disable logging for the library."""
40
- logger.setLevel(logging.CRITICAL)
40
+ logger.setLevel(logging.NOTSET)
41
41
  for handler in logger.handlers[:]: # Remove all handlers
42
42
  logger.removeHandler(handler)
yutipy/models.py CHANGED
@@ -74,8 +74,11 @@ class UserPlaying(MusicInfo):
74
74
 
75
75
  Attributes
76
76
  ----------
77
+ timetamp : Optional[int]
78
+ Unix Timestamp (in seconds) when playback was started.
77
79
  is_playing : Optional[bool]
78
80
  Whether the music is currently playing or paused.
79
81
  """
80
82
 
83
+ timestamp: Optional[int] = None
81
84
  is_playing: Optional[bool] = None
yutipy/musicyt.py CHANGED
@@ -11,9 +11,9 @@ from yutipy.exceptions import (
11
11
  InvalidValueException,
12
12
  MusicYTException,
13
13
  )
14
+ from yutipy.logger import logger
14
15
  from yutipy.models import MusicInfo
15
16
  from yutipy.utils.helpers import are_strings_similar, is_valid_string
16
- from yutipy.logger import logger
17
17
 
18
18
 
19
19
  class MusicYT:
@@ -87,8 +87,8 @@ class MusicYT:
87
87
  try:
88
88
  results = self.ytmusic.search(query=query, limit=limit)
89
89
  except exceptions.YTMusicServerError as e:
90
- logger.error(f"Something went wrong while searching YTMusic: {e}")
91
- raise MusicYTException(f"Something went wrong while searching YTMusic: {e}")
90
+ logger.warning(f"Something went wrong while searching YTMusic: {e}")
91
+ return None
92
92
 
93
93
  for result in results:
94
94
  if self._is_relevant_result(artist, song, result):
@@ -181,9 +181,15 @@ class MusicYT:
181
181
  The extracted music information.
182
182
  """
183
183
  if result["resultType"] in ["song", "video"]:
184
- return self._get_song(result)
184
+ try:
185
+ return self._get_song(result)
186
+ except InvalidResponseException:
187
+ return None
185
188
  else:
186
- return self._get_album(result)
189
+ try:
190
+ return self._get_album(result)
191
+ except InvalidResponseException:
192
+ return None
187
193
 
188
194
  def _get_song(self, result: dict) -> MusicInfo:
189
195
  """
@@ -200,7 +206,9 @@ class MusicYT:
200
206
  The extracted music information.
201
207
  """
202
208
  title = result.get("title")
203
- artist_names = ", ".join([artist.get("name") for artist in result.get("artists", [])])
209
+ artist_names = ", ".join(
210
+ [artist.get("name") for artist in result.get("artists", [])]
211
+ )
204
212
  video_id = result.get("videoId")
205
213
  song_url = f"https://music.youtube.com/watch?v={video_id}"
206
214
  lyrics_id = self.ytmusic.get_watch_playlist(video_id)
yutipy/spotify.py CHANGED
@@ -14,9 +14,7 @@ from dotenv import load_dotenv
14
14
 
15
15
  from yutipy.exceptions import (
16
16
  AuthenticationException,
17
- InvalidResponseException,
18
17
  InvalidValueException,
19
- NetworkException,
20
18
  SpotifyAuthException,
21
19
  SpotifyException,
22
20
  )
@@ -100,6 +98,13 @@ class Spotify:
100
98
  self.__access_token = token_info.get("access_token")
101
99
  self.__token_expires_in = token_info.get("expires_in")
102
100
  self.__token_requested_at = token_info.get("requested_at")
101
+
102
+ try:
103
+ self.save_access_token(token_info)
104
+ except NotImplementedError:
105
+ logger.warning(
106
+ "`save_access_token` is not implemented, falling back to in-memory storage. Access token will not be saved."
107
+ )
103
108
  else:
104
109
  logger.warning(
105
110
  "`defer_load` is set to `True`. Make sure to call `load_token_after_init()`."
@@ -144,6 +149,13 @@ class Spotify:
144
149
  self.__token_expires_in = token_info.get("expires_in")
145
150
  self.__token_requested_at = token_info.get("requested_at")
146
151
 
152
+ try:
153
+ self.save_access_token(token_info)
154
+ except NotImplementedError:
155
+ logger.warning(
156
+ "`save_access_token` is not implemented, falling back to in-memory storage. Access token will not be saved."
157
+ )
158
+
147
159
  def __authorization_header(self) -> dict:
148
160
  """
149
161
  Generates the authorization header for Spotify API requests.
@@ -184,8 +196,8 @@ class Spotify:
184
196
  logger.debug(f"Authentication response status code: {response.status_code}")
185
197
  response.raise_for_status()
186
198
  except requests.RequestException as e:
187
- logger.error(f"Network error during Spotify authentication: {e}")
188
- raise NetworkException(f"Network error occurred: {e}")
199
+ logger.warning(f"Network error during Spotify authentication: {e}")
200
+ return None
189
201
 
190
202
  if response.status_code == 200:
191
203
  response_json = response.json()
@@ -198,19 +210,27 @@ class Spotify:
198
210
 
199
211
  def __refresh_access_token(self):
200
212
  """Refreshes the token if it has expired."""
201
- if time() - self.__token_requested_at >= self.__token_expires_in:
202
- token_info = self.__get_access_token()
213
+ try:
214
+ if time() - self.__token_requested_at >= self.__token_expires_in:
215
+ token_info = self.__get_access_token()
203
216
 
204
- try:
205
- self.save_access_token(token_info)
206
- except NotImplementedError as e:
207
- logger.warning(e)
217
+ try:
218
+ self.save_access_token(token_info)
219
+ except NotImplementedError as e:
220
+ logger.warning(e)
208
221
 
209
- self.__access_token = token_info.get("access_token")
210
- self.__token_expires_in = token_info.get("expires_in")
211
- self.__token_requested_at = token_info.get("requested_at")
222
+ self.__access_token = token_info.get("access_token")
223
+ self.__token_expires_in = token_info.get("expires_in")
224
+ self.__token_requested_at = token_info.get("requested_at")
212
225
 
213
- logger.info("The access token is still valid, no need to refresh.")
226
+ logger.info("The access token is still valid, no need to refresh.")
227
+ except TypeError:
228
+ logger.debug(
229
+ f"token requested at: {self.__token_requested_at} | token expires in: {self.__token_expires_in}"
230
+ )
231
+ logger.info(
232
+ "Something went wrong while trying to refresh the token. Set logging level to `DEBUG` to see the issue."
233
+ )
214
234
 
215
235
  def save_access_token(self, token_info: dict) -> None:
216
236
  """
@@ -321,7 +341,7 @@ class Spotify:
321
341
  )
322
342
  response.raise_for_status()
323
343
  except requests.RequestException as e:
324
- raise NetworkException(f"Network error occurred: {e}")
344
+ return None
325
345
 
326
346
  if response.status_code != 200:
327
347
  raise SpotifyException(f"Failed to search for music: {response.json()}")
@@ -388,7 +408,7 @@ class Spotify:
388
408
  )
389
409
  response.raise_for_status()
390
410
  except requests.RequestException as e:
391
- raise NetworkException(f"Network error occurred: {e}")
411
+ return None
392
412
 
393
413
  if response.status_code != 200:
394
414
  raise SpotifyException(
@@ -421,7 +441,7 @@ class Spotify:
421
441
  )
422
442
  response.raise_for_status()
423
443
  except requests.RequestException as e:
424
- raise NetworkException(f"Network error occurred: {e}")
444
+ return None
425
445
 
426
446
  if response.status_code != 200:
427
447
  return None
@@ -800,15 +820,15 @@ class SpotifyAuth:
800
820
  logger.debug(f"Authentication response status code: {response.status_code}")
801
821
  response.raise_for_status()
802
822
  except requests.RequestException as e:
803
- logger.error(f"Network error during Spotify authentication: {e}")
804
- raise NetworkException(f"Network error occurred: {e}")
823
+ logger.warning(f"Network error during Spotify authentication: {e}")
824
+ return None
805
825
 
806
826
  if response.status_code == 200:
807
827
  response_json = response.json()
808
828
  response_json["requested_at"] = time()
809
829
  return response_json
810
830
  else:
811
- raise InvalidResponseException(
831
+ raise AuthenticationException(
812
832
  f"Invalid response received: {response.json()}"
813
833
  )
814
834
 
@@ -1036,11 +1056,11 @@ class SpotifyAuth:
1036
1056
  response = self.__session.get(query_url, headers=header, timeout=30)
1037
1057
  response.raise_for_status()
1038
1058
  except requests.RequestException as e:
1039
- logger.error(f"Failed to fetch user profile: {e}")
1059
+ logger.warning(f"Failed to fetch user profile: {e}")
1040
1060
  return None
1041
1061
 
1042
1062
  if response.status_code != 200:
1043
- logger.error(f"Unexpected response: {response.json()}")
1063
+ logger.warning(f"Unexpected response: {response.json()}")
1044
1064
  return None
1045
1065
 
1046
1066
  response_json = response.json()
@@ -1085,16 +1105,16 @@ class SpotifyAuth:
1085
1105
  response = self.__session.get(query_url, headers=header, timeout=30)
1086
1106
  response.raise_for_status()
1087
1107
  except requests.RequestException as e:
1088
- raise NetworkException(f"Network error occurred: {e}")
1108
+ return None
1089
1109
 
1090
1110
  if response.status_code == 204:
1091
1111
  logger.info("Requested user is currently not listening to any music.")
1092
1112
  return None
1093
1113
  if response.status_code != 200:
1094
1114
  try:
1095
- logger.error(f"Unexpected response: {response.json()}")
1115
+ logger.warning(f"Unexpected response: {response.json()}")
1096
1116
  except requests.exceptions.JSONDecodeError:
1097
- logger.error(
1117
+ logger.warning(
1098
1118
  f"Response Code: {response.status_code}, Reason: {response.reason}"
1099
1119
  )
1100
1120
  return None
@@ -1108,6 +1128,8 @@ class SpotifyAuth:
1108
1128
  guess,
1109
1129
  use_translation=False,
1110
1130
  )
1131
+ # Spotify returns timestamp in milliseconds, so convert milliseconds to seconds:
1132
+ timestamp = response_json.get("timestamp") / 1000.0
1111
1133
  return UserPlaying(
1112
1134
  album_art=result.get("album", {}).get("images", [])[0].get("url"),
1113
1135
  album_title=result.get("album", {}).get("name"),
@@ -1124,6 +1146,7 @@ class SpotifyAuth:
1124
1146
  lyrics=None,
1125
1147
  release_date=result.get("album", {}).get("release_date"),
1126
1148
  tempo=None,
1149
+ timestamp=timestamp,
1127
1150
  title=result.get("name"),
1128
1151
  type=result.get("type"),
1129
1152
  upc=result.get("external_ids", {}).get("upc"),
yutipy/yutipy_music.py CHANGED
@@ -22,8 +22,23 @@ class YutipyMusic:
22
22
  Instead of calling each service separately, you can use this class to get the information from all services at once.
23
23
  """
24
24
 
25
- def __init__(self) -> None:
26
- """Initializes the YutipyMusic class."""
25
+ def __init__(
26
+ self,
27
+ custom_kkbox_class = KKBox,
28
+ custom_spotify_class = Spotify,
29
+ ) -> None:
30
+ """
31
+ Initializes the YutipyMusic class.
32
+
33
+ Parameters
34
+ ----------
35
+ custom_kkbox_class : Optional[type], optional
36
+ A custom class inherited from ``KKBox`` to override the default KKBox implementation.
37
+ This class should implement ``load_access_token()`` and ``save_access_token()`` methods. Default is ``KKBox``.
38
+ custom_spotify_class : Optional[type], optional
39
+ A custom class inherited from ``Spotify`` to override the default Spotify implementation.
40
+ This class should implement ``load_access_token()`` and ``save_access_token()`` methods. Default is ``Spotify``.
41
+ """
27
42
  self.music_info = MusicInfos()
28
43
  self.normalize_non_english = True
29
44
  self.album_art_priority = ["deezer", "ytmusic", "itunes"]
@@ -34,8 +49,8 @@ class YutipyMusic:
34
49
  }
35
50
 
36
51
  try:
37
- self.services["kkbox"] = KKBox()
38
- except (KKBoxException) as e:
52
+ self.services["kkbox"] = custom_kkbox_class()
53
+ except KKBoxException as e:
39
54
  logger.warning(
40
55
  f"{self.__class__.__name__}: Skipping KKBox due to KKBoxException: {e}"
41
56
  )
@@ -44,8 +59,8 @@ class YutipyMusic:
44
59
  self.album_art_priority.insert(idx, "kkbox")
45
60
 
46
61
  try:
47
- self.services["spotify"] = Spotify()
48
- except (SpotifyException) as e:
62
+ self.services["spotify"] = custom_spotify_class()
63
+ except SpotifyException as e:
49
64
  logger.warning(
50
65
  f"{self.__class__.__name__}: Skipping Spotify due to SpotifyException: {e}"
51
66
  )
@@ -114,7 +129,7 @@ class YutipyMusic:
114
129
  result = future.result()
115
130
  self._combine_results(result, service_name)
116
131
  except Exception as e:
117
- logger.error(
132
+ logger.warning(
118
133
  f"Error occurred while searching with {service_name}: {e}"
119
134
  )
120
135
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yutipy
3
- Version: 2.2.2
3
+ Version: 2.2.4
4
4
  Summary: A simple package for retrieving music information from various music platforms APIs.
5
5
  Author: Cheap Nightbot
6
6
  Author-email: Cheap Nightbot <hi@cheapnightbot.slmail.me>
@@ -0,0 +1,22 @@
1
+ yutipy/__init__.py,sha256=Zrw3cr_6khXp1IgQdZxGcUM9A64GYgPs-6rlqSukW5Q,294
2
+ yutipy/deezer.py,sha256=xI7ZDoPHES64_uRN4aYA-kj56V4tFU8xYkZYPXidl_I,11266
3
+ yutipy/exceptions.py,sha256=zz0XyyZr5xRcmRyw3hdTGaVRcwRn_RSYZdmwmuO0sEM,1379
4
+ yutipy/itunes.py,sha256=3YBLoWPhIx6ODE2G-msRppCHo0DNDGZADj-XvL_f5H0,7867
5
+ yutipy/kkbox.py,sha256=ZOIW8rQuiYEWmsXW3Dw9Q5mw71Jh_tMRAULvEgAuDew,19310
6
+ yutipy/lastfm.py,sha256=smbft17Q_wdYXH0Wb1-bfgWilO6wCwcsN3D5lCis4yI,4361
7
+ yutipy/logger.py,sha256=GyLBlfQZ6pLNJ5MbyQSvcD_PkxmFdX41DPq5aeG1z68,1316
8
+ yutipy/models.py,sha256=45M-bNHusaAan_Ta_E9DyvsWujsT-ivbJqIfy2-i3R8,2343
9
+ yutipy/musicyt.py,sha256=WKR4J4ru1uqNa7ORSZKlet1FxXQlHzlXTg9CIUqnsoc,9462
10
+ yutipy/spotify.py,sha256=NiBjaK2SUCyRhGGDsP0mGguFZOLW6DkUVoUghIH_0Ho,44395
11
+ yutipy/yutipy_music.py,sha256=MNNh2WT-7GTAykAabLF6p4-0uXiIIbuogswmb-_QqtQ,7272
12
+ yutipy/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ yutipy/cli/config.py,sha256=e5RIq6RxVxxzx30nKVMa06gwyQ258s7U0WA1xvJuR_0,4543
14
+ yutipy/cli/search.py,sha256=8SQw0bjRzRqAg-FuVz9aWjB2KBZqmCf38SyKAQ3rx5E,3025
15
+ yutipy/utils/__init__.py,sha256=AZaqvs6AJwnqwJuodbGnHu702WSUqc8plVC16SppOcU,239
16
+ yutipy/utils/helpers.py,sha256=W3g9iqoSygcFFCKCp2sk0NQrZOEG26wI2XuNi9pgAXE,5207
17
+ yutipy-2.2.4.dist-info/licenses/LICENSE,sha256=_89JsS2QnBG8tAb5-VWbJDj_uJ002zPJAYBJJdh3DPY,1071
18
+ yutipy-2.2.4.dist-info/METADATA,sha256=T693it2xLgmx13Cx1N5LEZ_7fdTaZPa3Oqj83gHoJNw,6522
19
+ yutipy-2.2.4.dist-info/WHEEL,sha256=ck4Vq1_RXyvS4Jt6SI0Vz6fyVs4GWg7AINwpsaGEgPE,91
20
+ yutipy-2.2.4.dist-info/entry_points.txt,sha256=BrgmanaPjQqKQ3Ip76JLcsPgGANtrBSURf5CNIxl1HA,106
21
+ yutipy-2.2.4.dist-info/top_level.txt,sha256=t2A5V2_mUcfnHkbCy6tAQlb3909jDYU5GQgXtA4756I,7
22
+ yutipy-2.2.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (79.0.1)
2
+ Generator: setuptools (80.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,22 +0,0 @@
1
- yutipy/__init__.py,sha256=Zrw3cr_6khXp1IgQdZxGcUM9A64GYgPs-6rlqSukW5Q,294
2
- yutipy/deezer.py,sha256=PTTTfeORh1HZ_ta7_Uu4YARouSknUnAxO9AQJPFm4v0,11402
3
- yutipy/exceptions.py,sha256=oMuhNfDJ2AFsM_fJn6sayxMqIJRY_ihHRmL0U2IK6qQ,1501
4
- yutipy/itunes.py,sha256=fV7KLsXWvfM_97KwVwn_KfnWM7j0cVGE7RytvnDGlZM,7929
5
- yutipy/kkbox.py,sha256=MuYpR_UTZQxeitn2rc0UUgiMVikIXcVWmns3eSVjd_g,18847
6
- yutipy/lastfm.py,sha256=0adVGigS8Kqnu52k-ry5eqHR6koktgKBhCNI1riUMfk,4302
7
- yutipy/logger.py,sha256=69mUj7XiNbK61vo4k6BDZlwP8RDNTMVxoZsPd9DhQfI,1317
8
- yutipy/models.py,sha256=_92e54uXXCw53oWZiNLBBai6C0InOZMJL7r8GJ5smbM,2215
9
- yutipy/musicyt.py,sha256=6Vz8bI8hDNFoDKRh6GK90dGMRbn_d5d6eGPsaYogb_Y,9315
10
- yutipy/spotify.py,sha256=mHa5C6LTzfWOb_6LJhGm_HX7yvWcY0q7acUfU_ofw4A,43508
11
- yutipy/yutipy_music.py,sha256=cHJ95HxGILweVrnEacj8tTlU0NPxMpuDVMpngdX0mZQ,6558
12
- yutipy/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- yutipy/cli/config.py,sha256=e5RIq6RxVxxzx30nKVMa06gwyQ258s7U0WA1xvJuR_0,4543
14
- yutipy/cli/search.py,sha256=8SQw0bjRzRqAg-FuVz9aWjB2KBZqmCf38SyKAQ3rx5E,3025
15
- yutipy/utils/__init__.py,sha256=AZaqvs6AJwnqwJuodbGnHu702WSUqc8plVC16SppOcU,239
16
- yutipy/utils/helpers.py,sha256=W3g9iqoSygcFFCKCp2sk0NQrZOEG26wI2XuNi9pgAXE,5207
17
- yutipy-2.2.2.dist-info/licenses/LICENSE,sha256=_89JsS2QnBG8tAb5-VWbJDj_uJ002zPJAYBJJdh3DPY,1071
18
- yutipy-2.2.2.dist-info/METADATA,sha256=XWSYmaoMjUgwnSdXzRbRM5Awn4IHT5-Gfgecm1lxvDE,6522
19
- yutipy-2.2.2.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
20
- yutipy-2.2.2.dist-info/entry_points.txt,sha256=BrgmanaPjQqKQ3Ip76JLcsPgGANtrBSURf5CNIxl1HA,106
21
- yutipy-2.2.2.dist-info/top_level.txt,sha256=t2A5V2_mUcfnHkbCy6tAQlb3909jDYU5GQgXtA4756I,7
22
- yutipy-2.2.2.dist-info/RECORD,,