yutipy 2.2.4__py3-none-any.whl → 2.2.6__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/lastfm.py CHANGED
@@ -2,6 +2,7 @@ __all__ = ["LastFm", "LastFmException"]
2
2
 
3
3
  import os
4
4
  from dataclasses import asdict
5
+ from time import time
5
6
  from pprint import pprint
6
7
  from typing import Optional
7
8
 
@@ -73,6 +74,46 @@ class LastFm:
73
74
  """Checks if the session is closed."""
74
75
  return self._is_session_closed
75
76
 
77
+ def get_user_profile(self, username: str):
78
+ """
79
+ Fetches the user profile information for the provided username.
80
+
81
+ Returns
82
+ -------
83
+ dict
84
+ A dictionary containing the user's profile information or error is username does not exist.
85
+ """
86
+ query = (
87
+ f"?method=user.getinfo&user={username}&api_key={self.api_key}&format=json"
88
+ )
89
+ query_url = self.__api_url + query
90
+
91
+ try:
92
+ response = self.__session.get(query_url, timeout=30)
93
+ except requests.RequestException as e:
94
+ logger.warning(f"Failed to fetch user profile: {e}")
95
+ return None
96
+
97
+ response_json = response.json()
98
+ result = response_json.get("user")
99
+ error = response_json.get("message")
100
+ if result:
101
+ images = [
102
+ {"size": image.get("size"), "url": image.get("#text")}
103
+ for image in result.get("image", [])
104
+ ]
105
+ return {
106
+ "name": result.get("realname"),
107
+ "username": result.get("name"),
108
+ "type": result.get("type"),
109
+ "url": result.get("url"),
110
+ "images": images,
111
+ }
112
+ elif error:
113
+ return {"error": error}
114
+ else:
115
+ return None
116
+
76
117
  def get_currently_playing(self, username: str) -> Optional[UserPlaying]:
