From 297811dcabf62cec18889f5a56b701de28cde797 Mon Sep 17 00:00:00 2001 From: Marvin Schenkel Date: Sat, 2 Jul 2022 16:47:50 +0200 Subject: [PATCH] Parse artist, album and track --- examples/ytmusic.py | 14 ++++-- music_assistant/music_providers/ytmusic.py | 53 +++++++++++++++++----- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/examples/ytmusic.py b/examples/ytmusic.py index 86a90c1d..c62b3366 100644 --- a/examples/ytmusic.py +++ b/examples/ytmusic.py @@ -106,9 +106,17 @@ async def main(): async with MusicAssistant(mass_conf) as mass: # get some data yt = mass.music.get_provider(ProviderType.YTMUSIC) - await yt.get_album("MPREb_9nqEki4ZDpp") - track = await yt.get_track("pE3ju1qS848") - await yt.get_stream_details("pE3ju1qS848") + track = await yt.get_track("pE3ju1qS848") + await yt.get_album("MPREb_AYetWMZunqA") + await yt.get_artist("UCU2d6Vg6hp0vJb8K0krR5_g") + + #test_player1 = TestPlayer("test1") + #await mass.players.register_player(test_player1) + #await test_player1.active_queue.play_media(track) + + #await asyncio.sleep(3600) + + if __name__ == "__main__": try: diff --git a/music_assistant/music_providers/ytmusic.py b/music_assistant/music_providers/ytmusic.py index 65870de2..49f366cf 100644 --- a/music_assistant/music_providers/ytmusic.py +++ b/music_assistant/music_providers/ytmusic.py @@ -7,6 +7,11 @@ from typing import AsyncGenerator, Dict, List, Optional from urllib.parse import unquote import ytmusicapi +from ytmusicapi.navigation import ( + nav, + SINGLE_COLUMN_TAB, + SECTION_LIST +) import pytube from music_assistant.models.enums import ProviderType @@ -67,6 +72,13 @@ class YTMusic(MusicProvider): async def get_artist(self, prov_artist_id) -> Artist: """Get full artist details by id""" + data = {"browseId": prov_artist_id} + artist_obj = await self._post_data(endpoint="browse", data=data) + return ( + await self._parse_artist(artist_obj=artist_obj) + if artist_obj + else None + ) async def get_track(self, prov_track_id) -> Track: """Get full track details by id.""" @@ -157,44 +169,61 @@ class YTMusic(MusicProvider): async def _parse_album(self, album_obj: dict) -> Album: """Parses a YT Album response to an Album model object""" parsed_album = ytmusicapi.parsers.albums.parse_album_header(album_obj) - album = Album( item_id = parsed_album["audioPlaylistId"], name = parsed_album["title"], + year = parsed_album["year"], album_type = AlbumType.ALBUM, provider = self.type ) - #TODO Add metadata + images = [] + for thumb in parsed_album["thumbnails"]: + images.append(MediaItemImage(ImageType.THUMB, thumb["url"])) + album.metadata.images = images + album.metadata.description = unquote(parsed_album["description"]) + artists = [] + for artist in parsed_album["artists"]: + artists.append(await self.get_artist(artist["id"])) + album.artists = artists return album async def _parse_artist(self, artist_obj: dict) -> Artist: """Parse a YT Artist response to Artist model object""" - print(json.dumps(artist_obj)) + name = artist_obj["header"]["musicImmersiveHeaderRenderer"]["title"]["runs"][0]["text"] + id = artist_obj["header"]["musicImmersiveHeaderRenderer"]["subscriptionButton"]["subscribeButtonRenderer"]["channelId"] + artist = Artist( + item_id=str(id), provider=self.type, name=name + ) + artist.metadata.description = unquote(artist_obj["header"]["musicImmersiveHeaderRenderer"]["description"]["runs"][0]["text"]) + images = [] + for thumb in artist_obj["header"]["musicImmersiveHeaderRenderer"]["thumbnail"]["musicThumbnailRenderer"]["thumbnail"]["thumbnails"]: + images.append(MediaItemImage(ImageType.THUMB, thumb["url"])) + artist.metadata.images = images + return artist async def _parse_track(self, track_obj: dict) -> Track: """Parses a YT Track response to a Track model object""" - keys = ['videoDetails', 'playabilityStatus', 'streamingData', 'microformat'] - for k in list(track_obj.keys()): - if k not in keys: - del track_obj[k] track = Track( item_id=track_obj["videoDetails"]["videoId"], provider=self.type, - name=track_obj["videoDetails"]["title"] + name=track_obj["videoDetails"]["title"], + duration=track_obj["videoDetails"]["lengthSeconds"] ) + artist = await self.get_artist(track_obj["microformat"]["microformatDataRenderer"]["pageOwnerDetails"]["externalChannelId"]) + track.artists = [artist] + images = [] + for thumb in track_obj["microformat"]["microformatDataRenderer"]["thumbnail"]["thumbnails"]: + images.append(MediaItemImage(ImageType.THUMB, thumb["url"])) return track async def _parse_stream_format(self, track_obj: dict) -> dict: """Grabs the highes available audio stream from available streams""" stream_format = None - for format in track_obj["streamingData"]["adaptiveFormats"]: if format["mimeType"].startswith("audio") and format["audioQuality"] == "AUDIO_QUALITY_HIGH": - stream_format = format - + stream_format = format if stream_format is None: raise MediaNotFoundError("No stream found for this track") - return stream_format async def _parse_stream_url(self, stream_format: dict, item_id: str) -> str: -- 2.34.1