From 41a91a6afeef4bc71eec6f74c1466f563fb1255f Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Thu, 16 May 2024 13:41:06 +0200 Subject: [PATCH 01/15] feat: removing dependence beteen artist.album and album.artist --- music_kraken/objects/song.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/music_kraken/objects/song.py b/music_kraken/objects/song.py index 8e30a9a..48f6edd 100644 --- a/music_kraken/objects/song.py +++ b/music_kraken/objects/song.py @@ -108,8 +108,8 @@ class Song(Base): "artwork": Artwork, "main_artist_collection": Collection, - "album_collection": Collection, "feature_artist_collection": Collection, + "album_collection": Collection, "title": lambda: None, "unified_title": lambda: None, @@ -376,6 +376,7 @@ class Album(Base): def _compile(self): self.analyze_implied_album_type() self.update_tracksort() + self.fix_artist_collection() def analyze_implied_album_type(self): # if the song collection has only one song, it is reasonable to assume that it is a single @@ -417,6 +418,16 @@ class Album(Base): tracksort_map[i] = existing_list.pop(0) tracksort_map[i].tracksort = i + def fix_artist_collection(self): + """ + I add artists, that could only be feature artists to the feature artist collection. + They get automatically moved to main artist collection, if a matching artist exists in the main artist collection or is appended to it later on. + If I am not sure for any artist, I try to analyze the most common artist in the song collection of one album. + """ + + # move all artists that are in all feature_artist_collections, of every song, to the main_artist_collection + pass + @property def copyright(self) -> str: if self.date is None: @@ -510,10 +521,6 @@ class Artist(Base): UPWARDS_COLLECTION_STRING_ATTRIBUTES = ("label_collection",) def __init_collections__(self): - self.main_album_collection.append_object_to_attribute = { - "artist_collection": self - } - self.label_collection.append_object_to_attribute = { "current_artist_collection": self } From 2b3f4d82d9426c8cab119c629835307edcd0813b Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Thu, 16 May 2024 14:05:33 +0200 Subject: [PATCH 02/15] feat: renamed main_artist_collection to artist_collection --- development/objects_collection.py | 2 +- music_kraken/cli/main_downloader.py | 2 +- music_kraken/download/page_attributes.py | 2 +- music_kraken/objects/song.py | 25 ++++++++++---------- music_kraken/pages/encyclopaedia_metallum.py | 2 +- music_kraken/utils/support_classes/query.py | 2 +- tests/test_collection.py | 10 ++++---- 7 files changed, 23 insertions(+), 22 deletions(-) diff --git a/development/objects_collection.py b/development/objects_collection.py index 893e2c5..04e0ba6 100644 --- a/development/objects_collection.py +++ b/development/objects_collection.py @@ -21,5 +21,5 @@ if __name__ == "__main__": song_1.merge(song_2) print("#" * 120) - print("main", *song_1.main_artist_collection) + print("main", *song_1.artist_collection) print("feat", *song_1.feature_artist_collection) diff --git a/music_kraken/cli/main_downloader.py b/music_kraken/cli/main_downloader.py index e3fe2cb..38d20cf 100644 --- a/music_kraken/cli/main_downloader.py +++ b/music_kraken/cli/main_downloader.py @@ -226,7 +226,7 @@ class Downloader: if album is not None: song.album_collection.append(album) if artist is not None: - song.main_artist_collection.append(artist) + song.artist_collection.append(artist) return Query(raw_query=query, music_object=song) if album is not None: diff --git a/music_kraken/download/page_attributes.py b/music_kraken/download/page_attributes.py index 3bd14f2..fbf6982 100644 --- a/music_kraken/download/page_attributes.py +++ b/music_kraken/download/page_attributes.py @@ -239,7 +239,7 @@ class Pages: naming["isrc"].append(song.isrc) naming["album"].extend(a.title_string for a in song.album_collection) naming["album_type"].extend(a.album_type.value for a in song.album_collection) - naming["artist"].extend(a.name for a in song.main_artist_collection) + naming["artist"].extend(a.name for a in song.artist_collection) naming["artist"].extend(a.name for a in song.feature_artist_collection) for a in song.album_collection: naming["label"].extend([l.title_string for l in a.label_collection]) diff --git a/music_kraken/objects/song.py b/music_kraken/objects/song.py index 48f6edd..58e13e3 100644 --- a/music_kraken/objects/song.py +++ b/music_kraken/objects/song.py @@ -95,7 +95,7 @@ class Song(Base): target_collection: Collection[Target] lyrics_collection: Collection[Lyrics] - main_artist_collection: Collection[Artist] + artist_collection: Collection[Artist] feature_artist_collection: Collection[Artist] album_collection: Collection[Album] @@ -107,7 +107,7 @@ class Song(Base): "lyrics_collection": Collection, "artwork": Artwork, - "main_artist_collection": Collection, + "artist_collection": Collection, "feature_artist_collection": Collection, "album_collection": Collection, @@ -141,23 +141,23 @@ class Song(Base): Base.__init__(**real_kwargs) - UPWARDS_COLLECTION_STRING_ATTRIBUTES = ("main_artist_collection", "feature_artist_collection", "album_collection") + UPWARDS_COLLECTION_STRING_ATTRIBUTES = ("artist_collection", "feature_artist_collection", "album_collection") TITEL = "title" def __init_collections__(self) -> None: self.album_collection.sync_on_append = { - "artist_collection": self.main_artist_collection, + "artist_collection": self.artist_collection, } self.album_collection.append_object_to_attribute = { "song_collection": self, } - self.main_artist_collection.extend_object_to_attribute = { + self.artist_collection.extend_object_to_attribute = { "main_album_collection": self.album_collection } - self.feature_artist_collection.push_to = [self.main_artist_collection] - self.main_artist_collection.pull_from = [self.feature_artist_collection] + self.feature_artist_collection.push_to = [self.artist_collection] + self.artist_collection.pull_from = [self.feature_artist_collection] def _add_other_db_objects(self, object_type: Type[OuterProxy], object_list: List[OuterProxy]): if object_type is Song: @@ -200,14 +200,14 @@ class Song(Base): # metadata.merge_many([s.get_song_metadata() for s in self.source_collection]) album sources have no relevant metadata for id3 metadata.merge_many([a.metadata for a in self.album_collection]) - metadata.merge_many([a.metadata for a in self.main_artist_collection]) + metadata.merge_many([a.metadata for a in self.artist_collection]) metadata.merge_many([a.metadata for a in self.feature_artist_collection]) metadata.merge_many([lyrics.metadata for lyrics in self.lyrics_collection]) return metadata def get_artist_credits(self) -> str: - main_artists = ", ".join([artist.name for artist in self.main_artist_collection]) + main_artists = ", ".join([artist.name for artist in self.artist_collection]) feature_artists = ", ".join([artist.name for artist in self.feature_artist_collection]) if len(feature_artists) == 0: @@ -218,7 +218,7 @@ class Song(Base): def option_string(self) -> str: r = OPTION_FOREGROUND.value + self.title_string + BColors.ENDC.value + OPTION_BACKGROUND.value r += get_collection_string(self.album_collection, " from {}", ignore_titles={self.title}) - r += get_collection_string(self.main_artist_collection, " by {}") + r += get_collection_string(self.artist_collection, " by {}") r += get_collection_string(self.feature_artist_collection, " feat. {}") return r @@ -270,6 +270,7 @@ class Album(Base): "source_collection": SourceCollection, "artist_collection": Collection, + "song_collection": Collection, "label_collection": Collection, } @@ -307,7 +308,7 @@ class Album(Base): "album_collection": self } self.song_collection.sync_on_append = { - "main_artist_collection": self.artist_collection + "artist_collection": self.artist_collection } self.artist_collection.append_object_to_attribute = { @@ -425,7 +426,7 @@ class Album(Base): If I am not sure for any artist, I try to analyze the most common artist in the song collection of one album. """ - # move all artists that are in all feature_artist_collections, of every song, to the main_artist_collection + # move all artists that are in all feature_artist_collections, of every song, to the artist_collection pass @property diff --git a/music_kraken/pages/encyclopaedia_metallum.py b/music_kraken/pages/encyclopaedia_metallum.py index 9c1fefe..9074e57 100644 --- a/music_kraken/pages/encyclopaedia_metallum.py +++ b/music_kraken/pages/encyclopaedia_metallum.py @@ -266,7 +266,7 @@ class EncyclopaediaMetallum(Page): song_title = song.title.strip() album_titles = ["*"] if song.album_collection.empty else [album.title.strip() for album in song.album_collection] - artist_titles = ["*"] if song.main_artist_collection.empty else [artist.name.strip() for artist in song.main_artist_collection] + artist_titles = ["*"] if song.artist_collection.empty else [artist.name.strip() for artist in song.artist_collection] search_results = [] diff --git a/music_kraken/utils/support_classes/query.py b/music_kraken/utils/support_classes/query.py index d6d70c9..754032d 100644 --- a/music_kraken/utils/support_classes/query.py +++ b/music_kraken/utils/support_classes/query.py @@ -24,7 +24,7 @@ class Query: return [self.music_object.name] if isinstance(self.music_object, Song): - return [f"{artist.name} - {self.music_object}" for artist in self.music_object.main_artist_collection] + return [f"{artist.name} - {self.music_object}" for artist in self.music_object.artist_collection] if isinstance(self.music_object, Album): return [f"{artist.name} - {self.music_object}" for artist in self.music_object.artist_collection] diff --git a/tests/test_collection.py b/tests/test_collection.py index bc3674b..186e814 100644 --- a/tests/test_collection.py +++ b/tests/test_collection.py @@ -86,7 +86,7 @@ class TestCollection(unittest.TestCase): ] ) - self.assertTrue(artist.id == artist.main_album_collection[0].song_collection[0].main_artist_collection[0].id) + self.assertTrue(artist.id == artist.main_album_collection[0].song_collection[0].artist_collection[0].id) def test_artist_collection_sync(self): album_1 = Album( @@ -111,13 +111,13 @@ class TestCollection(unittest.TestCase): album_1.merge(album_2) - self.assertTrue(id(album_1.artist_collection) == id(album_1.artist_collection) == id(album_1.song_collection[0].main_artist_collection) == id(album_1.song_collection[0].main_artist_collection)) + self.assertTrue(id(album_1.artist_collection) == id(album_1.artist_collection) == id(album_1.song_collection[0].artist_collection) == id(album_1.song_collection[0].artist_collection)) def test_song_artist_relations(self): a = self.complicated_object() - b = a.main_album_collection[0].song_collection[0].main_artist_collection[0] - c = b.main_album_collection[0].song_collection[0].main_artist_collection[0] - d = c.main_album_collection[0].song_collection[0].main_artist_collection[0] + b = a.main_album_collection[0].song_collection[0].artist_collection[0] + c = b.main_album_collection[0].song_collection[0].artist_collection[0] + d = c.main_album_collection[0].song_collection[0].artist_collection[0] self.assertTrue(a.id == b.id == c.id == d.id) self.assertTrue(a.name == b.name == c.name == d.name == "artist") From 8ccc28daf85f8faaafdde87dfa07c2f084e1314b Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Thu, 16 May 2024 14:09:34 +0200 Subject: [PATCH 03/15] draft: added feature artist collection attr --- music_kraken/objects/song.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/music_kraken/objects/song.py b/music_kraken/objects/song.py index 58e13e3..4156a93 100644 --- a/music_kraken/objects/song.py +++ b/music_kraken/objects/song.py @@ -107,9 +107,9 @@ class Song(Base): "lyrics_collection": Collection, "artwork": Artwork, + "album_collection": Collection, "artist_collection": Collection, "feature_artist_collection": Collection, - "album_collection": Collection, "title": lambda: None, "unified_title": lambda: None, @@ -252,8 +252,9 @@ class Album(Base): source_collection: SourceCollection - artist_collection: Collection[Artist] song_collection: Collection[Song] + artist_collection: Collection[Artist] + feature_artist_collection: Collection[Artist] label_collection: Collection[Label] _default_factories = { @@ -269,9 +270,10 @@ class Album(Base): "notes": FormattedText, "source_collection": SourceCollection, - "artist_collection": Collection, "song_collection": Collection, + "artist_collection": Collection, + "feature_artist_collection": Collection, "label_collection": Collection, } From adcf26b51820094e33b599ced59cf047afab25a1 Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Thu, 16 May 2024 14:10:00 +0200 Subject: [PATCH 04/15] feat: renamed main album collection to album collection --- music_kraken/objects/song.py | 27 ++++++++++++-------- music_kraken/pages/bandcamp.py | 4 +-- music_kraken/pages/encyclopaedia_metallum.py | 2 +- music_kraken/pages/musify.py | 2 +- tests/test_collection.py | 16 ++++++------ 5 files changed, 28 insertions(+), 23 deletions(-) diff --git a/music_kraken/objects/song.py b/music_kraken/objects/song.py index 4156a93..bab1ae3 100644 --- a/music_kraken/objects/song.py +++ b/music_kraken/objects/song.py @@ -153,7 +153,12 @@ class Song(Base): "song_collection": self, } self.artist_collection.extend_object_to_attribute = { - "main_album_collection": self.album_collection + "album_collection": self.album_collection + } + + + self.album_collection.append_object_to_attribute = { + "artist_collection": self } self.feature_artist_collection.push_to = [self.artist_collection] @@ -314,7 +319,7 @@ class Album(Base): } self.artist_collection.append_object_to_attribute = { - "main_album_collection": self + "album_collection": self } self.artist_collection.extend_object_to_attribute = { "label_collection": self.label_collection @@ -475,7 +480,7 @@ class Artist(Base): source_collection: SourceCollection contact_collection: Collection[Contact] - main_album_collection: Collection[Album] + album_collection: Collection[Album] label_collection: Collection[Label] _default_factories = { @@ -489,7 +494,7 @@ class Artist(Base): "general_genre": lambda: "", "source_collection": SourceCollection, - "main_album_collection": Collection, + "album_collection": Collection, "contact_collection": Collection, "label_collection": Collection, } @@ -520,7 +525,7 @@ class Artist(Base): Base.__init__(**real_kwargs) - DOWNWARDS_COLLECTION_STRING_ATTRIBUTES = ("main_album_collection",) + DOWNWARDS_COLLECTION_STRING_ATTRIBUTES = ("album_collection",) UPWARDS_COLLECTION_STRING_ATTRIBUTES = ("label_collection",) def __init_collections__(self): @@ -537,7 +542,7 @@ class Artist(Base): return if object_type is Album: - self.main_album_collection.extend(object_list) + self.album_collection.extend(object_list) return if object_type is Label: @@ -550,7 +555,7 @@ class Artist(Base): def update_albumsort(self): """ This updates the albumsort attributes, of the albums in - `self.main_album_collection`, and sorts the albums, if possible. + `self.album_collection`, and sorts the albums, if possible. It is advised to only call this function, once all the albums are added to the artist. @@ -568,7 +573,7 @@ class Artist(Base): # order albums in the previously defined section album: Album - for album in self.main_album_collection: + for album in self.album_collection: sections[type_section[album.album_type]].append(album) def sort_section(_section: List[Album], last_albumsort: int) -> int: @@ -599,7 +604,7 @@ class Artist(Base): album_list.extend(sections[section_index]) # replace the old collection with the new one - self.main_album_collection._data = album_list + self.album_collection._data = album_list INDEX_DEPENDS_ON = ("name", "source_collection", "contact_collection") @property @@ -625,8 +630,8 @@ class Artist(Base): r += get_collection_string(self.label_collection, " under {}") r += OPTION_BACKGROUND.value - if len(self.main_album_collection) > 0: - r += f" with {len(self.main_album_collection)} albums" + if len(self.album_collection) > 0: + r += f" with {len(self.album_collection)} albums" r += BColors.ENDC.value diff --git a/music_kraken/pages/bandcamp.py b/music_kraken/pages/bandcamp.py index c938189..2c15bcb 100644 --- a/music_kraken/pages/bandcamp.py +++ b/music_kraken/pages/bandcamp.py @@ -237,7 +237,7 @@ class Bandcamp(Page): html_music_grid = soup.find("ol", {"id": "music-grid"}) if html_music_grid is not None: for subsoup in html_music_grid.find_all("li"): - artist.main_album_collection.append(self._parse_album(soup=subsoup, initial_source=source)) + artist.album_collection.append(self._parse_album(soup=subsoup, initial_source=source)) for i, data_blob_soup in enumerate(soup.find_all("div", {"id": ["pagedata", "collectors-data"]})): data_blob = data_blob_soup["data-blob"] @@ -246,7 +246,7 @@ class Bandcamp(Page): dump_to_file(f"bandcamp_artist_data_blob_{i}.json", data_blob, is_json=True, exit_after_dump=False) if data_blob is not None: - artist.main_album_collection.extend( + artist.album_collection.extend( self._parse_artist_data_blob(json.loads(data_blob), source.url) ) diff --git a/music_kraken/pages/encyclopaedia_metallum.py b/music_kraken/pages/encyclopaedia_metallum.py index 9074e57..0cf313c 100644 --- a/music_kraken/pages/encyclopaedia_metallum.py +++ b/music_kraken/pages/encyclopaedia_metallum.py @@ -663,7 +663,7 @@ class EncyclopaediaMetallum(Page): artist.notes = band_notes discography: List[Album] = self._fetch_artist_discography(artist_id) - artist.main_album_collection.extend(discography) + artist.album_collection.extend(discography) return artist diff --git a/music_kraken/pages/musify.py b/music_kraken/pages/musify.py index 54d849a..e8078fb 100644 --- a/music_kraken/pages/musify.py +++ b/music_kraken/pages/musify.py @@ -1054,7 +1054,7 @@ class Musify(Page): if not self.fetch_options.download_all and album.album_type in self.fetch_options.album_type_blacklist: continue - artist.main_album_collection.append(album) + artist.album_collection.append(album) def fetch_artist(self, source: Source, **kwargs) -> Artist: """ diff --git a/tests/test_collection.py b/tests/test_collection.py index 186e814..98e8695 100644 --- a/tests/test_collection.py +++ b/tests/test_collection.py @@ -37,7 +37,7 @@ class TestCollection(unittest.TestCase): is the same object """ - a = self.complicated_object().main_album_collection[0] + a = self.complicated_object().album_collection[0] b = a.song_collection[0].album_collection[0] c = a.song_collection[1].album_collection[0] d = b.song_collection[0].album_collection[0] @@ -62,9 +62,9 @@ class TestCollection(unittest.TestCase): """ a = self.complicated_object() - b = a.main_album_collection[0].artist_collection[0] - c = b.main_album_collection[0].artist_collection[0] - d = c.main_album_collection[0].artist_collection[0] + b = a.album_collection[0].artist_collection[0] + c = b.album_collection[0].artist_collection[0] + d = c.album_collection[0].artist_collection[0] self.assertTrue(a.id == b.id == c.id == d.id) self.assertTrue(a.name == b.name == c.name == d.name == "artist") @@ -86,7 +86,7 @@ class TestCollection(unittest.TestCase): ] ) - self.assertTrue(artist.id == artist.main_album_collection[0].song_collection[0].artist_collection[0].id) + self.assertTrue(artist.id == artist.album_collection[0].song_collection[0].artist_collection[0].id) def test_artist_collection_sync(self): album_1 = Album( @@ -115,9 +115,9 @@ class TestCollection(unittest.TestCase): def test_song_artist_relations(self): a = self.complicated_object() - b = a.main_album_collection[0].song_collection[0].artist_collection[0] - c = b.main_album_collection[0].song_collection[0].artist_collection[0] - d = c.main_album_collection[0].song_collection[0].artist_collection[0] + b = a.album_collection[0].song_collection[0].artist_collection[0] + c = b.album_collection[0].song_collection[0].artist_collection[0] + d = c.album_collection[0].song_collection[0].artist_collection[0] self.assertTrue(a.id == b.id == c.id == d.id) self.assertTrue(a.name == b.name == c.name == d.name == "artist") From 897897dba2f6981105bc24226a4c99e165550453 Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Thu, 16 May 2024 14:29:50 +0200 Subject: [PATCH 05/15] feat: added recursive structure --- development/objects_collection.py | 2 +- music_kraken/objects/collection.py | 18 +++++++++--------- music_kraken/objects/song.py | 19 ++++++++----------- music_kraken/pages/bandcamp.py | 4 ++-- music_kraken/pages/encyclopaedia_metallum.py | 2 +- music_kraken/pages/youtube.py | 4 ++-- .../pages/youtube_music/_list_render.py | 13 +++++++++++++ .../pages/youtube_music/youtube_music.py | 2 +- tests/test_collection.py | 8 ++++---- 9 files changed, 41 insertions(+), 31 deletions(-) diff --git a/development/objects_collection.py b/development/objects_collection.py index 04e0ba6..8b4f866 100644 --- a/development/objects_collection.py +++ b/development/objects_collection.py @@ -13,7 +13,7 @@ if __name__ == "__main__": song_2 = Song( title = "song", - main_artist_list=[other_artist] + artist_list=[other_artist] ) other_artist.name = "main_artist" diff --git a/music_kraken/objects/collection.py b/music_kraken/objects/collection.py index b058630..d0cd75d 100644 --- a/music_kraken/objects/collection.py +++ b/music_kraken/objects/collection.py @@ -115,13 +115,6 @@ class Collection(Generic[T]): self._data.append(other) other._inner._is_in_collection.add(self) - # all of the existing hooks to get the defined datastructures - for collection_attribute, generator in self.extend_object_to_attribute.items(): - other.__getattribute__(collection_attribute).extend(generator, **kwargs) - - for attribute, new_object in self.append_object_to_attribute.items(): - other.__getattribute__(attribute).append(new_object, **kwargs) - for attribute, a in self.sync_on_append.items(): # syncing two collections by reference b = other.__getattribute__(attribute) @@ -141,6 +134,13 @@ class Collection(Generic[T]): a.extend(b_data, **kwargs) + # all of the existing hooks to get the defined datastructures + for collection_attribute, generator in self.extend_object_to_attribute.items(): + other.__getattribute__(collection_attribute).extend(generator, **kwargs) + + for attribute, new_object in self.append_object_to_attribute.items(): + other.__getattribute__(attribute).append(new_object, **kwargs) + def append(self, other: Optional[T], **kwargs): """ If an object, that represents the same entity exists in a relevant collection, @@ -164,13 +164,13 @@ class Collection(Generic[T]): for c in self.push_to: r = c._find_object(other) if r is not None: - # output("found push to", r, other, c, self, color=BColors.RED, sep="\t") + output("found push to", r, other, c, self, color=BColors.RED, sep="\t") return c.append(other, **kwargs) for c in self.pull_from: r = c._find_object(other) if r is not None: - # output("found pull from", r, other, c, self, color=BColors.RED, sep="\t") + output("found pull from", r, other, c, self, color=BColors.RED, sep="\t") c.remove(r, existing=r, **kwargs) existing = self._find_object(other) diff --git a/music_kraken/objects/song.py b/music_kraken/objects/song.py index bab1ae3..12749c9 100644 --- a/music_kraken/objects/song.py +++ b/music_kraken/objects/song.py @@ -129,7 +129,7 @@ class Song(Base): source_list: List[Source] = None, target_list: List[Target] = None, lyrics_list: List[Lyrics] = None, - main_artist_list: List[Artist] = None, + artist_list: List[Artist] = None, feature_artist_list: List[Artist] = None, album_list: List[Album] = None, tracksort: int = 0, @@ -145,6 +145,9 @@ class Song(Base): TITEL = "title" def __init_collections__(self) -> None: + self.feature_artist_collection.push_to = [self.artist_collection] + self.artist_collection.pull_from = [self.feature_artist_collection] + self.album_collection.sync_on_append = { "artist_collection": self.artist_collection, } @@ -156,14 +159,10 @@ class Song(Base): "album_collection": self.album_collection } - self.album_collection.append_object_to_attribute = { "artist_collection": self } - self.feature_artist_collection.push_to = [self.artist_collection] - self.artist_collection.pull_from = [self.feature_artist_collection] - def _add_other_db_objects(self, object_type: Type[OuterProxy], object_list: List[OuterProxy]): if object_type is Song: return @@ -239,11 +238,6 @@ class Song(Base): return f"{self.tracksort}/{len(self.album_collection[0].song_collection) or 1}" -""" -All objects dependent on Album -""" - - class Album(Base): title: str unified_title: str @@ -311,6 +305,9 @@ class Album(Base): UPWARDS_COLLECTION_STRING_ATTRIBUTES = ("label_collection", "artist_collection") def __init_collections__(self): + self.feature_artist_collection.push_to = [self.artist_collection] + self.artist_collection.pull_from = [self.feature_artist_collection] + self.song_collection.append_object_to_attribute = { "album_collection": self } @@ -515,7 +512,7 @@ class Artist(Base): source_list: List[Source] = None, contact_list: List[Contact] = None, feature_song_list: List[Song] = None, - main_album_list: List[Album] = None, + album_list: List[Album] = None, label_list: List[Label] = None, **kwargs ) -> None: diff --git a/music_kraken/pages/bandcamp.py b/music_kraken/pages/bandcamp.py index 2c15bcb..1caf803 100644 --- a/music_kraken/pages/bandcamp.py +++ b/music_kraken/pages/bandcamp.py @@ -117,7 +117,7 @@ class Bandcamp(Page): return Song( title=clean_song_title(name, artist_name=data["band_name"]), source_list=source_list, - main_artist_list=[ + artist_list=[ Artist( name=data["band_name"], source_list=[ @@ -370,7 +370,7 @@ class Bandcamp(Page): date=ID3Timestamp.strptime(data["datePublished"], "%d %b %Y %H:%M:%S %Z"), source_list=[Source(self.SOURCE_TYPE, album_data["@id"])] )], - main_artist_list=[Artist( + artist_list=[Artist( name=artist_data["name"].strip(), source_list=[Source(self.SOURCE_TYPE, _parse_artist_url(artist_data["@id"]))] )], diff --git a/music_kraken/pages/encyclopaedia_metallum.py b/music_kraken/pages/encyclopaedia_metallum.py index 0cf313c..52d9ea3 100644 --- a/music_kraken/pages/encyclopaedia_metallum.py +++ b/music_kraken/pages/encyclopaedia_metallum.py @@ -52,7 +52,7 @@ def _song_from_json(artist_html=None, album_html=None, release_type=None, title= return Song( title=title, - main_artist_list=[ + artist_list=[ _artist_from_json(artist_html=artist_html) ], album_list=[ diff --git a/music_kraken/pages/youtube.py b/music_kraken/pages/youtube.py index 5f65631..8f21c73 100644 --- a/music_kraken/pages/youtube.py +++ b/music_kraken/pages/youtube.py @@ -143,7 +143,7 @@ class YouTube(SuperYouTube): self.SOURCE_TYPE, get_invidious_url(path="/watch", query=f"v={data['videoId']}") )], notes=FormattedText(html=data["descriptionHtml"] + f"\n

{license_str}" ), - main_artist_list=artist_list + artist_list=artist_list ), int(data["published"]) def fetch_song(self, source: Source, stop_at_level: int = 1) -> Song: @@ -284,7 +284,7 @@ class YouTube(SuperYouTube): self.LOGGER.warning(f"didn't found any playlists with piped, falling back to invidious. (it is unusual)") album_list, artist_name = self.fetch_invidious_album_list(parsed.id) - return Artist(name=artist_name, main_album_list=album_list, source_list=[source]) + return Artist(name=artist_name, album_list=album_list, source_list=[source]) def download_song_to_target(self, source: Source, target: Target, desc: str = None) -> DownloadResult: """ diff --git a/music_kraken/pages/youtube_music/_list_render.py b/music_kraken/pages/youtube_music/_list_render.py index 2158385..7dcc8cf 100644 --- a/music_kraken/pages/youtube_music/_list_render.py +++ b/music_kraken/pages/youtube_music/_list_render.py @@ -58,6 +58,19 @@ def music_responsive_list_item_renderer(renderer: dict) -> List[DatabaseObject]: song.album_collection.extend(album_list) return [song] + if len(album_list) == 1: + album = album_list[0] + album.artist_collection.extend(artist_list) + album.song_collection.extend(song_list) + return [album] + + """ + if len(artist_list) == 1: + artist = artist_list[0] + artist.main_album_collection.extend(album_list) + return [artist] + """ + return results diff --git a/music_kraken/pages/youtube_music/youtube_music.py b/music_kraken/pages/youtube_music/youtube_music.py index 5d9e55c..9dfc44f 100644 --- a/music_kraken/pages/youtube_music/youtube_music.py +++ b/music_kraken/pages/youtube_music/youtube_music.py @@ -639,7 +639,7 @@ class YoutubeMusic(SuperYouTube): album_list=album_list, length=int(ydl_res.get("duration", 0)) * 1000, artwork=Artwork(*ydl_res.get("thumbnails", [])), - main_artist_list=artist_list, + artist_list=artist_list, source_list=[Source( self.SOURCE_TYPE, f"https://music.youtube.com/watch?v={ydl_res.get('id')}" diff --git a/tests/test_collection.py b/tests/test_collection.py index 98e8695..37b795c 100644 --- a/tests/test_collection.py +++ b/tests/test_collection.py @@ -8,7 +8,7 @@ class TestCollection(unittest.TestCase): return Artist( name="artist", country=Country.by_alpha_2("DE"), - main_album_list=[ + album_list=[ Album( title="album", song_list=[ @@ -73,7 +73,7 @@ class TestCollection(unittest.TestCase): def test_artist_artist_relation(self): artist = Artist( name="artist", - main_album_list=[ + album_list=[ Album( title="album", song_list=[ @@ -92,7 +92,7 @@ class TestCollection(unittest.TestCase): album_1 = Album( title="album", song_list=[ - Song(title="song", main_artist_list=[Artist(name="artist")]), + Song(title="song", artist_list=[Artist(name="artist")]), ], artist_list=[ Artist(name="artist"), @@ -102,7 +102,7 @@ class TestCollection(unittest.TestCase): album_2 = Album( title="album", song_list=[ - Song(title="song", main_artist_list=[Artist(name="artist")]), + Song(title="song", artist_list=[Artist(name="artist")]), ], artist_list=[ Artist(name="artist"), From 2c1ac0f12de9d8ce29956474379f3b337d1f935c Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Thu, 16 May 2024 17:09:36 +0200 Subject: [PATCH 06/15] fix: wrong collection --- music_kraken/objects/collection.py | 2 ++ music_kraken/objects/song.py | 15 ++++++++------- music_kraken/utils/shared.py | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/music_kraken/objects/collection.py b/music_kraken/objects/collection.py index d0cd75d..476ab3c 100644 --- a/music_kraken/objects/collection.py +++ b/music_kraken/objects/collection.py @@ -115,6 +115,7 @@ class Collection(Generic[T]): self._data.append(other) other._inner._is_in_collection.add(self) + """ for attribute, a in self.sync_on_append.items(): # syncing two collections by reference b = other.__getattribute__(attribute) @@ -133,6 +134,7 @@ class Collection(Generic[T]): a._collection_for[synced_with] = key a.extend(b_data, **kwargs) + """ # all of the existing hooks to get the defined datastructures for collection_attribute, generator in self.extend_object_to_attribute.items(): diff --git a/music_kraken/objects/song.py b/music_kraken/objects/song.py index 12749c9..9e95604 100644 --- a/music_kraken/objects/song.py +++ b/music_kraken/objects/song.py @@ -148,7 +148,7 @@ class Song(Base): self.feature_artist_collection.push_to = [self.artist_collection] self.artist_collection.pull_from = [self.feature_artist_collection] - self.album_collection.sync_on_append = { + self.album_collection.extend_object_to_attribute = { "artist_collection": self.artist_collection, } @@ -159,10 +159,6 @@ class Song(Base): "album_collection": self.album_collection } - self.album_collection.append_object_to_attribute = { - "artist_collection": self - } - def _add_other_db_objects(self, object_type: Type[OuterProxy], object_list: List[OuterProxy]): if object_type is Song: return @@ -223,7 +219,7 @@ class Song(Base): r = OPTION_FOREGROUND.value + self.title_string + BColors.ENDC.value + OPTION_BACKGROUND.value r += get_collection_string(self.album_collection, " from {}", ignore_titles={self.title}) r += get_collection_string(self.artist_collection, " by {}") - r += get_collection_string(self.feature_artist_collection, " feat. {}") + r += get_collection_string(self.feature_artist_collection, " feat. {}" if len(self.artist_collection) > 0 else " by {}") return r @property @@ -311,7 +307,7 @@ class Album(Base): self.song_collection.append_object_to_attribute = { "album_collection": self } - self.song_collection.sync_on_append = { + self.song_collection.extend_object_to_attribute = { "artist_collection": self.artist_collection } @@ -372,6 +368,7 @@ class Album(Base): def option_string(self) -> str: r = OPTION_FOREGROUND.value + self.title_string + BColors.ENDC.value + OPTION_BACKGROUND.value r += get_collection_string(self.artist_collection, " by {}") + r += get_collection_string(self.feature_artist_collection, " feat. {}" if len(self.artist_collection) > 0 else " by {}") r += get_collection_string(self.label_collection, " under {}") if len(self.song_collection) > 0: @@ -526,6 +523,10 @@ class Artist(Base): UPWARDS_COLLECTION_STRING_ATTRIBUTES = ("label_collection",) def __init_collections__(self): + self.album_collection.append_object_to_attribute = { + "feature_artist_collection": self + } + self.label_collection.append_object_to_attribute = { "current_artist_collection": self } diff --git a/music_kraken/utils/shared.py b/music_kraken/utils/shared.py index 5f87876..2a5d4a4 100644 --- a/music_kraken/utils/shared.py +++ b/music_kraken/utils/shared.py @@ -12,10 +12,10 @@ if not load_dotenv(Path(__file__).parent.parent.parent / ".env"): __stage__ = os.getenv("STAGE", "prod") -DEBUG = (__stage__ == "dev") and False +DEBUG = (__stage__ == "dev") and True DEBUG_LOGGING = DEBUG and False DEBUG_TRACE = DEBUG and True -DEBUG_OBJECT_TRACE = DEBUG and False +DEBUG_OBJECT_TRACE = DEBUG and True DEBUG_OBJECT_TRACE_CALLSTACK = DEBUG_OBJECT_TRACE and False DEBUG_YOUTUBE_INITIALIZING = DEBUG and False DEBUG_PAGES = DEBUG and False From a70a24d93eed35fa01b996073734cc0cde3733ff Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Thu, 16 May 2024 17:14:18 +0200 Subject: [PATCH 07/15] feat: minor adjustments --- music_kraken/objects/collection.py | 4 ++-- music_kraken/objects/song.py | 3 +++ music_kraken/utils/shared.py | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/music_kraken/objects/collection.py b/music_kraken/objects/collection.py index 476ab3c..466d84b 100644 --- a/music_kraken/objects/collection.py +++ b/music_kraken/objects/collection.py @@ -166,13 +166,13 @@ class Collection(Generic[T]): for c in self.push_to: r = c._find_object(other) if r is not None: - output("found push to", r, other, c, self, color=BColors.RED, sep="\t") + # output("found push to", r, other, c, self, color=BColors.RED, sep="\t") return c.append(other, **kwargs) for c in self.pull_from: r = c._find_object(other) if r is not None: - output("found pull from", r, other, c, self, color=BColors.RED, sep="\t") + # output("found pull from", r, other, c, self, color=BColors.RED, sep="\t") c.remove(r, existing=r, **kwargs) existing = self._find_object(other) diff --git a/music_kraken/objects/song.py b/music_kraken/objects/song.py index 9e95604..18a29cd 100644 --- a/music_kraken/objects/song.py +++ b/music_kraken/objects/song.py @@ -158,6 +158,9 @@ class Song(Base): self.artist_collection.extend_object_to_attribute = { "album_collection": self.album_collection } + self.feature_artist_collection.extend_object_to_attribute = { + "album_collection": self.album_collection + } def _add_other_db_objects(self, object_type: Type[OuterProxy], object_list: List[OuterProxy]): if object_type is Song: diff --git a/music_kraken/utils/shared.py b/music_kraken/utils/shared.py index 2a5d4a4..8f671f9 100644 --- a/music_kraken/utils/shared.py +++ b/music_kraken/utils/shared.py @@ -15,7 +15,7 @@ __stage__ = os.getenv("STAGE", "prod") DEBUG = (__stage__ == "dev") and True DEBUG_LOGGING = DEBUG and False DEBUG_TRACE = DEBUG and True -DEBUG_OBJECT_TRACE = DEBUG and True +DEBUG_OBJECT_TRACE = DEBUG and False DEBUG_OBJECT_TRACE_CALLSTACK = DEBUG_OBJECT_TRACE and False DEBUG_YOUTUBE_INITIALIZING = DEBUG and False DEBUG_PAGES = DEBUG and False From 86e985acece6b2aa79e64c2782109ae275eaa636 Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Thu, 16 May 2024 17:30:53 +0200 Subject: [PATCH 08/15] fix: files don't contain id anymore --- music_kraken/download/page_attributes.py | 6 +++--- music_kraken/objects/parents.py | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/music_kraken/download/page_attributes.py b/music_kraken/download/page_attributes.py index fbf6982..997960d 100644 --- a/music_kraken/download/page_attributes.py +++ b/music_kraken/download/page_attributes.py @@ -235,14 +235,14 @@ class Pages: # manage the naming naming: Dict[str, List[str]] = defaultdict(list, naming) - naming["song"].append(song.title_string) + naming["song"].append(song.title_value) naming["isrc"].append(song.isrc) - naming["album"].extend(a.title_string for a in song.album_collection) + naming["album"].extend(a.title_value for a in song.album_collection) naming["album_type"].extend(a.album_type.value for a in song.album_collection) naming["artist"].extend(a.name for a in song.artist_collection) naming["artist"].extend(a.name for a in song.feature_artist_collection) for a in song.album_collection: - naming["label"].extend([l.title_string for l in a.label_collection]) + naming["label"].extend([l.title_value for l in a.label_collection]) # removing duplicates from the naming, and process the strings for key, value in naming.items(): # https://stackoverflow.com/a/17016257 diff --git a/music_kraken/objects/parents.py b/music_kraken/objects/parents.py index 16ebe6a..af74836 100644 --- a/music_kraken/objects/parents.py +++ b/music_kraken/objects/parents.py @@ -339,6 +339,10 @@ class OuterProxy: def title_string(self) -> str: return str(self.__getattribute__(self.TITEL)) + (f" {self.id}" if DEBUG_PRINT_ID else "") + @property + def title_value(self) -> str: + return str(self.__getattribute__(self.TITEL)) + def __repr__(self): return f"{type(self).__name__}({self.title_string})" From e87075a8097b83838f049b6f0504ff25d0bc809f Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Thu, 16 May 2024 17:39:12 +0200 Subject: [PATCH 09/15] feat: changed syncing from event based to reference --- music_kraken/objects/collection.py | 19 +++++++++++++++++++ music_kraken/objects/song.py | 4 ++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/music_kraken/objects/collection.py b/music_kraken/objects/collection.py index 466d84b..2e68f54 100644 --- a/music_kraken/objects/collection.py +++ b/music_kraken/objects/collection.py @@ -162,6 +162,25 @@ class Collection(Generic[T]): object_trace(f"Appending {other.option_string} to {self}") + for attribute, a in self.sync_on_append.items(): + # syncing two collections by reference + b = other.__getattribute__(attribute) + if a is b: + continue + + object_trace(f"Syncing [{a}] = [{b}]") + + b_data = b.data.copy() + b_collection_for = b._collection_for.copy() + + del b + + for synced_with, key in b_collection_for.items(): + synced_with.__setattr__(key, a) + a._collection_for[synced_with] = key + + a.extend(b_data, **kwargs) + # switching collection in the case of push to for c in self.push_to: r = c._find_object(other) diff --git a/music_kraken/objects/song.py b/music_kraken/objects/song.py index 18a29cd..2aa8438 100644 --- a/music_kraken/objects/song.py +++ b/music_kraken/objects/song.py @@ -148,7 +148,7 @@ class Song(Base): self.feature_artist_collection.push_to = [self.artist_collection] self.artist_collection.pull_from = [self.feature_artist_collection] - self.album_collection.extend_object_to_attribute = { + self.album_collection.sync_on_append = { "artist_collection": self.artist_collection, } @@ -310,7 +310,7 @@ class Album(Base): self.song_collection.append_object_to_attribute = { "album_collection": self } - self.song_collection.extend_object_to_attribute = { + self.song_collection.sync_on_append = { "artist_collection": self.artist_collection } From 3cb35909d1eaf8818924a79da398cf2a6eb5731d Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Fri, 17 May 2024 13:31:46 +0200 Subject: [PATCH 10/15] feat: added option to just fetch the objects in select --- music_kraken/cli/main_downloader.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/music_kraken/cli/main_downloader.py b/music_kraken/cli/main_downloader.py index 38d20cf..b443ac0 100644 --- a/music_kraken/cli/main_downloader.py +++ b/music_kraken/cli/main_downloader.py @@ -354,14 +354,12 @@ class Downloader: command, query = _[0], ":".join(_[1:]) do_search = "s" in command + do_fetch = "f" in command do_download = "d" in command do_merge = "m" in command - if do_search and do_download: - raise MKInvalidInputException(message="You can't search and download at the same time.") - - if do_search and do_merge: - raise MKInvalidInputException(message="You can't search and merge at the same time.") + if do_search and (do_download or do_fetch or do_merge): + raise MKInvalidInputException(message="You can't search and do another operation at the same time.") if do_search: self.search(":".join(input_str.split(":")[1:])) @@ -397,6 +395,13 @@ class Downloader: selected_objects = [a] + if do_fetch: + for data_object in selected_objects: + self.pages.fetch_details(data_object) + + self.print_current_options() + return False + if do_download: self.download(selected_objects) return False From ab61ff7e9b230f27e056f4653c7aea86aed47fee Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Fri, 17 May 2024 13:37:49 +0200 Subject: [PATCH 11/15] feat: added the option to select all at options at the same time --- music_kraken/cli/main_downloader.py | 38 +++++++++++++++++------------ 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/music_kraken/cli/main_downloader.py b/music_kraken/cli/main_downloader.py index b443ac0..c5ba8a9 100644 --- a/music_kraken/cli/main_downloader.py +++ b/music_kraken/cli/main_downloader.py @@ -365,24 +365,30 @@ class Downloader: self.search(":".join(input_str.split(":")[1:])) return False - indices = [] - for possible_index in query.split(","): - possible_index = possible_index.strip() - if possible_index == "": - continue - - i = 0 - try: - i = int(possible_index) - except ValueError: - raise MKInvalidInputException(message=f"The index \"{possible_index}\" is not a number.") + def get_selected_objects(q: str): + if q.strip().lower() == "all": + return list(self.current_results) - if i < 0 or i >= len(self.current_results): - raise MKInvalidInputException(message=f"The index \"{i}\" is not within the bounds of 0-{len(self.current_results) - 1}.") - - indices.append(i) + indices = [] + for possible_index in q.split(","): + possible_index = possible_index.strip() + if possible_index == "": + continue + + i = 0 + try: + i = int(possible_index) + except ValueError: + raise MKInvalidInputException(message=f"The index \"{possible_index}\" is not a number.") - selected_objects = [self.current_results[i] for i in indices] + if i < 0 or i >= len(self.current_results): + raise MKInvalidInputException(message=f"The index \"{i}\" is not within the bounds of 0-{len(self.current_results) - 1}.") + + indices.append(i) + + return [self.current_results[i] for i in indices] + + selected_objects = get_selected_objects(query) if do_merge: old_selected_objects = selected_objects From 83a3334f1a760ce530202a7c6e237f1d2fe97d61 Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Fri, 17 May 2024 13:55:58 +0200 Subject: [PATCH 12/15] changed default value --- music_kraken/utils/config/config_files/main_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/music_kraken/utils/config/config_files/main_config.py b/music_kraken/utils/config/config_files/main_config.py index bae8618..decdf3b 100644 --- a/music_kraken/utils/config/config_files/main_config.py +++ b/music_kraken/utils/config/config_files/main_config.py @@ -19,7 +19,7 @@ config = Config(( You can use Audio formats which support ID3.2 and ID3.1, but you will have cleaner Metadata using ID3.2."""), - Attribute(name="result_history", default_value=False, description="""If enabled, you can go back to the previous results. + Attribute(name="result_history", default_value=True, description="""If enabled, you can go back to the previous results. The consequence is a higher meory consumption, because every result is saved."""), Attribute(name="history_length", default_value=8, description="""You can choose how far back you can go in the result history. The further you choose to be able to go back, the higher the memory usage. From 000a6c0dbaaa321cf528b7db662eccdd693a7fdf Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Fri, 17 May 2024 18:24:56 +0200 Subject: [PATCH 13/15] feat: added type identifier to option strings --- music_kraken/objects/song.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/music_kraken/objects/song.py b/music_kraken/objects/song.py index 2aa8438..980bc08 100644 --- a/music_kraken/objects/song.py +++ b/music_kraken/objects/song.py @@ -219,7 +219,8 @@ class Song(Base): @property def option_string(self) -> str: - r = OPTION_FOREGROUND.value + self.title_string + BColors.ENDC.value + OPTION_BACKGROUND.value + r = "song " + r += OPTION_FOREGROUND.value + self.title_string + BColors.ENDC.value + OPTION_BACKGROUND.value r += get_collection_string(self.album_collection, " from {}", ignore_titles={self.title}) r += get_collection_string(self.artist_collection, " by {}") r += get_collection_string(self.feature_artist_collection, " feat. {}" if len(self.artist_collection) > 0 else " by {}") @@ -369,9 +370,11 @@ class Album(Base): @property def option_string(self) -> str: - r = OPTION_FOREGROUND.value + self.title_string + BColors.ENDC.value + OPTION_BACKGROUND.value + r = "album " + r += OPTION_FOREGROUND.value + self.title_string + BColors.ENDC.value + OPTION_BACKGROUND.value r += get_collection_string(self.artist_collection, " by {}") - r += get_collection_string(self.feature_artist_collection, " feat. {}" if len(self.artist_collection) > 0 else " by {}") + if len(self.artist_collection) <= 0: + r += get_collection_string(self.feature_artist_collection, " by {}") r += get_collection_string(self.label_collection, " under {}") if len(self.song_collection) > 0: @@ -627,7 +630,8 @@ class Artist(Base): @property def option_string(self) -> str: - r = OPTION_FOREGROUND.value + self.title_string + BColors.ENDC.value + OPTION_BACKGROUND.value + r = "artist " + r += OPTION_FOREGROUND.value + self.title_string + BColors.ENDC.value + OPTION_BACKGROUND.value r += get_collection_string(self.label_collection, " under {}") r += OPTION_BACKGROUND.value @@ -720,4 +724,4 @@ class Label(Base): @property def option_string(self): - return OPTION_FOREGROUND.value + self.name + BColors.ENDC.value + return "label " + OPTION_FOREGROUND.value + self.name + BColors.ENDC.value From 356ba658cee53c6d04d5f3460beaad17c86fc6c6 Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Tue, 21 May 2024 13:37:26 +0200 Subject: [PATCH 14/15] fix: lyrics enpoint could crash the whole program --- music_kraken/pages/youtube_music/youtube_music.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/music_kraken/pages/youtube_music/youtube_music.py b/music_kraken/pages/youtube_music/youtube_music.py index 9dfc44f..3dc8fc9 100644 --- a/music_kraken/pages/youtube_music/youtube_music.py +++ b/music_kraken/pages/youtube_music/youtube_music.py @@ -589,6 +589,8 @@ class YoutubeMusic(SuperYouTube): }, name=f"fetch_song_lyrics_{video_id}.json" ) + if r is None: + return None dump_to_file(f"fetch_song_lyrics_{video_id}.json", r.text, is_json=True, exit_after_dump=False) From 8cdb5c1f996ee115cfe07ae9e086cabc08a5b55f Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Tue, 21 May 2024 13:52:20 +0200 Subject: [PATCH 15/15] fix: tests were a mess and didn't properly test the functionality but random things that worked with implementation --- music_kraken/objects/collection.py | 20 ----- music_kraken/utils/shared.py | 2 +- tests/test_collection.py | 138 ++++++++++++++--------------- 3 files changed, 66 insertions(+), 94 deletions(-) diff --git a/music_kraken/objects/collection.py b/music_kraken/objects/collection.py index 2e68f54..f1d7e75 100644 --- a/music_kraken/objects/collection.py +++ b/music_kraken/objects/collection.py @@ -115,7 +115,6 @@ class Collection(Generic[T]): self._data.append(other) other._inner._is_in_collection.add(self) - """ for attribute, a in self.sync_on_append.items(): # syncing two collections by reference b = other.__getattribute__(attribute) @@ -134,7 +133,6 @@ class Collection(Generic[T]): a._collection_for[synced_with] = key a.extend(b_data, **kwargs) - """ # all of the existing hooks to get the defined datastructures for collection_attribute, generator in self.extend_object_to_attribute.items(): @@ -162,24 +160,6 @@ class Collection(Generic[T]): object_trace(f"Appending {other.option_string} to {self}") - for attribute, a in self.sync_on_append.items(): - # syncing two collections by reference - b = other.__getattribute__(attribute) - if a is b: - continue - - object_trace(f"Syncing [{a}] = [{b}]") - - b_data = b.data.copy() - b_collection_for = b._collection_for.copy() - - del b - - for synced_with, key in b_collection_for.items(): - synced_with.__setattr__(key, a) - a._collection_for[synced_with] = key - - a.extend(b_data, **kwargs) # switching collection in the case of push to for c in self.push_to: diff --git a/music_kraken/utils/shared.py b/music_kraken/utils/shared.py index 8f671f9..2a5d4a4 100644 --- a/music_kraken/utils/shared.py +++ b/music_kraken/utils/shared.py @@ -15,7 +15,7 @@ __stage__ = os.getenv("STAGE", "prod") DEBUG = (__stage__ == "dev") and True DEBUG_LOGGING = DEBUG and False DEBUG_TRACE = DEBUG and True -DEBUG_OBJECT_TRACE = DEBUG and False +DEBUG_OBJECT_TRACE = DEBUG and True DEBUG_OBJECT_TRACE_CALLSTACK = DEBUG_OBJECT_TRACE and False DEBUG_YOUTUBE_INITIALIZING = DEBUG and False DEBUG_PAGES = DEBUG and False diff --git a/tests/test_collection.py b/tests/test_collection.py index 37b795c..7dfb29e 100644 --- a/tests/test_collection.py +++ b/tests/test_collection.py @@ -3,92 +3,94 @@ import unittest from music_kraken.objects import Song, Album, Artist, Collection, Country class TestCollection(unittest.TestCase): - @staticmethod - def complicated_object() -> Artist: - return Artist( - name="artist", - country=Country.by_alpha_2("DE"), - album_list=[ - Album( - title="album", - song_list=[ - Song( - title="song", - album_list=[ - Album(title="album", albumsort=123), - ], - ), - Song( - title="other_song", - album_list=[ - Album(title="album", albumsort=423), - ], - ), - ] - ), - Album(title="album", barcode="1234567890123"), + def test_song_contains_album(self): + """ + Tests that every song contains the album it is added to in its album_collection + """ + + a_1 = Album( + title="album", + song_list= [ + Song(title="song"), ] ) + a_2 = a_1.song_collection[0].album_collection[0] + self.assertTrue(a_1.id == a_2.id) - def test_song_album_relation(self): + def test_album_contains_song(self): """ - Tests that - album = album.any_song.one_album - is the same object + Tests that every album contains the song it is added to in its song_collection + """ + s_1 = Song( + title="song", + album_list=[ + Album(title="album"), + ] + ) + s_2 = s_1.album_collection[0].song_collection[0] + self.assertTrue(s_1.id == s_2.id) + + + def test_auto_add_artist_to_album_feature_artist(self): + """ + Tests that every artist is added to the album's feature_artist_collection per default """ - a = self.complicated_object().album_collection[0] - b = a.song_collection[0].album_collection[0] - c = a.song_collection[1].album_collection[0] - d = b.song_collection[0].album_collection[0] - e = d.song_collection[0].album_collection[0] - f = e.song_collection[0].album_collection[0] - g = f.song_collection[0].album_collection[0] + a_1 = Artist( + name="artist", + album_list=[ + Album(title="album") + ] + ) + a_2 = a_1.album_collection[0].feature_artist_collection[0] - self.assertTrue(a.id == b.id == c.id == d.id == e.id == f.id == g.id) - self.assertTrue(a.title == b.title == c.title == d.title == e.title == f.title == g.title == "album") - self.assertTrue(a.barcode == b.barcode == c.barcode == d.barcode == e.barcode == f.barcode == g.barcode == "1234567890123") - self.assertTrue(a.albumsort == b.albumsort == c.albumsort == d.albumsort == e.albumsort == f.albumsort == g.albumsort == 123) - - d.title = "new_title" - - self.assertTrue(a.title == b.title == c.title == d.title == e.title == f.title == g.title == "new_title") - - def test_album_artist_relation(self): + self.assertTrue(a_1.id == a_2.id) + + def test_auto_add_artist_to_album_feature_artist_push(self): """ - Tests that - artist = artist.any_album.any_song.one_artist - is the same object + Tests that every artist is added to the album's feature_artist_collection per default but pulled into the album's artist_collection if a merge exitst """ - a = self.complicated_object() - b = a.album_collection[0].artist_collection[0] - c = b.album_collection[0].artist_collection[0] - d = c.album_collection[0].artist_collection[0] - - self.assertTrue(a.id == b.id == c.id == d.id) - self.assertTrue(a.name == b.name == c.name == d.name == "artist") - self.assertTrue(a.country == b.country == c.country == d.country) - - def test_artist_artist_relation(self): - artist = Artist( + a_1 = Artist( name="artist", album_list=[ Album( title="album", - song_list=[ - Song(title="song"), - ], artist_list=[ Artist(name="artist"), ] ) ] ) + a_2 = a_1.album_collection[0].artist_collection[0] - self.assertTrue(artist.id == artist.album_collection[0].song_collection[0].artist_collection[0].id) + self.assertTrue(a_1.id == a_2.id) + + + def test_artist_artist_relation(self): + """ + Tests the proper syncing between album.artist_collection and song.artist_collection + """ + + album = Album( + title="album", + song_list=[ + Song(title="song"), + ], + artist_list=[ + Artist(name="artist"), + ] + ) + a_1 = album.artist_collection[0] + a_2 = album.song_collection[0].artist_collection[0] + + self.assertTrue(a_1.id == a_2.id) def test_artist_collection_sync(self): + """ + tests the actual implementation of the test above + """ + album_1 = Album( title="album", song_list=[ @@ -113,15 +115,5 @@ class TestCollection(unittest.TestCase): self.assertTrue(id(album_1.artist_collection) == id(album_1.artist_collection) == id(album_1.song_collection[0].artist_collection) == id(album_1.song_collection[0].artist_collection)) - def test_song_artist_relations(self): - a = self.complicated_object() - b = a.album_collection[0].song_collection[0].artist_collection[0] - c = b.album_collection[0].song_collection[0].artist_collection[0] - d = c.album_collection[0].song_collection[0].artist_collection[0] - - self.assertTrue(a.id == b.id == c.id == d.id) - self.assertTrue(a.name == b.name == c.name == d.name == "artist") - self.assertTrue(a.country == b.country == c.country == d.country) - if __name__ == "__main__": unittest.main()