77
118
  """
78
119
  Fetches information about the currently playing or most recent track for a user.
@@ -100,29 +141,34 @@ class LastFm:
100
141
 
101
142
  response_json = response.json()
102
143
  result = response_json.get("recenttracks", {}).get("track", [])[0]
103
- album_art = [
104
- img.get("#text")
105
- for img in result.get("image", [])
106
- if img.get("size") == "extralarge"
107
- ]
108
- return UserPlaying(
109
- album_art="".join(album_art),
110
- album_title=result.get("album", {}).get("#text"),
111
- artists=", ".join(separate_artists(result.get("artist", {}).get("#text"))),
112
- id=result.get("mbid"),
113
- timestamp=result.get("date", {}).get("uts"),
114
- title=result.get("name"),
115
- url=result.get("url"),
116
- is_playing=result.get("@attr", {}).get("nowplaying", False),
117
- )
144
+ is_playing = result.get("@attr", {}).get("nowplaying", False)
145
+ if result and is_playing:
146
+ album_art = [
147
+ img.get("#text")
148
+ for img in result.get("image", [])
149
+ if img.get("size") == "extralarge"
150
+ ]
151
+ return UserPlaying(
152
+ album_art="".join(album_art),
153
+ album_title=result.get("album", {}).get("#text"),
154
+ artists=", ".join(
155
+ separate_artists(result.get("artist", {}).get("#text"))
156
+ ),
157
+ id=result.get("mbid"),
158
+ timestamp=result.get("date", {}).get("uts") or time(),
159
+ title=result.get("name"),
160
+ url=result.get("url"),
161
+ is_playing=is_playing,
162
+ )
163
+ return None
118
164
 
119
165
 
120
166
  if __name__ == "__main__":
121
167
  with LastFm() as lastfm:
122
168
  username = input("Enter Lasfm Username: ").strip()
123
- result = lastfm.get_currently_playing(username=username, limit=5)
169
+ result = lastfm.get_user_profile(username=username)
124
170
 
125
171
  if result:
126
- pprint(asdict(result))
172
+ pprint(result)
127
173
  else:
128
174
  print("No result was found. Make sure the username is correct!")
yutipy/spotify.py CHANGED
@@ -196,8 +196,9 @@ class Spotify:
196
196
  logger.debug(f"Authentication response status code: {response.status_code}")
197
197
  response.raise_for_status()
198
198
  except requests.RequestException as e:
199
- logger.warning(f"Network error during Spotify authentication: {e}")
200
- return None
199
+ raise requests.RequestException(
200
+ f"Network error during Spotify authentication: {e}"
201
+ )
201
202
 
202
203
  if response.status_code == 200:
203
204
  response_json = response.json()
@@ -210,6 +211,9 @@ class Spotify:
210
211
 
211
212
  def __refresh_access_token(self):
212
213
  """Refreshes the token if it has expired."""
214
+ if not self.__access_token:
215
+ raise SpotifyAuthException("No access token was found.")
216
+
213
217
  try:
214
218
  if time() - self.__token_requested_at >= self.__token_expires_in:
215
219
  token_info = self.__get_access_token()
@@ -224,12 +228,16 @@ class Spotify:
224
228
  self.__token_requested_at = token_info.get("requested_at")
225
229
 
226
230
  logger.info("The access token is still valid, no need to refresh.")
231
+ except (AuthenticationException, requests.RequestException) as e:
232
+ logger.warning(
233
+ f"Failed to refresh the access toke due to following error: {e}"
234
+ )
227
235
  except TypeError:
228
236
  logger.debug(
229
237
  f"token requested at: {self.__token_requested_at} | token expires in: {self.__token_expires_in}"
230
238
  )
231
239
  logger.info(
232
- "Something went wrong while trying to refresh the token. Set logging level to `DEBUG` to see the issue."
240
+ "Something went wrong while trying to refresh the access token. Set logging level to `DEBUG` to see the issue."
233
241
  )
234
242
 
235
243
  def save_access_token(self, token_info: dict) -> None:
@@ -341,6 +349,7 @@ class Spotify:
341
349
  )
342
350
  response.raise_for_status()
343
351
  except requests.RequestException as e:
352
+ logger.warning(f"Network error during Spotify search: {e}")
344
353
  return None
345
354
 
346
355
  if response.status_code != 200:
@@ -408,6 +417,7 @@ class Spotify:
408
417
  )
409
418
  response.raise_for_status()
410
419
  except requests.RequestException as e:
420
+ logger.warning(f"Network error during Spotify search (advanced): {e}")
411
421
  return None
412
422
 
413
423
  if response.status_code != 200:
@@ -441,6 +451,7 @@ class Spotify:
441
451
  )
442
452
  response.raise_for_status()
443
453
  except requests.RequestException as e:
454
+ logger.warning(f"Network error during Spotify get artist ids: {e}")
444
455
  return None
445
456
 
446
457
  if response.status_code != 200:
@@ -820,8 +831,9 @@ class SpotifyAuth:
820
831
  logger.debug(f"Authentication response status code: {response.status_code}")
821
832
  response.raise_for_status()
822
833
  except requests.RequestException as e:
823
- logger.warning(f"Network error during Spotify authentication: {e}")
824
- return None
834
+ raise requests.RequestException(
835
+ f"Network error during Spotify authentication: {e}"
836
+ )
825
837
 
826
838
  if response.status_code == 200:
827
839
  response_json = response.json()
@@ -837,20 +849,30 @@ class SpotifyAuth:
837
849
  if not self.__access_token:
838
850
  raise SpotifyAuthException("No access token was found.")
839
851
 
840
- if time() - self.__token_requested_at >= self.__token_expires_in:
841
- token_info = self.__get_access_token(refresh_token=self.__refresh_token)
852
+ try:
853
+ if time() - self.__token_requested_at >= self.__token_expires_in:
854
+ token_info = self.__get_access_token(refresh_token=self.__refresh_token)
842
855
 
843
- try:
844
- self.save_access_token(token_info)
845
- except NotImplementedError as e:
846
- logger.warning(e)
856
+ try:
857
+ self.save_access_token(token_info)
858
+ except NotImplementedError as e:
859
+ logger.warning(e)
847
860
 
848
- self.__access_token = token_info.get("access_token")
849
- self.__refresh_token = token_info.get("refresh_token")
850
- self.__token_expires_in = token_info.get("expires_in")
851
- self.__token_requested_at = token_info.get("requested_at")
861
+ self.__access_token = token_info.get("access_token")
862
+ self.__refresh_token = token_info.get("refresh_token")
863
+ self.__token_expires_in = token_info.get("expires_in")
864
+ self.__token_requested_at = token_info.get("requested_at")
852
865
 
853
- logger.info("The access token is still valid, no need to refresh.")
866
+ logger.info("The access token is still valid, no need to refresh.")
867
+ except (AuthenticationException, requests.RequestException) as e:
868
+ logger.warning(f"Failed to refresh the access toke due to following error: {e}")
869
+ except TypeError:
870
+ logger.debug(
871
+ f"token requested at: {self.__token_requested_at} | token expires in: {self.__token_expires_in}"
872
+ )
873
+ logger.warning(
874
+ "Something went wrong while trying to refresh the access token. Set logging level to `DEBUG` to see the issue."
875
+ )
854
876
 
855
877
  @staticmethod
856
878
  def generate_state() -> str:
@@ -1028,7 +1050,7 @@ class SpotifyAuth:
1028
1050
  except NotImplementedError as e:
1029
1051
  logger.warning(e)
1030
1052
 
1031
- def get_user_profile(self):
1053
+ def get_user_profile(self) -> Optional[dict]:
1032
1054
  """
