From c4f10e790676d97219062a7c3abb1165de53761f Mon Sep 17 00:00:00 2001 From: Hellow <74311245+HeIIow2@users.noreply.github.com> Date: Fri, 28 Jul 2023 00:20:51 +0200 Subject: [PATCH] finished first search functionality --- .../html/youtube-music/search/search.md | 2 +- src/actual_donwload.py | 2 +- .../pages/youtube_music/_list_render.py | 37 ++++++++++++ .../youtube_music/_music_object_render.py | 56 +++++++++++++++++++ .../pages/youtube_music/youtube_music.py | 9 ++- 5 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 src/music_kraken/pages/youtube_music/_list_render.py create mode 100644 src/music_kraken/pages/youtube_music/_music_object_render.py diff --git a/documentation/html/youtube-music/search/search.md b/documentation/html/youtube-music/search/search.md index 6fc220f..e5892b4 100644 --- a/documentation/html/youtube-music/search/search.md +++ b/documentation/html/youtube-music/search/search.md @@ -4,7 +4,7 @@ what is it | query | file ---|---|--- -general search response | `psychonaut 4`, [general-result.json](general-result.json) +general search response | `psychonaut 4` | [general-result.json](general-result.json) ## A general search yields diff --git a/src/actual_donwload.py b/src/actual_donwload.py index f69b781..93f5bd9 100644 --- a/src/actual_donwload.py +++ b/src/actual_donwload.py @@ -29,7 +29,7 @@ if __name__ == "__main__": ] youtube_music_test = [ - "s: psychonaut 4" + "s: billie eilish" ] music_kraken.cli.download(genre="test", command_list=youtube_music_test, process_metadata_anyway=True) diff --git a/src/music_kraken/pages/youtube_music/_list_render.py b/src/music_kraken/pages/youtube_music/_list_render.py new file mode 100644 index 0000000..689d827 --- /dev/null +++ b/src/music_kraken/pages/youtube_music/_list_render.py @@ -0,0 +1,37 @@ +from typing import List, Optional +from enum import Enum + +from ...utils.shared import YOUTUBE_MUSIC_LOGGER as LOGGER +from ...objects import Source, DatabaseObject +from ..abstract import Page +from ...objects import ( + Artist, + Source, + SourcePages, + Song, + Album, + Label, + Target +) +from ._music_object_render import parse_run_list + + +def music_card_shelf_renderer(renderer: dict) -> List[DatabaseObject]: + return parse_run_list(renderer.get("title", {}).get("runs", [])) + + +RENDERER_PARSERS = { + "musicCardShelfRenderer": music_card_shelf_renderer +} + +def parse_renderer(renderer: dict) -> List[DatabaseObject]: + result: List[DatabaseObject] = [] + + for renderer_name, renderer in renderer.items(): + if renderer_name not in RENDERER_PARSERS: + LOGGER.warning(f"Can't parse the renderer {renderer_name}.") + continue + + result.extend(RENDERER_PARSERS[renderer_name](renderer)) + + return result \ No newline at end of file diff --git a/src/music_kraken/pages/youtube_music/_music_object_render.py b/src/music_kraken/pages/youtube_music/_music_object_render.py new file mode 100644 index 0000000..b40b0d6 --- /dev/null +++ b/src/music_kraken/pages/youtube_music/_music_object_render.py @@ -0,0 +1,56 @@ +from typing import List, Optional +from enum import Enum + +from ...objects import Source, DatabaseObject +from ..abstract import Page +from ...objects import ( + Artist, + Source, + SourcePages, + Song, + Album, + Label, + Target +) + + +SOURCE_PAGE = SourcePages.YOUTUBE_MUSIC + + +class PageType(Enum): + ARTIST = "MUSIC_PAGE_TYPE_ARTIST" + ALBUM = "MUSIC_PAGE_TYPE_ALBUM" + CHANNEL = "MUSIC_PAGE_TYPE_USER_CHANNEL" + PLAYLIST = "MUSIC_PAGE_TYPE_PLAYLIST" + + +def parse_run_element(run_element: dict) -> Optional[DatabaseObject]: + navigation_endpoint = run_element.get("navigationEndpoint", {}).get("browseEndpoint", {}) + + element_type = PageType(navigation_endpoint.get("browseEndpointContextSupportedConfigs", {}).get("browseEndpointContextMusicConfig", {}).get("pageType", "")) + + element_id = navigation_endpoint.get("browseId") + element_text = run_element.get("text") + + if element_id is None or element_text is None: + return + + if element_type == PageType.ARTIST: + source = Source(SOURCE_PAGE, f"https://music.youtube.com/channel/{element_id}") + return Artist(name=element_text, source_list=[source]) + + +def parse_run_list(run_list: List[dict]) -> List[DatabaseObject]: + music_object_list: List[DatabaseObject] = [] + + for run_renderer in run_list: + if "navigationEndpoint" not in run_renderer: + continue + + music_object = parse_run_element(run_renderer) + if music_object is None: + continue + + music_object_list.append(music_object) + + return music_object_list diff --git a/src/music_kraken/pages/youtube_music/youtube_music.py b/src/music_kraken/pages/youtube_music/youtube_music.py index ee54117..031ed16 100644 --- a/src/music_kraken/pages/youtube_music/youtube_music.py +++ b/src/music_kraken/pages/youtube_music/youtube_music.py @@ -27,6 +27,8 @@ from ...objects import ( from ...connection import Connection from ...utils.support_classes import DownloadResult +from ._list_render import parse_renderer + def get_youtube_url(path: str = "", params: str = "", query: str = "", fragment: str = "") -> str: return urlunparse(("https", "music.youtube.com", path, params, query, fragment)) @@ -265,9 +267,10 @@ class YoutubeMusic(Page): for i, content in enumerate(renderer_list): dump_to_file(f"{i}-renderer.json", json.dumps(content), is_json=True, exit_after_dump=False) - return [ - Song(title="Lore Ipsum") - ] + results = [] + results.extend(parse_renderer(renderer_list[1])) + + return results def label_search(self, label: Label) -> List[Label]: return []