metadata
This commit is contained in:
parent
4abb17ca8e
commit
bc69cac27c
@ -247,67 +247,77 @@ class ID3Timestamp:
|
||||
timestamp: str = property(fget=get_timestamp)
|
||||
|
||||
|
||||
class Metadata:
|
||||
class MetadataAttribute:
|
||||
"""
|
||||
Shall only be read or edited via the Song object.
|
||||
call it like a dict to read/write values
|
||||
This class shall be added to any object, which can return data for tagging
|
||||
"""
|
||||
|
||||
def __init__(self, id3_dict: dict = None) -> None:
|
||||
class Metadata:
|
||||
# its a null byte for the later concatenation of text frames
|
||||
NULL_BYTE: str = "\x00"
|
||||
# this is pretty self-explanatory
|
||||
# the key is a 4 letter key from the id3 standards like TITL
|
||||
# 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()
|
||||
|
||||
self.id3_attributes: Dict[str, list] = {}
|
||||
|
||||
def __init__(self, id3_dict: Dict[any, list] = None) -> None:
|
||||
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"
|
||||
|
||||
def get_all_metadata(self):
|
||||
return list(self.id3_attributes.items())
|
||||
|
||||
def __setitem__(self, key: str, value: list, override_existing: bool = True):
|
||||
if len(value) == 0:
|
||||
def __setitem__(self, frame, value_list: list, override_existing: bool = True):
|
||||
if len(value_list) == 0:
|
||||
return
|
||||
if type(value_list) != list:
|
||||
raise ValueError(f"can only set attribute to list, not {type(value_list)}")
|
||||
|
||||
new_val = [i for i in value_list if i is not None]
|
||||
|
||||
if len(new_val) == 0:
|
||||
return
|
||||
if type(value) != list:
|
||||
raise ValueError(f"can only set attribute to list, not {type(value)}")
|
||||
|
||||
if override_existing:
|
||||
new_val = []
|
||||
for elem in value:
|
||||
if elem is not None:
|
||||
new_val.append(elem)
|
||||
if len(new_val) > 0:
|
||||
self.id3_attributes[key] = new_val
|
||||
self.id3_dict[frame] = new_val
|
||||
else:
|
||||
if key not in self.id3_attributes:
|
||||
self.id3_attributes[key] = value
|
||||
if frame not in self.id3_dict:
|
||||
self.id3_dict[frame] = new_val
|
||||
return
|
||||
self.id3_attributes[key].extend(value)
|
||||
|
||||
self.id3_attributes[frame].extend(new_val)
|
||||
|
||||
def __getitem__(self, key):
|
||||
if key not in self.id3_attributes:
|
||||
if key not in self.id3_dict:
|
||||
return None
|
||||
return self.id3_attributes[key]
|
||||
return self.id3_dict[key]
|
||||
|
||||
|
||||
def delete_field(self, key: str):
|
||||
if key in self.id3_attributes:
|
||||
return self.id3_attributes.pop(key)
|
||||
|
||||
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_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 merge(self, other, override_existing: bool = False):
|
||||
"""
|
||||
adds the values of another metadata obj to this one
|
||||
"""
|
||||
self.add_metadata_dict(other.id3_dict, override_existing=override_existing)
|
||||
|
||||
def delete_item(self, key: str):
|
||||
if key in self.id3_attributes:
|
||||
return self.id3_attributes.pop(key)
|
||||
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, key: str):
|
||||
if key not in self.id3_attributes:
|
||||
def get_id3_value(self, field):
|
||||
if field not in self.id3_attributes:
|
||||
return None
|
||||
|
||||
list_data = self.id3_attributes[key]
|
||||
list_data = self.id3_dict[field]
|
||||
|
||||
# convert for example the time objects to timestamps
|
||||
for i, element in enumerate(list_data):
|
||||
@ -324,23 +334,36 @@ class Metadata:
|
||||
Thus if above conditions are met, I concatenate the list,
|
||||
else I take the first element
|
||||
"""
|
||||
if key[0].upper() == "T" and key.upper() != "TXXX":
|
||||
if field.value[0].upper() == "T" and field.value.upper() != "TXXX":
|
||||
return self.null_byte.join(list_data)
|
||||
|
||||
return list_data[0]
|
||||
|
||||
def get_mutagen_object(self, key: str):
|
||||
return Mapping.get_mutagen_instance(Mapping(key), self.get_id3_value(key))
|
||||
|
||||
def __iter__(self):
|
||||
# set the tagging timestamp to the current time
|
||||
self.__setitem__(Mapping.TAGGING_TIME.value, [ID3Timestamp.now()])
|
||||
|
||||
for key in self.id3_attributes:
|
||||
yield key, self.get_mutagen_object(key)
|
||||
def get_mutagen_object(self, field):
|
||||
return Mapping.get_mutagen_instance(field, self.get_id3_value(field))
|
||||
|
||||
def __str__(self) -> str:
|
||||
rows = []
|
||||
for key, value in self.id3_attributes.items():
|
||||
rows.append(f"{key} - {str(value)}")
|
||||
return "\n".join(rows)
|
||||
|
||||
|
||||
def __iter__(self):
|
||||
"""
|
||||
returns a generator, you can iterate through,
|
||||
to directly tagg a file with id3 container.
|
||||
"""
|
||||
# set the tagging timestamp to the current time
|
||||
self.__setitem__(Mapping.TAGGING_TIME.value, [ID3Timestamp.now()])
|
||||
|
||||
for field in self.id3_attributes:
|
||||
yield self.get_mutagen_object(field)
|
||||
|
||||
def get_metadata(self) -> Metadata:
|
||||
"""
|
||||
this is intendet to be overwritten by the child class
|
||||
"""
|
||||
return self.Metadata()
|
||||
|
||||
metadata = property(fget=get_metadata)
|
||||
|
@ -21,7 +21,8 @@ from .parents import (
|
||||
from .source import (
|
||||
Source,
|
||||
SourceTypes,
|
||||
SourcePages
|
||||
SourcePages,
|
||||
SourceAttribute
|
||||
)
|
||||
|
||||
"""
|
||||
@ -79,15 +80,24 @@ class Target(DatabaseObject, SongAttribute):
|
||||
exists_on_disc = property(fget=get_exists_on_disc)
|
||||
|
||||
|
||||
class Lyrics(DatabaseObject, SongAttribute):
|
||||
def __init__(self, text: str, language: str, id_: str = None) -> None:
|
||||
class Lyrics(DatabaseObject, SongAttribute, SourceAttribute):
|
||||
def __init__(
|
||||
self,
|
||||
text: str,
|
||||
language: str,
|
||||
id_: str = None,
|
||||
source_list: List[Source] = None
|
||||
) -> None:
|
||||
DatabaseObject.__init__(self, id_=id_)
|
||||
SongAttribute.__init__(self)
|
||||
self.text = text
|
||||
self.language = language
|
||||
|
||||
if source_list is not None:
|
||||
self.source_list = source_list
|
||||
|
||||
class Song(DatabaseObject, ID3Metadata):
|
||||
|
||||
class Song(DatabaseObject, ID3Metadata, SourceAttribute):
|
||||
def __init__(
|
||||
self,
|
||||
id_: str = None,
|
||||
@ -98,7 +108,7 @@ class Song(DatabaseObject, ID3Metadata):
|
||||
length: int = None,
|
||||
tracksort: int = None,
|
||||
genre: str = None,
|
||||
sources: List[Source] = None,
|
||||
source_list: List[Source] = None,
|
||||
target: Target = None,
|
||||
lyrics: List[Lyrics] = None,
|
||||
album=None,
|
||||
@ -122,8 +132,8 @@ class Song(DatabaseObject, ID3Metadata):
|
||||
self.tracksort: int | None = tracksort
|
||||
self.genre: str = genre
|
||||
|
||||
self._sources: List[Source] = []
|
||||
self.sources = sources
|
||||
if source_list:
|
||||
self.source_list = source_list
|
||||
|
||||
self.album = album
|
||||
|
||||
@ -187,7 +197,7 @@ class Song(DatabaseObject, ID3Metadata):
|
||||
def get_metadata(self) -> Metadata:
|
||||
metadata = Metadata(self.get_id3_dict())
|
||||
|
||||
metadata.add_many_metadata_dict([source.get_id3_dict() for source in self.sources])
|
||||
metadata.add_many_metadata_dict([source.get_id3_dict() for source 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])
|
||||
@ -195,15 +205,6 @@ class Song(DatabaseObject, ID3Metadata):
|
||||
|
||||
return metadata
|
||||
|
||||
def set_sources(self, source_list: List[Source]):
|
||||
if source_list is None:
|
||||
return
|
||||
|
||||
self._sources = source_list
|
||||
for source in self._sources:
|
||||
source.type_enum = SourceTypes.SONG
|
||||
|
||||
sources: List[Source] = property(fget=lambda self: self._sources, fset=set_sources)
|
||||
metadata = property(fget=get_metadata)
|
||||
|
||||
|
||||
@ -212,7 +213,7 @@ All objects dependent on Album
|
||||
"""
|
||||
|
||||
|
||||
class Album(DatabaseObject, ID3Metadata):
|
||||
class Album(DatabaseObject, ID3Metadata, SourceAttribute):
|
||||
"""
|
||||
-------DB-FIELDS-------
|
||||
title TEXT,
|
||||
@ -240,7 +241,7 @@ class Album(DatabaseObject, ID3Metadata):
|
||||
is_split: bool = False,
|
||||
albumsort: int = None,
|
||||
dynamic: bool = False,
|
||||
sources: List[Source] = None,
|
||||
source_list: List[Source] = None,
|
||||
artists: list = None
|
||||
) -> None:
|
||||
DatabaseObject.__init__(self, id_=id_, dynamic=dynamic)
|
||||
@ -261,8 +262,8 @@ class Album(DatabaseObject, ID3Metadata):
|
||||
|
||||
self.tracklist: List[Song] = []
|
||||
|
||||
self._sources = []
|
||||
self.sources = sources
|
||||
if source_list is not None:
|
||||
self.source_list = source_list
|
||||
|
||||
self.artists = []
|
||||
if artists is not None:
|
||||
@ -312,16 +313,6 @@ class Album(DatabaseObject, ID3Metadata):
|
||||
|
||||
return self.language.alpha_3
|
||||
|
||||
def set_sources(self, source_list: List[Source]):
|
||||
if source_list is None:
|
||||
return
|
||||
|
||||
self._sources = source_list
|
||||
for source in self._sources:
|
||||
source.add_song(self)
|
||||
source.type_enum = SourceTypes.ALBUM
|
||||
|
||||
sources: List[Source] = property(fget=lambda self: self._sources, fset=set_sources)
|
||||
copyright = property(fget=get_copyright)
|
||||
iso_639_2_language = property(fget=get_iso_639_2_lang)
|
||||
|
||||
@ -332,7 +323,7 @@ All objects dependent on Artist
|
||||
"""
|
||||
|
||||
|
||||
class Artist(DatabaseObject, ID3Metadata):
|
||||
class Artist(DatabaseObject, ID3Metadata, SourceAttribute):
|
||||
"""
|
||||
main_songs
|
||||
feature_song
|
||||
@ -344,7 +335,7 @@ class Artist(DatabaseObject, ID3Metadata):
|
||||
self,
|
||||
id_: str = None,
|
||||
name: str = None,
|
||||
sources: List[Source] = None,
|
||||
source_list: List[Source] = None,
|
||||
main_songs: List[Song] = None,
|
||||
feature_songs: List[Song] = None,
|
||||
main_albums: List[Album] = None,
|
||||
@ -368,9 +359,8 @@ class Artist(DatabaseObject, ID3Metadata):
|
||||
|
||||
self.main_albums = main_albums
|
||||
|
||||
self._sources = []
|
||||
self.sources = sources
|
||||
|
||||
if source_list is not None:
|
||||
self.source_list = source_list
|
||||
|
||||
def __str__(self):
|
||||
return self.name or ""
|
||||
@ -427,16 +417,7 @@ class Artist(DatabaseObject, ID3Metadata):
|
||||
|
||||
return id3_dict
|
||||
|
||||
def set_sources(self, source_list: List[Source]):
|
||||
if source_list is None:
|
||||
return
|
||||
|
||||
self._sources = source_list
|
||||
for source in self._sources:
|
||||
source.add_song(self)
|
||||
source.type_enum = SourceTypes.ARTIST
|
||||
|
||||
sources: List[Source] = property(fget=lambda self: self._sources, fset=set_sources)
|
||||
discography: List[Album] = property(fget=get_discography)
|
||||
features: Album = property(fget=get_features)
|
||||
songs: Album = property(fget=get_songs)
|
||||
|
@ -86,7 +86,7 @@ class SourceAttribute:
|
||||
"""
|
||||
adds a new Source to the sources
|
||||
"""
|
||||
pass
|
||||
self._source_dict[source.page_enum].append(source)
|
||||
|
||||
def get_sources_from_page(self, page_enum) -> List[Source]:
|
||||
"""
|
||||
@ -99,7 +99,13 @@ class SourceAttribute:
|
||||
"""
|
||||
gets all sources
|
||||
"""
|
||||
return []
|
||||
return [item for _, item in self._source_dict.items()]
|
||||
|
||||
def set_source_list(self, source_list: List[Source]):
|
||||
self._source_dict = {page_enum: list() for page_enum in SourcePages}
|
||||
|
||||
for source in source_list:
|
||||
self.add_source(source)
|
||||
|
||||
def get_source_dict(self) -> Dict[any: List[Source]]:
|
||||
"""
|
||||
@ -109,5 +115,5 @@ class SourceAttribute:
|
||||
"""
|
||||
return self._source_dict
|
||||
|
||||
source_list: List[Source] = property(fget=get_source_list)
|
||||
source_list: List[Source] = property(fget=get_source_list, fset=set_source_list)
|
||||
source_dict: Dict[any: List[Source]] = property(fget=get_source_dict)
|
||||
|
Loading…
Reference in New Issue
Block a user