started fixing importand design flaw

This commit is contained in:
Hellow2 2023-03-24 14:28:19 +01:00
parent d685827fb5
commit 5387301ed2
2 changed files with 64 additions and 110 deletions

View File

@ -62,7 +62,7 @@ class Collection:
except KeyError: except KeyError:
pass pass
def append(self, element: DatabaseObject, merge_on_conflict: bool = True, merge_into_existing: bool = True) -> bool: def append(self, element: DatabaseObject, merge_on_conflict: bool = True, merge_into_existing: bool = True) -> DatabaseObject:
""" """
:param element: :param element:
:param merge_on_conflict: :param merge_on_conflict:
@ -78,28 +78,33 @@ class Collection:
if value in self._attribute_to_object_map[name]: if value in self._attribute_to_object_map[name]:
existing_object = self._attribute_to_object_map[name][value] existing_object = self._attribute_to_object_map[name][value]
if merge_on_conflict: if not merge_on_conflict:
# if the object does already exist return existing_object
# thus merging and don't add it afterwards
if merge_into_existing: # if the object does already exist
existing_object.merge(element) # thus merging and don't add it afterwards
# in case any relevant data has been added (e.g. it remaps the old object) if merge_into_existing:
self.map_element(existing_object) existing_object.merge(element)
else: # in case any relevant data has been added (e.g. it remaps the old object)
element.merge(existing_object) self.map_element(existing_object)
return existing_object
exists_at = self._data.index(existing_object)
self._data[exists_at] = element
self.unmap_element(existing_object)
self.map_element(element)
return False element.merge(existing_object)
exists_at = self._data.index(existing_object)
self._data[exists_at] = element
self.unmap_element(existing_object)
self.map_element(element)
return element
self._data.append(element) self._data.append(element)
self.map_element(element) self.map_element(element)
return True return element
def append_is_already_in_collection(self, element: DatabaseObject, merge_on_conflict: bool = True, merge_into_existing: bool = True) -> bool:
object_representing_the_data = self.append(element, merge_on_conflict=merge_on_conflict, merge_into_existing=merge_into_existing)
def extend(self, element_list: Iterable[DatabaseObject], merge_on_conflict: bool = True): def extend(self, element_list: Iterable[DatabaseObject], merge_on_conflict: bool = True):
for element in element_list: for element in element_list:

View File

