music-kraken-core/music_kraken/pages/musicbrainz.py

142 lines
4.1 KiB
Python
Raw Normal View History

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