1033
1055
  Fetches the user's display name and profile images.
1034
1056
 
@@ -1063,10 +1085,11 @@ class SpotifyAuth:
1063
1085
  logger.warning(f"Unexpected response: {response.json()}")
1064
1086
  return None
1065
1087
 
1066
- response_json = response.json()
1088
+ result = response.json()
1067
1089
  return {
1068
- "display_name": response_json.get("display_name"),
1069
- "images": response_json.get("images", []),
1090
+ "display_name": result.get("display_name"),
1091
+ "images": result.get("images", []),
1092
+ "url": result.get("external_urls", {}).get("spotify")
1070
1093
  }
1071
1094
 
1072
1095
  def get_currently_playing(self) -> Optional[UserPlaying]:
@@ -1105,6 +1128,7 @@ class SpotifyAuth:
1105
1128
  response = self.__session.get(query_url, headers=header, timeout=30)
1106
1129
  response.raise_for_status()
1107
1130
  except requests.RequestException as e:
1131
+ logger.warning(f"Error while getting Spotify user activity: {e}")
1108
1132
  return None
1109
1133
 
1110
1134
  if response.status_code == 204:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yutipy
3
- Version: 2.2.4
3
+ Version: 2.2.6
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>
@@ -3,20 +3,20 @@ yutipy/deezer.py,sha256=xI7ZDoPHES64_uRN4aYA-kj56V4tFU8xYkZYPXidl_I,11266
3
3
  yutipy/exceptions.py,sha256=zz0XyyZr5xRcmRyw3hdTGaVRcwRn_RSYZdmwmuO0sEM,1379
4
4
  yutipy/itunes.py,sha256=3YBLoWPhIx6ODE2G-msRppCHo0DNDGZADj-XvL_f5H0,7867
5
5
  yutipy/kkbox.py,sha256=ZOIW8rQuiYEWmsXW3Dw9Q5mw71Jh_tMRAULvEgAuDew,19310
6
- yutipy/lastfm.py,sha256=smbft17Q_wdYXH0Wb1-bfgWilO6wCwcsN3D5lCis4yI,4361
6
+ yutipy/lastfm.py,sha256=MFQFi7w3-KSsV6MVFDSSwkbINlOEDazi2h_rib76wPw,5876
7
7
  yutipy/logger.py,sha256=GyLBlfQZ6pLNJ5MbyQSvcD_PkxmFdX41DPq5aeG1z68,1316
8
8
  yutipy/models.py,sha256=45M-bNHusaAan_Ta_E9DyvsWujsT-ivbJqIfy2-i3R8,2343
9
9
  yutipy/musicyt.py,sha256=WKR4J4ru1uqNa7ORSZKlet1FxXQlHzlXTg9CIUqnsoc,9462
10
- yutipy/spotify.py,sha256=NiBjaK2SUCyRhGGDsP0mGguFZOLW6DkUVoUghIH_0Ho,44395
10
+ yutipy/spotify.py,sha256=aKOntF5uBh_X8A779sDlRUAqihJid5NCSmEGOxTIQF0,45708
11
11
  yutipy/yutipy_music.py,sha256=MNNh2WT-7GTAykAabLF6p4-0uXiIIbuogswmb-_QqtQ,7272
12
12
  yutipy/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  yutipy/cli/config.py,sha256=e5RIq6RxVxxzx30nKVMa06gwyQ258s7U0WA1xvJuR_0,4543
14
14
  yutipy/cli/search.py,sha256=8SQw0bjRzRqAg-FuVz9aWjB2KBZqmCf38SyKAQ3rx5E,3025
15
15
  yutipy/utils/__init__.py,sha256=AZaqvs6AJwnqwJuodbGnHu702WSUqc8plVC16SppOcU,239
16
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,,
17
+ yutipy-2.2.6.dist-info/licenses/LICENSE,sha256=_89JsS2QnBG8tAb5-VWbJDj_uJ002zPJAYBJJdh3DPY,1071
18
+ yutipy-2.2.6.dist-info/METADATA,sha256=K2BV7ZPAsD1sxXGFCd6FELl8Bqev0-b5zBzwtpGkTw4,6522
19
+ yutipy-2.2.6.dist-info/WHEEL,sha256=ooBFpIzZCPdw3uqIQsOo4qqbA4ZRPxHnOH7peeONza0,91
20
+ yutipy-2.2.6.dist-info/entry_points.txt,sha256=BrgmanaPjQqKQ3Ip76JLcsPgGANtrBSURf5CNIxl1HA,106
21
+ yutipy-2.2.6.dist-info/top_level.txt,sha256=t2A5V2_mUcfnHkbCy6tAQlb3909jDYU5GQgXtA4756I,7
22
+ yutipy-2.2.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.0.0)
2
+ Generator: setuptools (80.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5