yutipy 2.3.0__tar.gz → 2.3.1__tar.gz

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.

Files changed (64) hide show
  1. {yutipy-2.3.0 → yutipy-2.3.1}/PKG-INFO +1 -1
  2. {yutipy-2.3.0 → yutipy-2.3.1}/docs/api_reference.rst +3 -3
  3. {yutipy-2.3.0 → yutipy-2.3.1}/docs/conf.py +1 -0
  4. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/base_clients.py +0 -5
  5. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/deezer.py +15 -8
  6. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/itunes.py +22 -10
  7. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/kkbox.py +16 -10
  8. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/lastfm.py +4 -8
  9. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/lrclib.py +8 -10
  10. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/musicyt.py +9 -3
  11. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/spotify.py +27 -18
  12. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/yutipy_music.py +21 -11
  13. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy.egg-info/PKG-INFO +1 -1
  14. {yutipy-2.3.0 → yutipy-2.3.1}/.gitattributes +0 -0
  15. {yutipy-2.3.0 → yutipy-2.3.1}/.github/FUNDING.yml +0 -0
  16. {yutipy-2.3.0 → yutipy-2.3.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  17. {yutipy-2.3.0 → yutipy-2.3.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  18. {yutipy-2.3.0 → yutipy-2.3.1}/.github/dependabot.yml +0 -0
  19. {yutipy-2.3.0 → yutipy-2.3.1}/.github/workflows/pytest-unit-testing.yml +0 -0
  20. {yutipy-2.3.0 → yutipy-2.3.1}/.github/workflows/release.yml +0 -0
  21. {yutipy-2.3.0 → yutipy-2.3.1}/.gitignore +0 -0
  22. {yutipy-2.3.0 → yutipy-2.3.1}/.readthedocs.yaml +0 -0
  23. {yutipy-2.3.0 → yutipy-2.3.1}/LICENSE +0 -0
  24. {yutipy-2.3.0 → yutipy-2.3.1}/MANIFEST.in +0 -0
  25. {yutipy-2.3.0 → yutipy-2.3.1}/README.md +0 -0
  26. {yutipy-2.3.0 → yutipy-2.3.1}/docs/Makefile +0 -0
  27. {yutipy-2.3.0 → yutipy-2.3.1}/docs/_static/yutipy_header.png +0 -0
  28. {yutipy-2.3.0 → yutipy-2.3.1}/docs/_static/yutipy_logo.png +0 -0
  29. {yutipy-2.3.0 → yutipy-2.3.1}/docs/available_platforms.rst +0 -0
  30. {yutipy-2.3.0 → yutipy-2.3.1}/docs/cli.rst +0 -0
  31. {yutipy-2.3.0 → yutipy-2.3.1}/docs/faq.rst +0 -0
  32. {yutipy-2.3.0 → yutipy-2.3.1}/docs/index.rst +0 -0
  33. {yutipy-2.3.0 → yutipy-2.3.1}/docs/installation.rst +0 -0
  34. {yutipy-2.3.0 → yutipy-2.3.1}/docs/make.bat +0 -0
  35. {yutipy-2.3.0 → yutipy-2.3.1}/docs/requirements.txt +0 -0
  36. {yutipy-2.3.0 → yutipy-2.3.1}/docs/usage_examples.rst +0 -0
  37. {yutipy-2.3.0 → yutipy-2.3.1}/pyproject.toml +0 -0
  38. {yutipy-2.3.0 → yutipy-2.3.1}/requirements-dev.txt +0 -0
  39. {yutipy-2.3.0 → yutipy-2.3.1}/requirements.txt +0 -0
  40. {yutipy-2.3.0 → yutipy-2.3.1}/setup.cfg +0 -0
  41. {yutipy-2.3.0 → yutipy-2.3.1}/tests/__init__.py +0 -0
  42. {yutipy-2.3.0 → yutipy-2.3.1}/tests/test_deezer.py +0 -0
  43. {yutipy-2.3.0 → yutipy-2.3.1}/tests/test_itunes.py +0 -0
  44. {yutipy-2.3.0 → yutipy-2.3.1}/tests/test_kkbox.py +0 -0
  45. {yutipy-2.3.0 → yutipy-2.3.1}/tests/test_lastfm.py +0 -0
  46. {yutipy-2.3.0 → yutipy-2.3.1}/tests/test_lrclib.py +0 -0
  47. {yutipy-2.3.0 → yutipy-2.3.1}/tests/test_models.py +0 -0
  48. {yutipy-2.3.0 → yutipy-2.3.1}/tests/test_musicyt.py +0 -0
  49. {yutipy-2.3.0 → yutipy-2.3.1}/tests/test_spotify.py +0 -0
  50. {yutipy-2.3.0 → yutipy-2.3.1}/tests/test_utils.py +0 -0
  51. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/__init__.py +0 -0
  52. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/cli/__init__.py +0 -0
  53. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/cli/config.py +0 -0
  54. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/cli/search.py +0 -0
  55. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/exceptions.py +0 -0
  56. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/logger.py +0 -0
  57. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/models.py +0 -0
  58. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/utils/__init__.py +0 -0
  59. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy/utils/helpers.py +0 -0
  60. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy.egg-info/SOURCES.txt +0 -0
  61. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy.egg-info/dependency_links.txt +0 -0
  62. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy.egg-info/entry_points.txt +0 -0
  63. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy.egg-info/requires.txt +0 -0
  64. {yutipy-2.3.0 → yutipy-2.3.1}/yutipy.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yutipy
3
- Version: 2.3.0
3
+ Version: 2.3.1
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,7 +30,7 @@ KKBox
30
30
  :members:
31
31
  :inherited-members:
32
32
  :noindex:
33
- :exclude-members: is_session_closed
33
+ :exclude-members: is_session_closed, SERVICE_NAME, ACCESS_TOKEN_URL
34
34
 
35
35
  Lastfm
36
36
  ------
@@ -57,13 +57,13 @@ Spotify
57
57
  :members:
58
58
  :inherited-members:
59
59
  :noindex:
60
- :exclude-members: is_session_closed
60
+ :exclude-members: is_session_closed, SERVICE_NAME, ACCESS_TOKEN_URL
61
61
 
62
62
  .. autoclass:: yutipy.spotify.SpotifyAuth
63
63
  :members:
64
64
  :inherited-members:
65
65
  :noindex:
66
- :exclude-members: is_session_closed
66
+ :exclude-members: is_session_closed, SERVICE_NAME, ACCESS_TOKEN_URL, USER_AUTH_URL
67
67
 
68
68
  YouTube Music
69
69
  -------------
@@ -35,6 +35,7 @@ autodoc_default_options = {
35
35
  "inherited-members": True,
36
36
  "show-inheritance": True,
37
37
  }
38
+ autoclass_content = "both"
38
39
 
39
40
  # sphinx-copybutton optional configurations
40
41
  copybutton_prompt_text = r">>> |\.\.\. "
@@ -409,11 +409,6 @@ class BaseAuthClient:
409
409
 
410
410
  def _refresh_access_token(self):
411
411
  """Refreshes the token if it has expired."""
412
- try:
413
- self.load_token_after_init()
414
- except NotImplementedError as e:
415
- logger.warning(e)
416
-
417
412
  if not self._access_token or not self._refresh_token:
418
413
  logger.warning(
419
414
  "No access token or refresh token found. You must authenticate to obtain a new token."
@@ -15,11 +15,17 @@ from yutipy.lrclib import LrcLib
15
15
  class Deezer:
16
16
  """A class to interact with the Deezer API."""
17
17
 
18
- def __init__(self) -> None:
19
- """Initializes the Deezer class and sets up the session."""
18
+ def __init__(self, fetch_lyrics: bool = True) -> None:
19
+ """
20
+ Parameters
21
+ ----------
22
+ fetch_lyrics : bool, optional
23
+ Whether to fetch lyrics (using `LRCLIB <https://lrclib.net>`__) if the music platform does not provide lyrics (default is True).
24
+ """
20
25
  self.api_url = "https://api.deezer.com"
21
26
  self._is_session_closed = False
22
27
  self.normalize_non_english = True
28
+ self.fetch_lyrics = fetch_lyrics
23
29
  self.__session = requests.Session()
24
30
  self._translation_session = requests.Session()
25
31
 
@@ -304,12 +310,13 @@ class Deezer:
304
310
  music_info.release_date = album_info.get("release_date")
305
311
  music_info.genre = album_info.get("genre")
306
312
 
307
- with LrcLib() as lrc_lib:
308
- lyrics = lrc_lib.get_lyrics(
309
- artist=music_info.artists, song=music_info.title
310
- )
311
- if lyrics:
312
- music_info.lyrics = lyrics.get("plainLyrics")
313
+ if self.fetch_lyrics:
314
+ with LrcLib() as lrc_lib:
315
+ lyrics = lrc_lib.get_lyrics(
316
+ artist=music_info.artists, song=music_info.title
317
+ )
318
+ if lyrics:
319
+ music_info.lyrics = lyrics.get("plainLyrics")
313
320
 
314
321
  return music_info
315
322
 
@@ -8,19 +8,30 @@ import requests
8
8
 
9
9
  from yutipy.exceptions import InvalidValueException, ItunesException
10
10
  from yutipy.logger import logger
11
- from yutipy.models import MusicInfo
12
- from yutipy.utils.helpers import are_strings_similar, guess_album_type, is_valid_string, separate_artists
13
11
  from yutipy.lrclib import LrcLib
12
+ from yutipy.models import MusicInfo
13
+ from yutipy.utils.helpers import (
14
+ are_strings_similar,
15
+ guess_album_type,
16
+ is_valid_string,
17
+ separate_artists,
18
+ )
14
19
 
15
20
 
16
21
  class Itunes:
17
22
  """A class to interact with the iTunes API."""
18
23
 
19
- def __init__(self) -> None:
20
- """Initializes the iTunes class and sets up the session."""
24
+ def __init__(self, fetch_lyrics: bool = True) -> None:
25
+ """
26
+ Parameters
27
+ ----------
28
+ fetch_lyrics : bool, optional
29
+ Whether to fetch lyrics (using `LRCLIB <https://lrclib.net>`__) if the music platform does not provide lyrics (default is True).
30
+ """
21
31
  self.api_url = "https://itunes.apple.com"
22
32
  self.normalize_non_english = True
23
33
  self._is_session_closed = False
34
+ self.fetch_lyrics = fetch_lyrics
24
35
  self.__session = requests.Session()
25
36
  self.__translation_session = requests.Session()
26
37
 
@@ -169,12 +180,13 @@ class Itunes:
169
180
  url=result.get("trackViewUrl", result["collectionViewUrl"]),
170
181
  )
171
182
 
172
- with LrcLib() as lrc_lib:
173
- lyrics = lrc_lib.get_lyrics(
174
- artist=music_info.artists, song=music_info.title
175
- )
176
- if lyrics:
177
- music_info.lyrics = lyrics.get("plainLyrics")
183
+ if self.fetch_lyrics:
184
+ with LrcLib() as lrc_lib:
185
+ lyrics = lrc_lib.get_lyrics(
186
+ artist=music_info.artists, song=music_info.title
187
+ )
188
+ if lyrics:
189
+ music_info.lyrics = lyrics.get("plainLyrics")
178
190
 
179
191
  return music_info
180
192
  return None
@@ -11,9 +11,9 @@ from dotenv import load_dotenv
11
11
  from yutipy.base_clients import BaseClient
12
12
  from yutipy.exceptions import InvalidValueException, KKBoxException
13
13
  from yutipy.logger import logger
14
+ from yutipy.lrclib import LrcLib
14
15
  from yutipy.models import MusicInfo
15
16
  from yutipy.utils.helpers import are_strings_similar, is_valid_string
16
- from yutipy.lrclib import LrcLib
17
17
 
18
18
  load_dotenv()
19
19
 
@@ -30,11 +30,13 @@ class KKBox(BaseClient):
30
30
  """
31
31
 
32
32
  def __init__(
33
- self, client_id: str = None, client_secret: str = None, defer_load: bool = False
33
+ self,
34
+ client_id: str = None,
35
+ client_secret: str = None,
36
+ defer_load: bool = False,
37
+ fetch_lyrics: bool = True,
34
38
  ) -> None:
35
39
  """
36
- Initializes the KKBox class and sets up the session.
37
-
38
40
  Parameters
39
41
  ----------
40
42
  client_id : str, optional
@@ -43,9 +45,12 @@ class KKBox(BaseClient):
43
45
  The Client secret for the KKBOX Open API. Defaults to ``KKBOX_CLIENT_SECRET`` from .env file.
44
46
  defer_load : bool, optional
45
47
  Whether to defer loading the access token during initialization. Default is ``False``.
48
+ fetch_lyrics : bool, optional
49
+ Whether to fetch lyrics (using `LRCLIB <https://lrclib.net>`__) if the music platform does not provide lyrics (default is True).
46
50
  """
47
51
  self.client_id = client_id or KKBOX_CLIENT_ID
48
52
  self.client_secret = client_secret or KKBOX_CLIENT_SECRET
53
+ self.fetch_lyrics = fetch_lyrics
49
54
 
50
55
  if not self.client_id:
51
56
  raise KKBoxException(
@@ -274,12 +279,13 @@ class KKBox(BaseClient):
274
279
  url=track.get("url"),
275
280
  )
276
281
 
277
- with LrcLib() as lrc_lib:
278
- lyrics = lrc_lib.get_lyrics(
279
- artist=music_info.artists, song=music_info.title
280
- )
281
- if lyrics:
282
- music_info.lyrics = lyrics.get("plainLyrics")
282
+ if self.fetch_lyrics:
283
+ with LrcLib() as lrc_lib:
284
+ lyrics = lrc_lib.get_lyrics(
285
+ artist=music_info.artists, song=music_info.title
286
+ )
287
+ if lyrics:
288
+ music_info.lyrics = lyrics.get("plainLyrics")
283
289
  return music_info
284
290
  return None
285
291
 
@@ -1,8 +1,8 @@
1
1
  __all__ = ["LastFm", "LastFmException"]
2
2
 
3
3
  import os
4
- from time import time
5
4
  from pprint import pprint
5
+ from time import time
6
6
  from typing import Optional
7
7
 
8
8
  import requests
@@ -28,12 +28,6 @@ class LastFm:
28
28
 
29
29
  def __init__(self, api_key: str = None):
30
30
  """
31
- Initializes the LastFm class.
32
-
33
- Args:
34
- lastfm_api_key (str, optional): The Last.fm API key. If not provided,
35
- it will be fetched from the environment variable `LASTFM_API_KEY`.
36
-
37
31
  Parameters
38
32
  ----------
39
33
  lastfm_api_key : str, optional
@@ -141,7 +135,9 @@ class LastFm:
141
135
  response_json = response.json()
142
136
  result = response_json.get("recenttracks", {}).get("track", [])[0]
143
137
  is_playing = result.get("@attr", {}).get("nowplaying", False)
144
- is_playing = True if isinstance(is_playing, str) and is_playing == "true" else False
138
+ is_playing = (
139
+ True if isinstance(is_playing, str) and is_playing == "true" else False
140
+ )
145
141
  if result and is_playing:
146
142
  album_art = [
147
143
  img.get("#text")
@@ -21,8 +21,7 @@ class LrcLib:
21
21
  app_version: str = None,
22
22
  app_url: str = "https://github.com/CheapNightbot/yutipy",
23
23
  ) -> None:
24
- """Initializes the LrcLib with the API URL and application details.
25
-
24
+ """
26
25
  Parameters
27
26
  ----------
28
27
  app_name : str
@@ -135,14 +134,13 @@ class LrcLib:
135
134
  use_translation=normalize_non_english,
136
135
  translation_session=self._translation_session,
137
136
  ):
138
- if album:
139
- if not are_strings_similar(
140
- result.get("albumName"),
141
- album,
142
- use_translation=normalize_non_english,
143
- translation_session=self._translation_session,
144
- ):
145
- continue
137
+ if album and not are_strings_similar(
138
+ result.get("albumName"),
139
+ album,
140
+ use_translation=normalize_non_english,
141
+ translation_session=self._translation_session,
142
+ ):
143
+ continue
146
144
  return result
147
145
  return None
148
146
 
@@ -20,12 +20,18 @@ from yutipy.lrclib import LrcLib
20
20
  class MusicYT:
21
21
  """A class to interact with the YouTube Music API."""
22
22
 
23
- def __init__(self) -> None:
24
- """Initializes the YouTube Music class and sets up the session."""
23
+ def __init__(self, fetch_lyrics: bool = True) -> None:
24
+ """
25
+ Parameters
26
+ ----------
27
+ fetch_lyrics : bool, optional
28
+ Whether to fetch lyrics (using `LRCLIB <https://lrclib.net>`__) if the music platform does not provide lyrics (default is True).
29
+ """
25
30
  self.ytmusic = YTMusic()
26
31
  self._is_session_closed = False
27
32
  self.normalize_non_english = True
28
33
  self.__translation_session = requests.Session()
34
+ self.fetch_lyrics = fetch_lyrics
29
35
 
30
36
  def __enter__(self) -> "MusicYT":
31
37
  """Enters the runtime context related to this object."""
@@ -248,7 +254,7 @@ class MusicYT:
248
254
  url=song_url,
249
255
  )
