From fb8a89dbbd6f01e6b8bdb09e209be65e54bfbffb Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Mon, 30 Jan 2023 14:41:02 +0100 Subject: [PATCH] finished refactoring metadata --- src/create_custom_objects.py | 96 +++++++----------- src/music_kraken/database/__init__.py | 1 - src/music_kraken/database/new_database.py | 3 +- src/music_kraken/database/objects/__init__.py | 3 +- src/music_kraken/database/objects/metadata.py | 26 +++-- src/music_kraken/database/objects/song.py | 54 +++++----- src/music_kraken/database/objects/source.py | 39 ++++--- test.db | Bin 65536 -> 65536 bytes 8 files changed, 106 insertions(+), 116 deletions(-) diff --git a/src/create_custom_objects.py b/src/create_custom_objects.py index 35fa00f..1a280d3 100644 --- a/src/create_custom_objects.py +++ b/src/create_custom_objects.py @@ -29,39 +29,21 @@ def div(msg: str = ""): cache = music_kraken.database.new_database.Database("test.db") cache.reset() +def print_song(song_: Song): -main_artist = Artist( - name="I'm in a coffin", - sources=[ - Source(SourcePages.ENCYCLOPAEDIA_METALLUM, "https://www.metal-archives.com/bands/I%27m_in_a_Coffin/127727") - ] -) -artist_ref = main_artist.reference + print("tracksort", song_.tracksort, sep=": ") + # print("ID3", song_.metadata) + print(str(song_.metadata)) + print("----src----") + print("song:") + print(song_.source_list) + print("album:") + print(song_.album.source_list) + print("\n") -split_artist = Artist( - name="split" -) -feature_artist = Artist( - name="Ghost" -) - -album_input = Album( - title="One Final Action", - date=ID3Timestamp(year=1986, month=3, day=1), - language=pycountry.languages.get(alpha_2="en"), - label="cum productions", - sources=[ - Source(SourcePages.ENCYCLOPAEDIA_METALLUM, "https://www.metal-archives.com/albums/I%27m_in_a_Coffin/One_Final_Action/207614") - ] -) -album_input.artists = [ - main_artist, - split_artist -] - -song_input = Song( +song = Song( genre="HS Core", title="Vein Deep in the Solution", length=666, @@ -70,50 +52,48 @@ song_input = Song( target=Target(file="song.mp3", path="~/Music"), lyrics=[ Lyrics(text="these are some depressive lyrics", language="en"), - Lyrics(text="test", language="en") + Lyrics(text="Dies sind depressive Lyrics", language="de") ], - sources=[ + source_list=[ Source(SourcePages.YOUTUBE, "https://youtu.be/dfnsdajlhkjhsd"), Source(SourcePages.MUSIFY, "https://ln.topdf.de/Music-Kraken/") ], - album=album_input, - main_artist_list=[main_artist], - feature_artist_list=[feature_artist], + album=Album( + title="One Final Action", + date=ID3Timestamp(year=1986, month=3, day=1), + language=pycountry.languages.get(alpha_2="en"), + label="cum productions", + source_list=[ + Source(SourcePages.ENCYCLOPAEDIA_METALLUM, "https://www.metal-archives.com/albums/I%27m_in_a_Coffin/One_Final_Action/207614") + ] + ), + main_artist_list=[ + Artist( + name="I'm in a coffin", + source_list=[ + Source(SourcePages.ENCYCLOPAEDIA_METALLUM, "https://www.metal-archives.com/bands/I%27m_in_a_Coffin/127727") + ] + ), + Artist(name="some_split_artist") + ], + feature_artist_list=[Artist(name="Ruffiction")], ) -other_song = Song( - title="this is just another song", - main_artist_list=[feature_artist], - feature_artist_list=[main_artist] -) +print_song(song) -print(song_input) +exit() -additional_song = Song( - title="A fcking Song", - album=album_input -) +song_ref = song.reference -song_ref = song_input.reference -print(song_ref) +cache.push([song]) -lyrics = Lyrics(text="these are some Lyrics that don't belong to any Song", language="en") -cache.push([album_input, song_input, lyrics, additional_song, other_song]) # getting song by song ref div() -song_output_list = cache.pull_songs(song_ref=song_ref) -print(len(song_output_list), song_output_list, song_output_list[0].album, sep=" | ") -song = song_output_list[0] -print("tracksort", song_output_list[0].tracksort, sep=": ") -print("ID3", dict(song.metadata)) -print(str(song_output_list[0].metadata)) -print("--src--") -for source in song.sources: - print(source) +song_list = cache.pull_songs(song_ref=song_ref) +song_from_db = song_list[0] -print("album", song.album.sources) # try writing metadata write_metadata(song) diff --git a/src/music_kraken/database/__init__.py b/src/music_kraken/database/__init__.py index 067bb79..276edb1 100644 --- a/src/music_kraken/database/__init__.py +++ b/src/music_kraken/database/__init__.py @@ -11,7 +11,6 @@ SourcePages = objects.SourcePages Song = objects.Song Source = objects.Source Target = objects.Target -Metadata = objects.Metadata Lyrics = objects.Lyrics Album = objects.Album diff --git a/src/music_kraken/database/new_database.py b/src/music_kraken/database/new_database.py index 6d12a95..39e0054 100644 --- a/src/music_kraken/database/new_database.py +++ b/src/music_kraken/database/new_database.py @@ -11,7 +11,6 @@ from .objects.source import Source from .objects import ( Song, Lyrics, - Metadata, Target, Artist, Album, @@ -187,7 +186,7 @@ class Database: self.connection.commit() # add sources - for source in song.sources: + for source in song.source_list: source.add_song(song) source.type_enum = SourceTypes.SONG self.push_source(source=source) diff --git a/src/music_kraken/database/objects/__init__.py b/src/music_kraken/database/objects/__init__.py index 2fdc545..a33e3e9 100644 --- a/src/music_kraken/database/objects/__init__.py +++ b/src/music_kraken/database/objects/__init__.py @@ -7,7 +7,7 @@ from . import ( MusicObject = parents.DatabaseObject -ID3_MAPPING = metadata.Mapping +ID3Mapping = metadata.Mapping ID3Timestamp = metadata.ID3Timestamp SourceTypes = source.SourceTypes @@ -17,7 +17,6 @@ Song = song.Song Artist = song.Artist Source = source.Source Target = song.Target -Metadata = song.Metadata Lyrics = song.Lyrics Album = song.Album diff --git a/src/music_kraken/database/objects/metadata.py b/src/music_kraken/database/objects/metadata.py index 04b2d73..caba7ad 100644 --- a/src/music_kraken/database/objects/metadata.py +++ b/src/music_kraken/database/objects/metadata.py @@ -259,10 +259,11 @@ class MetadataAttribute: # the key is an enum from Mapping # the value is a list with each value # the mutagen object for each frame will be generated dynamically - id3_dict: Dict[any, list] = dict() + id3_dict: Dict[any, list] def __init__(self, id3_dict: Dict[any, list] = None) -> None: + self.id3_dict = dict() if id3_dict is not None: self.add_metadata_dict(id3_dict) @@ -284,7 +285,7 @@ class MetadataAttribute: self.id3_dict[frame] = new_val return - self.id3_attributes[frame].extend(new_val) + self.id3_dict[frame].extend(new_val) def __getitem__(self, key): if key not in self.id3_dict: @@ -298,23 +299,28 @@ class MetadataAttribute: def add_metadata_dict(self, metadata_dict: dict, override_existing: bool = True): for field_enum, value in metadata_dict.items(): - self.__setitem__(field_enum.value, value, override_existing=override_existing) + self.__setitem__(field_enum, value, override_existing=override_existing) def merge(self, other, override_existing: bool = False): """ adds the values of another metadata obj to this one + + other is a value of the type MetadataAttribute.Metadata """ + self.add_metadata_dict(other.id3_dict, override_existing=override_existing) def merge_many(self, many_other): """ adds the values of many other metadata objects to this one """ + for other in many_other: self.merge(other) + def get_id3_value(self, field): - if field not in self.id3_attributes: + if field not in self.id3_dict: return None list_data = self.id3_dict[field] @@ -335,7 +341,7 @@ class MetadataAttribute: else I take the first element """ if field.value[0].upper() == "T" and field.value.upper() != "TXXX": - return self.null_byte.join(list_data) + return self.NULL_BYTE.join(list_data) return list_data[0] @@ -344,7 +350,7 @@ class MetadataAttribute: def __str__(self) -> str: rows = [] - for key, value in self.id3_attributes.items(): + for key, value in self.id3_dict.items(): rows.append(f"{key} - {str(value)}") return "\n".join(rows) @@ -355,15 +361,15 @@ class MetadataAttribute: to directly tagg a file with id3 container. """ # set the tagging timestamp to the current time - self.__setitem__(Mapping.TAGGING_TIME.value, [ID3Timestamp.now()]) + self.__setitem__(Mapping.TAGGING_TIME, [ID3Timestamp.now()]) - for field in self.id3_attributes: + for field in self.id3_dict: yield self.get_mutagen_object(field) def get_metadata(self) -> Metadata: """ this is intendet to be overwritten by the child class """ - return self.Metadata() + return MetadataAttribute.Metadata() - metadata = property(fget=get_metadata) + metadata = property(fget=lambda self: self.get_metadata()) diff --git a/src/music_kraken/database/objects/song.py b/src/music_kraken/database/objects/song.py index 154d0a1..bba7241 100644 --- a/src/music_kraken/database/objects/song.py +++ b/src/music_kraken/database/objects/song.py @@ -5,8 +5,8 @@ import pycountry from .metadata import ( Mapping as ID3_MAPPING, - Metadata, - ID3Timestamp + ID3Timestamp, + MetadataAttribute ) from ...utils.shared import ( MUSIC_DIR, @@ -80,7 +80,7 @@ class Target(DatabaseObject, SongAttribute): exists_on_disc = property(fget=get_exists_on_disc) -class Lyrics(DatabaseObject, SongAttribute, SourceAttribute): +class Lyrics(DatabaseObject, SongAttribute, SourceAttribute, MetadataAttribute): def __init__( self, text: str, @@ -96,8 +96,11 @@ class Lyrics(DatabaseObject, SongAttribute, SourceAttribute): if source_list is not None: self.source_list = source_list + def get_metadata(self) -> MetadataAttribute.Metadata: + return super().get_metadata() -class Song(DatabaseObject, ID3Metadata, SourceAttribute): + +class Song(DatabaseObject, SourceAttribute, MetadataAttribute): def __init__( self, id_: str = None, @@ -186,26 +189,23 @@ class Song(DatabaseObject, ID3Metadata, SourceAttribute): return None return self.album.id - def get_id3_dict(self) -> dict: - return { + def get_metadata(self) -> MetadataAttribute.Metadata: + metadata = MetadataAttribute.Metadata({ ID3_MAPPING.TITLE: [self.title], ID3_MAPPING.ISRC: [self.isrc], ID3_MAPPING.LENGTH: [str(self.length)], ID3_MAPPING.GENRE: [self.genre] - } - - def get_metadata(self) -> Metadata: - metadata = Metadata(self.get_id3_dict()) + }) - metadata.add_many_metadata_dict([source.get_id3_dict() for source in self.source_list]) + metadata.merge_many([s.get_song_metadata() for s in self.source_list]) if self.album is not None: - metadata.add_metadata_dict(self.album.get_id3_dict()) - metadata.add_many_metadata_dict([artist.get_id3_dict() for artist in self.main_artist_list]) - metadata.add_many_metadata_dict([artist.get_id3_dict() for artist in self.feature_artist_list]) - + metadata.merge(self.album.metadata) + metadata.merge_many([a.metadata for a in self.main_artist_list]) + metadata.merge_many([a.metadata for a in self.feature_artist_list]) + metadata.merge_many([l.metadata for l in self.lyrics]) return metadata + - metadata = property(fget=get_metadata) """ @@ -213,7 +213,7 @@ All objects dependent on Album """ -class Album(DatabaseObject, ID3Metadata, SourceAttribute): +class Album(DatabaseObject, SourceAttribute, MetadataAttribute): """ -------DB-FIELDS------- title TEXT, @@ -292,14 +292,14 @@ class Album(DatabaseObject, ID3Metadata, SourceAttribute): song.tracksort = len(self.tracklist) self.tracklist.append(song) - def get_id3_dict(self) -> dict: - return { + def get_metadata(self) -> MetadataAttribute.Metadata: + return MetadataAttribute.Metadata({ ID3_MAPPING.ALBUM: [self.title], ID3_MAPPING.COPYRIGHT: [self.copyright], ID3_MAPPING.LANGUAGE: [self.iso_639_2_language], ID3_MAPPING.ALBUM_ARTIST: [a.name for a in self.artists], ID3_MAPPING.DATE: [self.date.timestamp] - } + }) def get_copyright(self) -> str: if self.date.year == 1 or self.label is None: @@ -323,7 +323,7 @@ All objects dependent on Artist """ -class Artist(DatabaseObject, ID3Metadata, SourceAttribute): +class Artist(DatabaseObject, SourceAttribute, MetadataAttribute): """ main_songs feature_song @@ -403,19 +403,17 @@ class Artist(DatabaseObject, ID3Metadata, SourceAttribute): return flat_copy_discography - def get_id3_dict(self) -> dict: + def get_metadata(self) -> MetadataAttribute.Metadata: """ TODO refactor :return: """ - id3_dict = { + metadata = MetadataAttribute.Metadata({ ID3_MAPPING.ARTIST: [self.name] - } - if len(self.sources) <= 0: - return id3_dict - id3_dict.update(self.sources[0].get_id3_dict()) + }) + metadata.merge_many([s.get_artist_metadata() for s in self.source_list]) - return id3_dict + return metadata discography: List[Album] = property(fget=get_discography) diff --git a/src/music_kraken/database/objects/source.py b/src/music_kraken/database/objects/source.py index b0a3309..717a4f8 100644 --- a/src/music_kraken/database/objects/source.py +++ b/src/music_kraken/database/objects/source.py @@ -1,7 +1,7 @@ from enum import Enum from typing import List, Dict -from .metadata import Mapping +from .metadata import Mapping, MetadataAttribute from .parents import ( DatabaseObject, SongAttribute, @@ -35,7 +35,7 @@ class SourcePages(Enum): return homepage_map[attribute] -class Source(DatabaseObject, SongAttribute, ID3Metadata): +class Source(DatabaseObject, SongAttribute, MetadataAttribute): """ create somehow like that ```python @@ -53,23 +53,32 @@ class Source(DatabaseObject, SongAttribute, ID3Metadata): self.url = url - def get_id3_dict(self) -> dict: + def get_song_metadata(self) -> MetadataAttribute.Metadata: + return MetadataAttribute.Metadata({ + Mapping.FILE_WEBPAGE_URL: [self.url], + Mapping.SOURCE_WEBPAGE_URL: [self.homepage] + }) + + def get_artist_metadata(self) -> MetadataAttribute.Metadata: + return MetadataAttribute.Metadata({ + Mapping.ARTIST_WEBPAGE_URL: [self.url] + }) + + def get_metadata(self) -> MetadataAttribute.Metadata: if self.type_enum == SourceTypes.SONG: - return { - Mapping.FILE_WEBPAGE_URL: [self.url], - Mapping.SOURCE_WEBPAGE_URL: [self.homepage] - } + return self.get_song_metadata() if self.type_enum == SourceTypes.ARTIST: - return { - Mapping.ARTIST_WEBPAGE_URL: [self.url] - } + return self.get_artist_metadata() - return {} + return super().get_metadata() def __str__(self): return f"{self.page_enum}: {self.url}" + def __repr__(self) -> str: + return f"Src({self.page_enum.value}: {self.url})" + page_str = property(fget=lambda self: self.page_enum.value) type_str = property(fget=lambda self: self.type_enum.value) homepage = property(fget=lambda self: SourcePages.get_homepage(self.page_enum)) @@ -80,7 +89,7 @@ class SourceAttribute: This is a class that is meant to be inherited from. it adds the source_list attribute to a class """ - _source_dict: Dict[any: List[Source]] = {page_enum: list() for page_enum in SourcePages} + _source_dict: Dict[object, List[Source]] = {page_enum: list() for page_enum in SourcePages} def add_source(self, source: Source): """ @@ -99,7 +108,7 @@ class SourceAttribute: """ gets all sources """ - return [item for _, item in self._source_dict.items()] + return [item for _, page_list in self._source_dict.items() for item in page_list] def set_source_list(self, source_list: List[Source]): self._source_dict = {page_enum: list() for page_enum in SourcePages} @@ -107,7 +116,7 @@ class SourceAttribute: for source in source_list: self.add_source(source) - def get_source_dict(self) -> Dict[any: List[Source]]: + def get_source_dict(self) -> Dict[object, List[Source]]: """ gets a dictionary of all Sources, where the key is a page enum, @@ -116,4 +125,4 @@ class SourceAttribute: return self._source_dict source_list: List[Source] = property(fget=get_source_list, fset=set_source_list) - source_dict: Dict[any: List[Source]] = property(fget=get_source_dict) + source_dict: Dict[object, List[Source]] = property(fget=get_source_dict) diff --git a/test.db b/test.db index 6398dffd56d13dc1cfcb34a67fa4fc01fc2c52ff..1a13b04e75131ef99fc0f15aeebc4ec299848e05 100644 GIT binary patch delta 233 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 L^@@pAIsg9;Jp&6s