diff --git a/music_kraken/pages/musicbrainz.py b/music_kraken/pages/musicbrainz.py new file mode 100644 index 0000000..65d23f3 --- /dev/null +++ b/music_kraken/pages/musicbrainz.py @@ -0,0 +1,142 @@ +from collections import defaultdict +from dataclasses import dataclass +from enum import Enum +from typing import List, Optional, Type, Union, Generator, Dict, Any +from urllib.parse import urlparse + +import pycountry +import musicbrainzngs +from bs4 import BeautifulSoup + +from ..connection import Connection +from .abstract import Page +from ..utils.enums import SourceType, ALL_SOURCE_TYPES +from ..utils.enums.album import AlbumType, AlbumStatus +from ..objects import ( + Artist, + Source, + Song, + Album, + ID3Timestamp, + FormattedText, + Label, + Target, + DatabaseObject, + Lyrics, + Artwork +) +from ..utils.config import logging_settings, main_settings +from ..utils import string_processing, shared +from ..utils.string_processing import clean_song_title +from ..utils.support_classes.query import Query +from ..utils.support_classes.download_result import DownloadResult + + + +class MusicbrainzTypes(Enum): + ARTIST = "artist" + RELEASE = "release" + SONG = "track" + + +@dataclass +class MusicbrainzUrl: + source_type: MusicbrainzTypes + name_without_id: str + name_with_id: str + musicbrainz_id: str + url: str + + +class Musicbrainz(Page): + SOURCE_TYPE = ALL_SOURCE_TYPES.MUSICBRAINZ + + HOST = "https://musicbrainz.org/" + + def __init__(self, *args, **kwargs): + self.connection: Connection = Connection( + host="https://musicbrainz.org/", + logger=self.LOGGER, + module="musicbrainz", + ) + + self.stream_connection: Connection = Connection( + host="https://musicbrainz.org/", + logger=self.LOGGER, + semantic_not_found=False, + ) + + super().__init__(*args, **kwargs) + + def get_source_type(self, source: Source) -> Optional[Type[DatabaseObject]]: + if source.url is None: + return None + + musicbrainz_url = parse_url(source.url) + + # Has no labels, because afaik musicbrainz has no Labels + musicbrainz_type_to_database_type = { + musicbrainzTypes.SONG: Song, + musicbrainzTypes.RELEASE: Album, + musicbrainzTypes.ARTIST: Artist + } + + return musicbrainz_type_to_database_type.get(musicbrainz_url.source_type) + + def parse_url(url: str) -> MusicbrainzUrl: + parsed = urlparse(url) + + path = parsed.path.split("/") + + split_name = path[2].split("-") + url_id = split_name[-1] + name_for_url = "-".join(split_name[:-1]) + + try: + type_enum = MusicbrainzTypes(path[1]) + except ValueError as e: + logging_settings["musicbrainz_logger"].warning(f"{path[1]} is not yet implemented, add it to MusicbrainzTypes") + raise e + + return MusicbrainzUrl( + source_type=type_enum, + name_without_id=name_for_url, + name_with_id=path[2], + musicbrainz_id=url_id, + url=url + ) + + def general_search(self, search_query: str) -> List[DatabaseObject]: + search_results = [] + + r = self.connection.get(f"https://musicbrainz.org/search?query={search_query}&type=artist&method=indexed", name="search_" + search_query) + if r is None: + return [] + search_soup: BeautifulSoup = self.get_soup_from_response(r) + + def artist_search(self, artist: Artist) -> List[Artist]: + artist_list = [] + + r = self.connection.get(f"https://musicbrainz.org/search?query={artist.name}&type=artist&method=indexed", name="search_" + artist.name) + if r is None: + return [] + + return artist_list + + def song_search(self, song: Song) -> List[Song]: + song_list = [] + + r = self.connection.get(f"https://musicbrainz.org/search?query={song.title_string}&type=recording&method=indexed", name="search_" + song.title_string) + if r is None: + return [] + + return song_list + + def album_search(self, album: Album) -> List[Album]: + album_list = [] + + r = self.connection.get(f"https://musicbrainz.org/search?query={album.title_string}&type=release_group&method=indexed", name="search_" + album.title_string) + if r is None: + return [] + + return album_list \ No newline at end of file