250
256
 
251
- if not music_info.lyrics:
257
+ if not music_info.lyrics and self.fetch_lyrics:
252
258
  with LrcLib() as lrc_lib:
253
259
  lyrics = lrc_lib.get_lyrics(
254
260
  artist=music_info.artists, song=music_info.title
@@ -15,6 +15,7 @@ from yutipy.exceptions import (
15
15
  SpotifyException,
16
16
  )
17
17
  from yutipy.logger import logger
18
+ from yutipy.lrclib import LrcLib
18
19
  from yutipy.models import MusicInfo, UserPlaying
19
20
  from yutipy.utils.helpers import (
20
21
  are_strings_similar,
@@ -22,7 +23,6 @@ from yutipy.utils.helpers import (
22
23
  is_valid_string,
23
24
  separate_artists,
24
25
  )
25
- from yutipy.lrclib import LrcLib
26
26
 
27
27
  load_dotenv()
28
28
 
@@ -40,11 +40,13 @@ class Spotify(BaseClient):
40
40
  """
41
41
 
42
42
  def __init__(
43
- self, client_id: str = None, client_secret: str = None, defer_load: bool = False
43
+ self,
44
+ client_id: str = None,
45
+ client_secret: str = None,
46
+ defer_load: bool = False,
47
+ fetch_lyrics: bool = True,
44
48
  ) -> None:
45
49
  """
46
- Initializes the Spotify class (using Client Credentials grant type/flow) and sets up the session.
47
-
48
50
  Parameters
49
51
  ----------
50
52
  client_id : str, optional
@@ -53,9 +55,12 @@ class Spotify(BaseClient):
53
55
  The Client secret for the Spotify API. Defaults to ``SPOTIFY_CLIENT_SECRET`` from environment variable or the ``.env`` file.
54
56
  defer_load : bool, optional
55
57
  Whether to defer loading the access token during initialization, by default ``False``
58
+ fetch_lyrics : bool, optional
59
+ Whether to fetch lyrics (using `LRCLIB <https://lrclib.net>`__) if the music platform does not provide lyrics (default is True).
56
60
  """
57
61
  self.client_id = client_id or SPOTIFY_CLIENT_ID
58
62
  self.client_secret = client_secret or SPOTIFY_CLIENT_SECRET
63
+ self.fetch_lyrics = fetch_lyrics
59
64
 
60
65
  if not self.client_id:
61
66
  raise SpotifyException(
@@ -344,12 +349,13 @@ class Spotify(BaseClient):
344
349
  url=track["external_urls"]["spotify"],
345
350
  )
346
351
 
347
- with LrcLib() as lrc_lib:
348
- lyrics = lrc_lib.get_lyrics(
349
- artist=music_info.artists, song=music_info.title
350
- )
351
- if lyrics:
352
- music_info.lyrics = lyrics.get("plainLyrics")
352
+ if self.fetch_lyrics:
353
+ with LrcLib() as lrc_lib:
354
+ lyrics = lrc_lib.get_lyrics(
355
+ artist=music_info.artists, song=music_info.title
356
+ )
357
+ if lyrics:
358
+ music_info.lyrics = lyrics.get("plainLyrics")
353
359
  return music_info
354
360
  return None
355
361
 
@@ -438,10 +444,9 @@ class SpotifyAuth(BaseAuthClient):
438
444
  redirect_uri: str = None,
439
445
  scopes: list[str] = None,
440
446
  defer_load: bool = False,
447
+ fetch_lyrics: bool = True,
441
448
  ):
442
449
  """
443
- Initializes the SpotifyAuth class (using Authorization Code grant type/flow) and sets up the session.
444
-
445
450
  Parameters
446
451
  ----------
447
452
  client_id : str, optional
@@ -454,11 +459,14 @@ class SpotifyAuth(BaseAuthClient):
454
459
  A list of scopes for the Spotify API. For example: `['user-read-email', 'user-read-private']`.
455
460
  defer_load : bool, optional
456
461
  Whether to defer loading the access token during initialization. Default is ``False``.
462
+ fetch_lyrics : bool, optional
463
+ Whether to fetch lyrics using `LRCLIB <https://lrclib.net>`__ if the music platform does not provide lyrics (default is True).
457
464
  """
458
465
  self.client_id = client_id or os.getenv("SPOTIFY_CLIENT_ID")
459
466
  self.client_secret = client_secret or os.getenv("SPOTIFY_CLIENT_SECRET")
460
467
  self.redirect_uri = redirect_uri or os.getenv("SPOTIFY_REDIRECT_URI")
461
468
  self.scopes = scopes
469
+ self.fetch_lyrics = fetch_lyrics
462
470
 
463
471
  if not self.client_id:
464
472
  raise SpotifyAuthException(
@@ -600,12 +608,13 @@ class SpotifyAuth(BaseAuthClient):
600
608
  url=result.get("external_urls", {}).get("spotify"),
601
609
  )
602
610
 
603
- with LrcLib() as lrc_lib:
604
- lyrics = lrc_lib.get_lyrics(
605
- artist=user_playing.artists, song=user_playing.title
606
- )
607
- if lyrics:
608
- user_playing.lyrics = lyrics.get("plainLyrics")
611
+ if self.fetch_lyrics:
612
+ with LrcLib() as lrc_lib:
613
+ lyrics = lrc_lib.get_lyrics(
614
+ artist=user_playing.artists, song=user_playing.title
615
+ )
616
+ if lyrics:
617
+ user_playing.lyrics = lyrics.get("plainLyrics")
609
618
  return user_playing
610
619
  return None
611
620
 
@@ -8,11 +8,12 @@ from yutipy.deezer import Deezer
8
8
  from yutipy.exceptions import InvalidValueException, KKBoxException, SpotifyException
9
9
  from yutipy.itunes import Itunes
10
10
  from yutipy.kkbox import KKBox
11
+ from yutipy.logger import logger
12
+ from yutipy.lrclib import LrcLib
11
13
  from yutipy.models import MusicInfo, MusicInfos
12
14
  from yutipy.musicyt import MusicYT
13
15
  from yutipy.spotify import Spotify
14
16
  from yutipy.utils.helpers import is_valid_string
15
- from yutipy.logger import logger
16
17
 
17
18
 
18
19
  class YutipyMusic:
@@ -28,8 +29,6 @@ class YutipyMusic:
28
29
  custom_spotify_class=Spotify,
29
30
  ) -> None:
30
31
  """
31
- Initializes the YutipyMusic class.
32
-
33
32
  Parameters
34
33
  ----------
35
34
  custom_kkbox_class : Optional[type], optional
@@ -43,13 +42,15 @@ class YutipyMusic:
43
42
  self.normalize_non_english = True
44
43
  self.album_art_priority = ["deezer", "ytmusic", "itunes"]
45
44
  self.services = {
46
- "deezer": Deezer(),
47
- "itunes": Itunes(),
48
- "ytmusic": MusicYT(),
45
+ "deezer": Deezer(fetch_lyrics=False),
46
+ "itunes": Itunes(fetch_lyrics=False),
47
+ "ytmusic": MusicYT(fetch_lyrics=False),
49
48
  }
50
49
 
51
50
  try:
52
- self.services["kkbox"] = custom_kkbox_class()
51
+ self.services["kkbox"] = custom_kkbox_class(
52
+ defer_load=True, fetch_lyrics=False
53
+ )
53
54
  except KKBoxException as e:
54
55
  logger.warning(
55
56
  f"{self.__class__.__name__}: Skipping KKBox due to KKBoxException: {e}"
@@ -59,7 +60,9 @@ class YutipyMusic:
59
60
  self.album_art_priority.insert(idx, "kkbox")
60
61
 
61
62
  try:
62
- self.services["spotify"] = custom_spotify_class()
63
+ self.services["spotify"] = custom_spotify_class(
64
+ defer_load=True, fetch_lyrics=False
65
+ )
63
66
  except SpotifyException as e:
64
67
  logger.warning(
65
68
  f"{self.__class__.__name__}: Skipping Spotify due to SpotifyException: {e}"
@@ -134,11 +137,18 @@ class YutipyMusic:
134
137
  )
135
138
 
136
139
  if len(self.music_info.url) == 0:
137
- logger.warning(
140
+ logger.info(
138
141
  f"No matching results found across all platforms for artist='{artist}' and song='{song}'"
139
142
  )
140
143
  return None
141
144
 
145
+ # Fetch lyrics only once using LrcLib if not already present
146
+ if not self.music_info.lyrics:
147
+ with LrcLib() as lrc_lib:
148
+ lyrics_result = lrc_lib.get_lyrics(artist, song)
149
+ if lyrics_result:
150
+ self.music_info.lyrics = lyrics_result.get("plainLyrics")
151
+
142
152
  return self.music_info
143
153
 
144
154
  def _combine_results(self, result: Optional[MusicInfo], service_name: str) -> None:
@@ -199,10 +209,10 @@ class YutipyMusic:
199
209
 
200
210
  if __name__ == "__main__":
201
211
  import logging
202
- from yutipy.logger import enable_logging
203
-
204
212
  from dataclasses import asdict
205
213
 
214
+ from yutipy.logger import enable_logging
215
+
206
216
  enable_logging(level=logging.DEBUG)
207
217
  yutipy_music = YutipyMusic()
208
218
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yutipy
3
- Version: 2.3.0
3
+ Version: 2.3.1
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>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes