From f389ffeb19141df74517c56a0f1aa6948c102d8d Mon Sep 17 00:00:00 2001 From: Joel Daniel Rico Date: Fri, 29 Dec 2023 09:50:41 -0800 Subject: [PATCH 1/3] No longer retrieves lyrics on initialization --- example.py | 10 +++++--- geniusdotpy/{genius_builder.py => genius.py} | 12 ++++------ geniusdotpy/track.py | 24 +++++++++++++------- geniusdotpy/typing.py | 3 --- geniusdotpy/utils.py | 9 ++++---- 5 files changed, 33 insertions(+), 25 deletions(-) rename geniusdotpy/{genius_builder.py => genius.py} (88%) delete mode 100644 geniusdotpy/typing.py diff --git a/example.py b/example.py index 6d437d0..804e6f6 100644 --- a/example.py +++ b/example.py @@ -1,13 +1,13 @@ -from geniusdotpy.genius_builder import GeniusBuilder +from geniusdotpy.genius import Genius from geniusdotpy.track import Track def main(): # Get your client access token from https://genius.com/api-clients - client_access_token = "token" + client_access_token = "_J6d3sXCgXEwBm-MmtDyLUCSAgMEfrKmospTdqrr4ZsorkLuHBG3wUu5WllnKUzQ" # Create a GeniusBuilder object - genius = GeniusBuilder(client_access_token=client_access_token) + genius = Genius(client_access_token=client_access_token) # Search for a track by ID print(genius.search_track_by_id(378195)) @@ -21,6 +21,10 @@ def main(): # Search tracks by artist tracks: list[Track] = genius.search_track_by_artist(artist_id=16775) print(tracks[0]) + + # Retrieve lyrics + tracks[0].get_lyrics() + print(tracks[0].lyrics) diff --git a/geniusdotpy/genius_builder.py b/geniusdotpy/genius.py similarity index 88% rename from geniusdotpy/genius_builder.py rename to geniusdotpy/genius.py index 774ca04..f652be6 100644 --- a/geniusdotpy/genius_builder.py +++ b/geniusdotpy/genius.py @@ -2,10 +2,8 @@ from geniusdotpy.artist import Artist from geniusdotpy.track import Track from geniusdotpy.utils import SortType -from geniusdotpy.typing import queryID - -class GeniusBuilder: +class Genius: endpoint = "https://api.genius.com" """Genius API endpoint""" @@ -21,7 +19,7 @@ def __init__(self, client_access_token: str): self.headers = {"Authorization": f"Bearer {client_access_token}"} - def search_track_by_id(self, track_id: queryID): + def search_track_by_id(self, track_id: str | int): """Search for a track by ID. Keyword arguments: @@ -38,7 +36,7 @@ def search_track_by_id(self, track_id: queryID): return Track(track_info=response.json()["response"]["song"]) - def search_artist(self, artist_id: queryID): + def search_artist(self, artist_id: str | int): """Search for an artist by ID. Keyword arguments: @@ -55,7 +53,7 @@ def search_artist(self, artist_id: queryID): return Artist(artist_info=response.json()["response"]["artist"]) - def search(self, query: queryID) -> list[Track]: + def search(self, query: str | int) -> list[Track]: """Search for a track by query. Keyword arguments: @@ -78,7 +76,7 @@ def search(self, query: queryID) -> list[Track]: return tracks def search_track_by_artist( - self, artist_id: queryID, sort=SortType.TITLE, page=1, per_page=20 + self, artist_id: str | int, sort=SortType.TITLE, page=1, per_page=20 ) -> list: endpoint = f"{self.endpoint}/artists/{artist_id}/songs?sort={sort.value}&per_page={per_page}&page={page}" tracks = list() diff --git a/geniusdotpy/track.py b/geniusdotpy/track.py index b8a4c28..3565506 100644 --- a/geniusdotpy/track.py +++ b/geniusdotpy/track.py @@ -24,7 +24,7 @@ def __init__(self, track_info: dict): self.url: str = track_info["url"] """Genius.com URL of the track.""" - self.lyrics: str = utils.retrieve_lyrics(self.url) + self.lyrics: None | str = None """Track lyrics.""" self.title: str = track_info["title"] @@ -33,7 +33,6 @@ def __init__(self, track_info: dict): self.artist: Artist = Artist(track_info["primary_artist"]) """Track artist.""" - # Possibly null values self.release_date: None | datetime.datetime = None """Track release date.""" @@ -59,12 +58,21 @@ def __init__(self, track_info: dict): if "media" in track_info: for provider in track_info["media"]: - if provider["provider"] == "youtube": - self.youtube_url = provider["url"] - elif provider["provider"] == "spotify": - self.spotify_url = provider["url"] - elif provider["provider"] == "soundcloud": - self.soundcloud_url = provider["url"] + match provider["provider"]: + case "youtube": + self.youtube_url = provider["url"] + case "spotify": + self.spotify_url = provider["url"] + case "soundcloud": + self.soundcloud_url = provider["url"] + + def get_lyrics(self) -> None | str: + """Retrieves the lyrics of the track.""" + + if not self.lyrics: + self.lyrics = utils.retrieve_lyrics(self.url) + + return self.lyrics def __str__(self): return f"{self.title} by {self.artist.name}" diff --git a/geniusdotpy/typing.py b/geniusdotpy/typing.py deleted file mode 100644 index a41de7f..0000000 --- a/geniusdotpy/typing.py +++ /dev/null @@ -1,3 +0,0 @@ -from typing import TypeAlias - -queryID: TypeAlias = str | int diff --git a/geniusdotpy/utils.py b/geniusdotpy/utils.py index abd8928..0680ab7 100644 --- a/geniusdotpy/utils.py +++ b/geniusdotpy/utils.py @@ -20,8 +20,9 @@ def retrieve_lyrics(track_url: str): html = requests.get(track_url).content soup = BeautifulSoup(html, "html.parser") + res = soup.find("div", class_=lambda x: x and x.startswith("Lyrics__Container")) - res = soup.find("div", class_="Lyrics__Container-sc-1ynbvzw-5") - assert res, "Could not find lyrics (div.Lyrics__Container-sc-1ynbvzw-5))" - - return res.get_text(separator="\n") + if res: + return res.get_text(separator="\n") + else: + return None \ No newline at end of file From 9c8f92b813c80652baf016ac751f9c429e81d63f Mon Sep 17 00:00:00 2001 From: Joel Daniel Rico Date: Fri, 29 Dec 2023 10:37:46 -0800 Subject: [PATCH 2/3] Update Genius API calls and print track and artist information --- example.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/example.py b/example.py index 804e6f6..3cd4bae 100644 --- a/example.py +++ b/example.py @@ -4,28 +4,31 @@ def main(): # Get your client access token from https://genius.com/api-clients - client_access_token = "_J6d3sXCgXEwBm-MmtDyLUCSAgMEfrKmospTdqrr4ZsorkLuHBG3wUu5WllnKUzQ" + client_access_token = "token" # Create a GeniusBuilder object genius = Genius(client_access_token=client_access_token) # Search for a track by ID - print(genius.search_track_by_id(378195)) + track1 = genius.search_track_by_id(378195) + print(repr(track1)) # Search artist by ID - print(genius.search_artist(16775)) + artist1 = genius.search_artist(track1.artist.id) + print(repr(artist1)) # Search for a track by query - print(genius.search("Beat It")[0]) + track3 = genius.search("Beat It")[0] + print(repr(track3)) # Search tracks by artist tracks: list[Track] = genius.search_track_by_artist(artist_id=16775) - print(tracks[0]) + track4 = tracks[0] + print(repr(track4)) # Retrieve lyrics - tracks[0].get_lyrics() - - print(tracks[0].lyrics) + track4.get_lyrics() + print(track4.lyrics) if __name__ == "__main__": From 9a47ad809499cd225bcbd2705ea9590d548643d6 Mon Sep 17 00:00:00 2001 From: Joel Daniel Rico Date: Fri, 29 Dec 2023 10:38:27 -0800 Subject: [PATCH 3/3] Refactor classes, add cleaned json output --- geniusdotpy/album.py | 19 +++++++++++++++++-- geniusdotpy/artist.py | 18 +++++++++++++++--- geniusdotpy/genius.py | 2 +- geniusdotpy/track.py | 26 +++++++++++++++++++++++++- 4 files changed, 58 insertions(+), 7 deletions(-) diff --git a/geniusdotpy/album.py b/geniusdotpy/album.py index 90b03cc..a34284f 100644 --- a/geniusdotpy/album.py +++ b/geniusdotpy/album.py @@ -1,12 +1,11 @@ from geniusdotpy.artist import Artist +import json class Album: """Album class""" def __init__(self, album_info: dict): - self.album_info = album_info - """JSON object containing album information.""" self.name: str = album_info["name"] """Album name""" @@ -26,3 +25,19 @@ def __init__(self, album_info: dict): self.full_title = album_info["full_title"] if "artist" in album_info: self.artist = Artist(album_info["artist"]) + + self.album_info: dict[str, str] = { + "name": self.name, + "url": self.url, + "full_title": self.full_title, + "artist": self.artist.artist_info, + } + """JSON object containing album information.""" + + self.json = json.dumps(self.album_info, indent=2) + + def __str__(self): + return f"{self.name} by {self.artist}" + + def __repr__(self): + return self.json \ No newline at end of file diff --git a/geniusdotpy/artist.py b/geniusdotpy/artist.py index 89c4e84..3af493f 100644 --- a/geniusdotpy/artist.py +++ b/geniusdotpy/artist.py @@ -1,3 +1,5 @@ +import json + class Artist: """Genius.com Artist class. @@ -15,9 +17,6 @@ def __init__(self, artist_info: dict): Artist object """ - self.artist_info = artist_info - """JSON object containing artist information.""" - self.api_path: str = artist_info["api_path"] """API path of the artist.""" @@ -30,5 +29,18 @@ def __init__(self, artist_info: dict): self.url: str = artist_info["url"] """Genius.com URL of the artist.""" + self.artist_info: dict[str, str] = { + "api_path": self.api_path, + "id": self.id, + "name": self.name, + "url": self.url, + } + """Dictionary containing artist information.""" + + self.json = json.dumps(self.artist_info, indent=2) + def __str__(self): return self.name + + def __repr__(self): + return self.json \ No newline at end of file diff --git a/geniusdotpy/genius.py b/geniusdotpy/genius.py index f652be6..cef02f6 100644 --- a/geniusdotpy/genius.py +++ b/geniusdotpy/genius.py @@ -79,7 +79,7 @@ def search_track_by_artist( self, artist_id: str | int, sort=SortType.TITLE, page=1, per_page=20 ) -> list: endpoint = f"{self.endpoint}/artists/{artist_id}/songs?sort={sort.value}&per_page={per_page}&page={page}" - tracks = list() + tracks: list[Track] = list() response = requests.get(endpoint, headers=self.headers) response.raise_for_status() diff --git a/geniusdotpy/track.py b/geniusdotpy/track.py index 3565506..a7b2ef1 100644 --- a/geniusdotpy/track.py +++ b/geniusdotpy/track.py @@ -2,6 +2,7 @@ from geniusdotpy import utils from geniusdotpy.album import Album from geniusdotpy.artist import Artist +import json class Track: @@ -12,7 +13,6 @@ def __init__(self, track_info: dict): track_info -- JSON object containing track info """ - self._track_info = track_info """JSON object containing track information.""" self.api_path: str = track_info["api_path"] @@ -65,6 +65,27 @@ def __init__(self, track_info: dict): self.spotify_url = provider["url"] case "soundcloud": self.soundcloud_url = provider["url"] + + + self.track_info: dict = { + "api_path": self.api_path, + "id": self.id, + "url": self.url, + "lyrics": self.lyrics, + "title": self.title, + "artist": self.artist.artist_info, + "release_date": str(self.release_date), + "youtube_url": self.youtube_url, + "spotify_url": self.spotify_url, + "soundcloud_url": self.soundcloud_url, + } + + if self.album: + self.track_info["album"] = self.album.album_info + else: + self.track_info["album"] = None + + self.json = json.dumps(self.track_info, indent=2) def get_lyrics(self) -> None | str: """Retrieves the lyrics of the track.""" @@ -76,3 +97,6 @@ def get_lyrics(self) -> None | str: def __str__(self): return f"{self.title} by {self.artist.name}" + + def __repr__(self): + return self.json \ No newline at end of file