finished refactoring metadata

This commit is contained in:
Lars Noack 2023-01-30 14:41:02 +01:00
parent bc69cac27c
commit fb8a89dbbd
8 changed files with 106 additions and 116 deletions

View File

@ -29,39 +29,21 @@ def div(msg: str = ""):
cache = music_kraken.database.new_database.Database("test.db") cache = music_kraken.database.new_database.Database("test.db")
cache.reset() 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( song = Song(
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(
genre="HS Core", genre="HS Core",
title="Vein Deep in the Solution", title="Vein Deep in the Solution",
length=666, length=666,
@ -70,50 +52,48 @@ song_input = Song(
target=Target(file="song.mp3", path="~/Music"), target=Target(file="song.mp3", path="~/Music"),
lyrics=[ lyrics=[
Lyrics(text="these are some depressive lyrics", language="en"), 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.YOUTUBE, "https://youtu.be/dfnsdajlhkjhsd"),
Source(SourcePages.MUSIFY, "https://ln.topdf.de/Music-Kraken/") Source(SourcePages.MUSIFY, "https://ln.topdf.de/Music-Kraken/")
], ],
album=album_input, album=Album(
main_artist_list=[main_artist], title="One Final Action",
feature_artist_list=[feature_artist], 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( print_song(song)
title="this is just another song",
main_artist_list=[feature_artist],
feature_artist_list=[main_artist]
)
print(song_input) exit()
additional_song = Song( song_ref = song.reference
title="A fcking Song",
album=album_input
)
song_ref = song_input.reference cache.push([song])
print(song_ref)
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 # getting song by song ref
div() div()
song_output_list = cache.pull_songs(song_ref=song_ref) song_list = cache.pull_songs(song_ref=song_ref)
print(len(song_output_list), song_output_list, song_output_list[0].album, sep=" | ") song_from_db = song_list[0]
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)
print("album", song.album.sources)
# try writing metadata # try writing metadata
write_metadata(song) write_metadata(song)

View File

@ -11,7 +11,6 @@ SourcePages = objects.SourcePages
Song = objects.Song Song = objects.Song
Source = objects.Source Source = objects.Source
Target = objects.Target Target = objects.Target
Metadata = objects.Metadata
Lyrics = objects.Lyrics Lyrics = objects.Lyrics
Album = objects.Album Album = objects.Album

View File

@ -11,7 +11,6 @@ from .objects.source import Source
from .objects import ( from .objects import (
Song, Song,
Lyrics, Lyrics,
Metadata,
Target, Target,
Artist, Artist,
Album, Album,
@ -187,7 +186,7 @@ class Database:
self.connection.commit() self.connection.commit()
# add sources # add sources
for source in song.sources: for source in song.source_list:
source.add_song(song) source.add_song(song)
source.type_enum = SourceTypes.SONG source.type_enum = SourceTypes.SONG
self.push_source(source=source) self.push_source(source=source)

View File

@ -7,7 +7,7 @@ from . import (
MusicObject = parents.DatabaseObject MusicObject = parents.DatabaseObject
ID3_MAPPING = metadata.Mapping ID3Mapping = metadata.Mapping
ID3Timestamp = metadata.ID3Timestamp ID3Timestamp = metadata.ID3Timestamp
SourceTypes = source.SourceTypes SourceTypes = source.SourceTypes
@ -17,7 +17,6 @@ Song = song.Song
Artist = song.Artist Artist = song.Artist
Source = source.Source Source = source.Source
Target = song.Target Target = song.Target
Metadata = song.Metadata
Lyrics = song.Lyrics Lyrics = song.Lyrics
Album = song.Album Album = song.Album

View File

@ -259,10 +259,11 @@ class MetadataAttribute:
# the key is an enum from Mapping # the key is an enum from Mapping
# the value is a list with each value # the value is a list with each value
# the mutagen object for each frame will be generated dynamically # 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: def __init__(self, id3_dict: Dict[any, list] = None) -> None:
self.id3_dict = dict()
if id3_dict is not None: if id3_dict is not None:
self.add_metadata_dict(id3_dict) self.add_metadata_dict(id3_dict)
@ -284,7 +285,7 @@ class MetadataAttribute:
self.id3_dict[frame] = new_val self.id3_dict[frame] = new_val
return return
self.id3_attributes[frame].extend(new_val) self.id3_dict[frame].extend(new_val)
def __getitem__(self, key): def __getitem__(self, key):
if key not in self.id3_dict: 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): def add_metadata_dict(self, metadata_dict: dict, override_existing: bool = True):
for field_enum, value in metadata_dict.items(): 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): def merge(self, other, override_existing: bool = False):
""" """
adds the values of another metadata obj to this one 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) self.add_metadata_dict(other.id3_dict, override_existing=override_existing)
def merge_many(self, many_other): def merge_many(self, many_other):
""" """
adds the values of many other metadata objects to this one adds the values of many other metadata objects to this one
""" """
for other in many_other: for other in many_other:
self.merge(other) self.merge(other)
def get_id3_value(self, field): def get_id3_value(self, field):
if field not in self.id3_attributes: if field not in self.id3_dict:
return None return None
list_data = self.id3_dict[field] list_data = self.id3_dict[field]
@ -335,7 +341,7 @@ class MetadataAttribute:
else I take the first element else I take the first element
""" """
if field.value[0].upper() == "T" and field.value.upper() != "TXXX": 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] return list_data[0]
@ -344,7 +350,7 @@ class MetadataAttribute:
def __str__(self) -> str: def __str__(self) -> str:
rows = [] rows = []
for key, value in self.id3_attributes.items(): for key, value in self.id3_dict.items():
rows.append(f"{key} - {str(value)}") rows.append(f"{key} - {str(value)}")
return "\n".join(rows) return "\n".join(rows)
@ -355,15 +361,15 @@ class MetadataAttribute:
to directly tagg a file with id3 container. to directly tagg a file with id3 container.
""" """
# set the tagging timestamp to the current time # 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) yield self.get_mutagen_object(field)
def get_metadata(self) -> Metadata: def get_metadata(self) -> Metadata:
""" """
this is intendet to be overwritten by the child class 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())

View File

@ -5,8 +5,8 @@ import pycountry
from .metadata import ( from .metadata import (
Mapping as ID3_MAPPING, Mapping as ID3_MAPPING,
Metadata, ID3Timestamp,
ID3Timestamp MetadataAttribute
) )
from ...utils.shared import ( from ...utils.shared import (
MUSIC_DIR, MUSIC_DIR,
@ -80,7 +80,7 @@ class Target(DatabaseObject, SongAttribute):
exists_on_disc = property(fget=get_exists_on_disc) exists_on_disc = property(fget=get_exists_on_disc)
class Lyrics(DatabaseObject, SongAttribute, SourceAttribute): class Lyrics(DatabaseObject, SongAttribute, SourceAttribute, MetadataAttribute):
def __init__( def __init__(
self, self,
text: str, text: str,
@ -96,8 +96,11 @@ class Lyrics(DatabaseObject, SongAttribute, SourceAttribute):
if source_list is not None: if source_list is not None:
self.source_list = source_list 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__( def __init__(
self, self,
id_: str = None, id_: str = None,
@ -186,26 +189,23 @@ class Song(DatabaseObject, ID3Metadata, SourceAttribute):
return None return None
return self.album.id return self.album.id
def get_id3_dict(self) -> dict: def get_metadata(self) -> MetadataAttribute.Metadata:
return { metadata = MetadataAttribute.Metadata({
ID3_MAPPING.TITLE: [self.title], ID3_MAPPING.TITLE: [self.title],
ID3_MAPPING.ISRC: [self.isrc], ID3_MAPPING.ISRC: [self.isrc],
ID3_MAPPING.LENGTH: [str(self.length)], ID3_MAPPING.LENGTH: [str(self.length)],
ID3_MAPPING.GENRE: [self.genre] 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: if self.album is not None:
metadata.add_metadata_dict(self.album.get_id3_dict()) metadata.merge(self.album.metadata)
metadata.add_many_metadata_dict([artist.get_id3_dict() for artist in self.main_artist_list]) metadata.merge_many([a.metadata for a in self.main_artist_list])
metadata.add_many_metadata_dict([artist.get_id3_dict() for artist in self.feature_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 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------- -------DB-FIELDS-------
title TEXT, title TEXT,
@ -292,14 +292,14 @@ class Album(DatabaseObject, ID3Metadata, SourceAttribute):
song.tracksort = len(self.tracklist) song.tracksort = len(self.tracklist)
self.tracklist.append(song) self.tracklist.append(song)
def get_id3_dict(self) -> dict: def get_metadata(self) -> MetadataAttribute.Metadata:
return { return MetadataAttribute.Metadata({
ID3_MAPPING.ALBUM: [self.title], ID3_MAPPING.ALBUM: [self.title],
ID3_MAPPING.COPYRIGHT: [self.copyright], ID3_MAPPING.COPYRIGHT: [self.copyright],
ID3_MAPPING.LANGUAGE: [self.iso_639_2_language], ID3_MAPPING.LANGUAGE: [self.iso_639_2_language],
ID3_MAPPING.ALBUM_ARTIST: [a.name for a in self.artists], ID3_MAPPING.ALBUM_ARTIST: [a.name for a in self.artists],
ID3_MAPPING.DATE: [self.date.timestamp] ID3_MAPPING.DATE: [self.date.timestamp]
} })
def get_copyright(self) -> str: def get_copyright(self) -> str:
if self.date.year == 1 or self.label is None: 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 main_songs
feature_song feature_song
@ -403,19 +403,17 @@ class Artist(DatabaseObject, ID3Metadata, SourceAttribute):
return flat_copy_discography return flat_copy_discography
def get_id3_dict(self) -> dict: def get_metadata(self) -> MetadataAttribute.Metadata:
""" """
TODO refactor TODO refactor
:return: :return:
""" """
id3_dict = { metadata = MetadataAttribute.Metadata({
ID3_MAPPING.ARTIST: [self.name] ID3_MAPPING.ARTIST: [self.name]
} })
if len(self.sources) <= 0: metadata.merge_many([s.get_artist_metadata() for s in self.source_list])
return id3_dict
id3_dict.update(self.sources[0].get_id3_dict())
return id3_dict return metadata
discography: List[Album] = property(fget=get_discography) discography: List[Album] = property(fget=get_discography)

View File

@ -1,7 +1,7 @@
from enum import Enum from enum import Enum
from typing import List, Dict from typing import List, Dict
from .metadata import Mapping from .metadata import Mapping, MetadataAttribute
from .parents import ( from .parents import (
DatabaseObject, DatabaseObject,
SongAttribute, SongAttribute,
@ -35,7 +35,7 @@ class SourcePages(Enum):
return homepage_map[attribute] return homepage_map[attribute]
class Source(DatabaseObject, SongAttribute, ID3Metadata): class Source(DatabaseObject, SongAttribute, MetadataAttribute):
""" """
create somehow like that create somehow like that
```python ```python
@ -53,23 +53,32 @@ class Source(DatabaseObject, SongAttribute, ID3Metadata):
self.url = url 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: if self.type_enum == SourceTypes.SONG:
return { return self.get_song_metadata()
Mapping.FILE_WEBPAGE_URL: [self.url],
Mapping.SOURCE_WEBPAGE_URL: [self.homepage]
}
if self.type_enum == SourceTypes.ARTIST: if self.type_enum == SourceTypes.ARTIST:
return { return self.get_artist_metadata()
Mapping.ARTIST_WEBPAGE_URL: [self.url]
}
return {} return super().get_metadata()
def __str__(self): def __str__(self):
return f"{self.page_enum}: {self.url}" 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) page_str = property(fget=lambda self: self.page_enum.value)
type_str = property(fget=lambda self: self.type_enum.value) type_str = property(fget=lambda self: self.type_enum.value)
homepage = property(fget=lambda self: SourcePages.get_homepage(self.page_enum)) 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. This is a class that is meant to be inherited from.
it adds the source_list attribute to a class 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): def add_source(self, source: Source):
""" """
@ -99,7 +108,7 @@ class SourceAttribute:
""" """
gets all sources 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]): def set_source_list(self, source_list: List[Source]):
self._source_dict = {page_enum: list() for page_enum in SourcePages} self._source_dict = {page_enum: list() for page_enum in SourcePages}
@ -107,7 +116,7 @@ class SourceAttribute:
for source in source_list: for source in source_list:
self.add_source(source) 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, gets a dictionary of all Sources,
where the key is a page enum, where the key is a page enum,
@ -116,4 +125,4 @@ class SourceAttribute:
return self._source_dict return self._source_dict
source_list: List[Source] = property(fget=get_source_list, fset=set_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) source_dict: Dict[object, List[Source]] = property(fget=get_source_dict)

BIN
test.db

Binary file not shown.