diff --git a/src/music_kraken/database/new_database.py b/src/music_kraken/database/new_database.py index b0cf386..fec292a 100644 --- a/src/music_kraken/database/new_database.py +++ b/src/music_kraken/database/new_database.py @@ -182,13 +182,16 @@ class Database: # add sources for source in song.sources: + source.add_song(song) self.push_source(source=source) # add lyrics for single_lyrics in song.lyrics: + single_lyrics.add_song(song) self.push_lyrics(lyrics=single_lyrics) # add target + song.target.add_song(song) self.push_target(target=song.target) for main_artist in song.main_artist_list: diff --git a/src/music_kraken/database/objects/metadata.py b/src/music_kraken/database/objects/metadata.py index 4060c5b..462de15 100644 --- a/src/music_kraken/database/objects/metadata.py +++ b/src/music_kraken/database/objects/metadata.py @@ -253,11 +253,13 @@ class Metadata: call it like a dict to read/write values """ - def __init__(self) -> None: + def __init__(self, id3_dict: dict = None) -> None: # this is pretty self-explanatory # the key is a 4 letter key from the id3 standards like TITL self.id3_attributes: Dict[str, list] = {} + if id3_dict is not None: + self.add_metadata_dict(id3_dict) # its a null byte for the later concatenation of text frames self.null_byte = "\x00" @@ -289,14 +291,13 @@ class Metadata: return None return self.id3_attributes[key] - def add_id3_metadata_obj(self, id3_metadata: ID3Metadata, override_existing: bool = True): - metadata_dict = id3_metadata.get_id3_dict() + 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) - def add_many_id3_metadata_obj(self, id3_metadata_list: List[ID3Metadata], override_existing: bool = False): - for id3_metadata in id3_metadata_list: - self.add_id3_metadata_obj(id3_metadata, override_existing=override_existing) + def add_many_metadata_dict(self, id3_metadata_list: List[dict], override_existing: bool = False): + for metadata_dict in id3_metadata_list: + self.add_metadata_dict(metadata_dict, override_existing=override_existing) def delete_item(self, key: str): if key in self.id3_attributes: diff --git a/src/music_kraken/database/objects/parents.py b/src/music_kraken/database/objects/parents.py index d5d4e92..ee2802d 100644 --- a/src/music_kraken/database/objects/parents.py +++ b/src/music_kraken/database/objects/parents.py @@ -67,6 +67,9 @@ class SongAttribute: class ID3Metadata: + def get_metadata(self): + pass + def get_id3_dict(self) -> dict: return {} diff --git a/src/music_kraken/database/objects/song.py b/src/music_kraken/database/objects/song.py index 579a98c..07c7c23 100644 --- a/src/music_kraken/database/objects/song.py +++ b/src/music_kraken/database/objects/song.py @@ -83,14 +83,13 @@ class Lyrics(DatabaseObject, SongAttribute): self.language = language -class Song(DatabaseObject): +class Song(DatabaseObject, ID3Metadata): def __init__( self, id_: str = None, mb_id: str = None, title: str = None, album_name: str = None, - artist_names: List[str] = [], isrc: str = None, length: int = None, tracksort: int = None, @@ -98,8 +97,8 @@ class Song(DatabaseObject): target: Target = None, lyrics: List[Lyrics] = None, album=None, - main_artist_list: list = [], - feature_artist_list: list = [] + main_artist_list: list = None, + feature_artist_list: list = None ) -> None: """ id: is not NECESARRILY the musicbrainz id, but is DISTINCT for every song @@ -110,41 +109,37 @@ class Song(DatabaseObject): super().__init__(id_=id_) # attributes # *private* attributes - self._title = None - self._isrc = None - self._length = None - self._sources: List[Source] = [] - self._album = None - - self.metadata = Metadata() - - self.title = title - self.isrc = isrc - self.length = length - + self.title: str = title + self.isrc: str = isrc + self.length: int = length self.mb_id: str | None = mb_id self.album_name: str | None = album_name - self.artist_names = artist_names self.tracksort: int | None = tracksort + + self.sources: List[Source] = [] + if sources is not None: + self.sources = sources - self.sources = sources self.album = album - if target is None: - target = Target() - self.target: Target = target + self.target = Target() + if target is not None: + self.target = target self.target.add_song(self) - if lyrics is None: - lyrics = [] - self.lyrics: List[Lyrics] = lyrics - for lyrics_ in self.lyrics: - lyrics_.add_song(self) + self.lyrics = [] + if lyrics is not None: + self.lyrics = lyrics self.album = album - self.main_artist_list = main_artist_list - self.feature_artist_list = feature_artist_list + self.main_artist_list = [] + if main_artist_list is not None: + self.main_artist_list = main_artist_list + + self.feature_artist_list = [] + if feature_artist_list is not None: + self.feature_artist_list = feature_artist_list def __eq__(self, other): if type(other) != type(self): @@ -168,92 +163,33 @@ class Song(DatabaseObject): def __repr__(self) -> str: return self.__str__() - def set_simple_metadata(self, name: str, value): - """ - this method is for setting values of attributes, - that directly map to an ID3 value. - A good example is the title or the isrc. - - for more complex data I will use seperate functions - - the naming convention for the name I follow is, to name - the attribute the same as the defined property, but with one underscore infront: - title -> _title - """ - if value is None: - return - - attribute_map = { - "_title": ID3_MAPPING.TITLE, - "_isrc": ID3_MAPPING.ISRC, - "_length": ID3_MAPPING.LENGTH - } - - # if this crashes/raises an error the function is - # called wrongly. I DO NOT CATCH ERRORS DUE TO PERFORMANCE AND DEBUGGING - self.__setattr__(name, value) - - # convert value to id3 value if necessary - id3_value = value - if type(value) == int: - id3_value = str(value) - - self.metadata[attribute_map[name].value] = [id3_value] - - def add_source(self, source_obj: Source): - if source_obj is None: - return - source_obj.add_song(self) - - print(source_obj) - self._sources.append(source_obj) - self.metadata[ID3_MAPPING.FILE_WEBPAGE_URL.value] = source_obj.url - - def set_sources(self, source_list): - if source_list is None: - return - - self._sources = source_list - for source in self._sources: - source.add_song(self) - - self.metadata.add_many_id3_metadata_obj(self._sources) - - def set_album(self, album): - if album is None: - return - - self.metadata.add_id3_metadata_obj(album) - self._album = album - - def get_metadata(self): - return self.metadata.get_all_metadata() - def has_isrc(self) -> bool: - return self._isrc is not None - - def get_artist_names(self) -> List[str]: - return self.artist_names - - def get_length(self): - if self._length is None: - return None - return int(self._length) + return self.isrc is not None def get_album_id(self): if self.album is None: return None return self.album.id - title: str = property(fget=lambda self: self._title, - fset=lambda self, value: self.set_simple_metadata("_title", value)) - isrc: str = property(fget=lambda self: self._isrc, - fset=lambda self, value: self.set_simple_metadata("_isrc", value)) - length: int = property(fget=get_length, fset=lambda self, value: self.set_simple_metadata("_length", value)) - album_id: str = property(fget=get_album_id) + def get_id3_dict(self) -> dict: + return { + ID3_MAPPING.TITLE: [self.title], + ID3_MAPPING.ISRC: [self.isrc], + ID3_MAPPING.LENGTH: [str(self.length)] + } + + def get_metadata(self) -> Metadata: + metadata = Metadata(self.get_id3_dict()) - sources: List[Source] = property(fget=lambda self: self._sources, fset=set_sources) - album = property(fget=lambda self: self._album, fset=set_album) + metadata.add_many_metadata_dict([source.get_id3_dict() for source in self.sources]) + 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]) + + return metadata + + metadata = property(fget=get_metadata) """ @@ -363,7 +299,7 @@ All objects dependent on Artist """ -class Artist(DatabaseObject): +class Artist(DatabaseObject, ID3Metadata): """ main_songs feature_song @@ -436,6 +372,11 @@ class Artist(DatabaseObject): return flat_copy_discography + def get_id3_dict(self) -> dict: + return { + ID3_MAPPING.ARTIST: [self.name] + } + discography: List[Album] = property(fget=get_discography) features: Album = property(fget=get_features) songs: Album = property(fget=get_songs) diff --git a/test.db b/test.db index 56ae8bd..a291c6d 100644 Binary files a/test.db and b/test.db differ