@ -1,4 +1,4 @@
from typing import Optional from typing import Optional, Union, Type
import requests import requests
import logging import logging
@ -16,7 +16,8 @@ from ..objects import (
MusicObject, MusicObject,
Options, Options,
SourcePages, SourcePages,
Collection Collection,
Label
) )
@ -138,114 +139,62 @@ class Page:
return Options() return Options()
@classmethod @classmethod
def fetch_details(cls, music_object: MusicObject, flat: bool = False) -> MusicObject: def fetch_details(cls, music_object: Union[Song, Album, Artist, Label], stop_at_level: int = 1) -> MusicObject:
""" """
when a music object with laccing data is passed in, it returns when a music object with laccing data is passed in, it returns
the SAME object **(no copy)** with more detailed data. the SAME object **(no copy)** with more detailed data.
If you for example put in an album, it fetches the tracklist If you for example put in an album, it fetches the tracklist
:param music_object: :param music_object:
:param flat: :param stop_at_level:
if it is true it fetches only the most important information (only one level) This says the depth of the level the scraper will recurse to.
if an Artist is passed in, it fetches only the discography of the artist, and not the If this is for example set to 2, then the levels could be:
tracklist of every album of the artist. 1. Level: the album
2. Level: every song of the album + every artist of the album
If no additional requests are needed to get the data one level below the supposed stop level
this gets ignored
:return detailed_music_object: IT MODIFIES THE INPUT OBJ :return detailed_music_object: IT MODIFIES THE INPUT OBJ
""" """
new_music_object: MusicObject = type(music_object).__init__()
source: Source
for source in music_object.source_collection:
new_music_object.merge(cls.fetch_object_from_source(source=source, obj_type=type(music_object), stop_at_level=stop_at_level))
if type(music_object) == Song:
song = cls.fetch_song_details(music_object, flat=flat)
song.compile()
return song
if type(music_object) == Album:
album = cls.fetch_album_details(music_object, flat=flat) music_object.merge(new_music_object)
album.compile() music_object.compile()
return album
if type(music_object) == Artist: return music_object
artist = cls.fetch_artist_details(music_object, flat=flat)
artist.compile()
return artist
raise NotImplementedError(f"MusicObject {type(music_object)} has not been implemented yet")
@classmethod @classmethod
def fetch_song_from_source(cls, source: Source, flat: bool = False) -> Song: def fetch_object_from_source(cls, source: Source, obj_type: Union[Type[Song], Type[Album], Type[Artist], Type[Label]], stop_at_level: int = 1):
if obj_type == Artist:
return cls.fetch_artist_from_source(source=source, stop_at_level=stop_at_level)
if obj_type == Song:
return cls.fetch_song_from_source(source=source, stop_at_level=stop_at_level)
if obj_type == Album:
return cls.fetch_album_from_source(source=source, stop_at_level=stop_at_level)
if obj_type == Label:
return cls.fetch_label_from_source(source=source, stop_at_level=stop_at_level)
@classmethod
def fetch_song_from_source(cls, source: Source, stop_at_level: int = 1) -> Song:
return Song() return Song()
@classmethod @classmethod
def fetch_song_details(cls, song: Song, flat: bool = False) -> Song: def fetch_album_from_source(cls, source: Source, stop_at_level: int = 1) -> Album:
"""
for a general description check cls.fetch_details
:param song: song without much data
:param flat:
when True it only fetches the artist and the album, and the attributes of those,
who can be gotten with one api request
when False it fetches everything including, but not limited to:
- Lyrics
- Album + Tracklist (for tracksort)
:return detailed_song: it modifies the input song
"""
source: Source
for source in song.source_collection.get_sources_from_page(cls.SOURCE_TYPE):
new_song = cls.fetch_song_from_source(source, flat)
song.merge(new_song)
return song
@classmethod
def fetch_album_from_source(cls, source: Source, flat: bool = False) -> Album:
return Album() return Album()
@classmethod
def fetch_album_details(cls, album: Album, flat: bool = False) -> Album:
"""
for a general description check cls.fetch_details
:param album: album without much data
:param flat:
when True it only fetches the artist and the tracklist, and the attributes of those,
which can be gotten with one api request
when False it fetches everything including, but not limited to:
- Lyrics of every song
- Artist, Album, Tracklist
- every attribute of those
:return detailed_artist: it modifies the input artist
"""
source: Source
for source in album.source_collection.get_sources_from_page(cls.SOURCE_TYPE):
new_album: Album = cls.fetch_album_from_source(source, flat)
album.merge(new_album)
return album
@classmethod @classmethod
def fetch_artist_from_source(cls, source: Source, flat: bool = False) -> Artist: def fetch_artist_from_source(cls, source: Source, stop_at_level: int = 1) -> Artist:
return Artist() return Artist()
@classmethod def fetch_label_from_source(source: Source, stop_at_level: int = 1) -> Label:
def fetch_artist_details(cls, artist: Artist, flat: bool = False) -> Artist: return Label()
"""
for a general description check cls.fetch_details
:param artist: artist without much data
:param flat:
when True it only fetches the discographie, meaning every album, but not every tracklist
when False it fetches everything including, but not limited to:
- the whole discography
- the tracklist of every album in the discography
:return detailed_artist: it modifies the input artist
"""
source: Source
for source in artist.source_collection.get_sources_from_page(cls.SOURCE_TYPE):
new_artist: Artist = cls.fetch_artist_from_source(source, flat)
artist.merge(new_artist)
return artist