music-kraken-core/music_kraken/objects/song.py

694 lines
23 KiB
Python
Raw Normal View History

2023-12-19 12:58:39 +00:00
from __future__ import annotations
2023-04-16 12:36:33 +00:00
import random
2023-04-16 15:39:53 +00:00
from collections import defaultdict
2023-12-19 21:11:46 +00:00
from typing import List, Optional, Dict, Tuple, Type, Union
2023-04-04 20:10:35 +00:00
2023-01-13 13:37:15 +00:00
import pycountry
2022-12-06 13:45:18 +00:00
2023-04-18 10:14:34 +00:00
from ..utils.enums.album import AlbumType, AlbumStatus
2023-10-24 09:44:00 +00:00
from .collection import Collection
2023-04-04 20:10:35 +00:00
from .formatted_text import FormattedText
from .lyrics import Lyrics
from .contact import Contact
2024-04-10 15:06:29 +00:00
from .artwork import Artwork
2023-01-12 22:01:19 +00:00
from .metadata import (
Mapping as id3Mapping,
2023-01-30 13:41:02 +00:00
ID3Timestamp,
2023-03-10 08:09:35 +00:00
Metadata
2023-01-12 22:01:19 +00:00
)
2023-03-10 20:28:13 +00:00
from .option import Options
2023-12-19 21:11:46 +00:00
from .parents import OuterProxy, P
2023-04-04 20:10:35 +00:00
from .source import Source, SourceCollection
from .target import Target
2023-12-19 15:10:02 +00:00
from .country import Language, Country
2023-04-04 20:10:35 +00:00
from ..utils.string_processing import unify
2023-08-30 19:14:03 +00:00
2023-12-19 12:58:39 +00:00
from .parents import OuterProxy as Base
2023-09-10 14:27:09 +00:00
from ..utils.config import main_settings
2022-12-06 13:45:18 +00:00
2022-12-07 14:51:38 +00:00
"""
All Objects dependent
"""
2023-02-22 16:56:52 +00:00
CountryTyping = type(list(pycountry.countries)[0])
2023-03-10 09:54:15 +00:00
OPTION_STRING_DELIMITER = " | "
2023-02-22 16:56:52 +00:00
2022-12-08 08:28:28 +00:00
2023-12-19 12:58:39 +00:00
class Song(Base):
title: str
unified_title: str
isrc: str
length: int
genre: str
note: FormattedText
2024-02-28 13:27:35 +00:00
tracksort: int
2024-04-10 15:06:29 +00:00
artwork: Artwork
2023-12-19 12:58:39 +00:00
source_collection: SourceCollection
target_collection: Collection[Target]
lyrics_collection: Collection[Lyrics]
2024-04-17 12:15:56 +00:00
2023-12-19 12:58:39 +00:00
main_artist_collection: Collection[Artist]
feature_artist_collection: Collection[Artist]
album_collection: Collection[Album]
_default_factories = {
"note": FormattedText,
"length": lambda: 0,
"source_collection": SourceCollection,
"target_collection": Collection,
"lyrics_collection": Collection,
2024-04-10 15:06:29 +00:00
"artwork": Artwork,
2023-12-19 12:58:39 +00:00
"main_artist_collection": Collection,
"album_collection": Collection,
2023-12-19 21:11:46 +00:00
"feature_artist_collection": Collection,
2023-12-20 08:55:09 +00:00
2024-01-15 10:52:31 +00:00
"title": lambda: "",
2023-12-20 08:55:09 +00:00
"unified_title": lambda: None,
"isrc": lambda: None,
"genre": lambda: None,
2024-02-28 13:27:35 +00:00
"tracksort": lambda: 0,
2023-12-19 12:58:39 +00:00
}
2024-01-15 10:52:31 +00:00
def __init__(self, title: str = "", unified_title: str = None, isrc: str = None, length: int = None,
2024-01-15 10:40:48 +00:00
genre: str = None, note: FormattedText = None, source_list: List[Source] = None,
2023-12-29 20:50:40 +00:00
target_list: List[Target] = None, lyrics_list: List[Lyrics] = None,
main_artist_list: List[Artist] = None, feature_artist_list: List[Artist] = None,
2024-04-10 15:14:52 +00:00
album_list: List[Album] = None, tracksort: int = 0, artwork: Optional[Artwork] = None, **kwargs) -> None:
2023-12-29 20:50:40 +00:00
2024-02-28 13:27:35 +00:00
Base.__init__(**locals())
2023-12-29 20:16:09 +00:00
2023-09-14 21:35:37 +00:00
UPWARDS_COLLECTION_STRING_ATTRIBUTES = ("album_collection", "main_artist_collection", "feature_artist_collection")
2024-04-10 08:25:05 +00:00
TITEL = "title"
2023-12-29 20:16:09 +00:00
2023-12-19 12:58:39 +00:00
def __init_collections__(self) -> None:
self.album_collection.sync_on_append = {
"artist_collection": self.main_artist_collection,
}
2023-12-19 12:58:39 +00:00
self.album_collection.append_object_to_attribute = {
"song_collection": self,
}
2023-09-14 21:35:37 +00:00
2023-12-19 12:58:39 +00:00
self.main_artist_collection.contain_given_in_attribute = {
"main_album_collection": self.album_collection
}
self.feature_artist_collection.append_object_to_attribute = {
"feature_song_collection": self
}
2024-01-15 11:48:36 +00:00
def _add_other_db_objects(self, object_type: Type[OuterProxy], object_list: List[OuterProxy]):
if object_type is Song:
return
if isinstance(object_list, Lyrics):
self.lyrics_collection.extend(object_list)
return
if isinstance(object_list, Artist):
self.main_artist_collection.extend(object_list)
return
if isinstance(object_list, Album):
self.album_collection.extend(object_list)
return
2023-03-10 08:09:35 +00:00
@property
def indexing_values(self) -> List[Tuple[str, object]]:
return [
('id', self.id),
('title', unify(self.title)),
2023-03-10 17:38:32 +00:00
('isrc', self.isrc),
2023-03-10 09:21:57 +00:00
*[('url', source.url) for source in self.source_collection]
2023-03-10 08:09:35 +00:00
]
2023-03-10 09:54:15 +00:00
2023-03-10 08:09:35 +00:00
@property
def metadata(self) -> Metadata:
metadata = Metadata({
id3Mapping.TITLE: [self.title],
id3Mapping.ISRC: [self.isrc],
id3Mapping.LENGTH: [self.length],
id3Mapping.GENRE: [self.genre],
2024-04-10 07:28:28 +00:00
id3Mapping.TRACKNUMBER: [self.tracksort_str],
id3Mapping.COMMENT: [self.note.markdown],
2023-03-10 08:09:35 +00:00
})
# metadata.merge_many([s.get_song_metadata() for s in self.source_collection]) album sources have no relevant metadata for id3
2023-03-10 08:09:35 +00:00
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.feature_artist_collection])
metadata.merge_many([lyrics.metadata for lyrics in self.lyrics_collection])
return metadata
2022-12-13 10:16:19 +00:00
def get_artist_credits(self) -> str:
2023-02-10 12:52:18 +00:00
main_artists = ", ".join([artist.name for artist in self.main_artist_collection])
feature_artists = ", ".join([artist.name for artist in self.feature_artist_collection])
2023-02-22 16:56:52 +00:00
2023-02-10 12:52:18 +00:00
if len(feature_artists) == 0:
return main_artists
return f"{main_artists} feat. {feature_artists}"
2022-12-13 10:16:19 +00:00
2022-12-06 13:45:18 +00:00
def __repr__(self) -> str:
2023-02-10 12:52:18 +00:00
return f"Song(\"{self.title}\")"
2022-12-09 17:24:58 +00:00
2023-03-10 09:54:15 +00:00
@property
def option_string(self) -> str:
2024-04-11 11:58:06 +00:00
r = f"{self.__repr__()}"
if not self.album_collection.empty:
r += f" from Album({OPTION_STRING_DELIMITER.join(album.title for album in self.album_collection)})"
if not self.main_artist_collection.empty:
r += f" by Artist({OPTION_STRING_DELIMITER.join(artist.name for artist in self.main_artist_collection)})"
if not self.feature_artist_collection.empty:
r += f" feat. Artist({OPTION_STRING_DELIMITER.join(artist.name for artist in self.feature_artist_collection)})"
return r
2023-03-10 09:54:15 +00:00
2023-12-19 21:11:46 +00:00
@property
def options(self) -> List[P]:
2023-03-10 09:54:15 +00:00
options = self.main_artist_collection.shallow_list
2023-02-23 22:52:41 +00:00
options.extend(self.feature_artist_collection)
options.extend(self.album_collection)
2023-02-09 08:40:57 +00:00
options.append(self)
2023-06-12 12:56:14 +00:00
return options
2023-03-10 20:28:13 +00:00
@property
def tracksort_str(self) -> str:
"""
2023-03-10 20:33:26 +00:00
if the album tracklist is empty, it sets it length to 1, this song has to be on the Album
2023-03-10 20:28:13 +00:00
:returns id3_tracksort: {song_position}/{album.length_of_tracklist}
"""
2023-03-24 09:30:40 +00:00
if len(self.album_collection) == 0:
return f"{self.tracksort}"
2023-04-12 10:00:29 +00:00
2023-03-31 08:46:56 +00:00
return f"{self.tracksort}/{len(self.album_collection[0].song_collection) or 1}"
2023-02-09 08:40:57 +00:00
2022-12-06 13:45:18 +00:00
2022-12-07 14:51:38 +00:00
"""
2022-12-09 17:24:58 +00:00
All objects dependent on Album
2022-12-07 14:51:38 +00:00
"""
2022-12-08 08:28:28 +00:00
2023-12-19 12:58:39 +00:00
class Album(Base):
title: str
unified_title: str
2023-12-19 15:10:02 +00:00
album_status: AlbumStatus
2023-12-19 12:58:39 +00:00
album_type: AlbumType
2023-12-19 15:10:02 +00:00
language: Language
date: ID3Timestamp
barcode: str
albumsort: int
notes: FormattedText
source_collection: SourceCollection
2024-04-19 15:45:49 +00:00
2023-12-19 15:10:02 +00:00
artist_collection: Collection[Artist]
song_collection: Collection[Song]
label_collection: Collection[Label]
2023-12-19 12:58:39 +00:00
_default_factories = {
2023-12-29 20:50:40 +00:00
"title": lambda: None,
2023-12-29 20:16:09 +00:00
"unified_title": lambda: None,
"album_status": lambda: None,
"barcode": lambda: None,
"albumsort": lambda: None,
2023-12-19 15:10:02 +00:00
"album_type": lambda: AlbumType.OTHER,
"language": lambda: Language.by_alpha_2("en"),
"date": ID3Timestamp,
"notes": FormattedText,
2023-12-19 21:11:46 +00:00
"source_collection": SourceCollection,
"artist_collection": Collection,
"song_collection": Collection,
"label_collection": Collection,
2023-12-19 12:58:39 +00:00
}
2024-04-10 08:25:05 +00:00
TITEL = "title"
2023-12-29 20:16:09 +00:00
# This is automatically generated
2023-12-29 20:50:40 +00:00
def __init__(self, title: str = None, unified_title: str = None, album_status: AlbumStatus = None,
2023-12-29 20:16:09 +00:00
album_type: AlbumType = None, language: Language = None, date: ID3Timestamp = None,
barcode: str = None, albumsort: int = None, notes: FormattedText = None,
2024-01-15 10:40:48 +00:00
source_list: List[Source] = None, artist_list: List[Artist] = None, song_list: List[Song] = None,
2023-12-29 20:16:09 +00:00
label_list: List[Label] = None, **kwargs) -> None:
super().__init__(title=title, unified_title=unified_title, album_status=album_status, album_type=album_type,
language=language, date=date, barcode=barcode, albumsort=albumsort, notes=notes,
source_list=source_list, artist_list=artist_list, song_list=song_list, label_list=label_list,
**kwargs)
2024-01-15 09:56:59 +00:00
DOWNWARDS_COLLECTION_STRING_ATTRIBUTES = ("song_collection",)
2023-09-14 21:35:37 +00:00
UPWARDS_COLLECTION_STRING_ATTRIBUTES = ("artist_collection", "label_collection")
2023-12-19 15:10:02 +00:00
def __init_collections__(self):
self.song_collection.append_object_to_attribute = {
"album_collection": self
}
self.song_collection.sync_on_append = {
2024-04-18 13:43:01 +00:00
"main_artist_collection": self.artist_collection
}
2023-02-23 22:52:41 +00:00
2024-04-17 12:15:56 +00:00
self.artist_collection.append_object_to_attribute = {
"main_album_collection": self
}
self.artist_collection.contain_given_in_attribute = {
"label_collection": self.label_collection
}
2024-01-15 11:48:36 +00:00
def _add_other_db_objects(self, object_type: Type[OuterProxy], object_list: List[OuterProxy]):
if object_type is Song:
self.song_collection.extend(object_list)
return
if object_type is Artist:
self.artist_collection.extend(object_list)
return
if object_type is Album:
return
if object_type is Label:
self.label_collection.extend(object_list)
return
@property
def indexing_values(self) -> List[Tuple[str, object]]:
return [
('id', self.id),
2024-04-12 12:14:10 +00:00
('title', unify(self.title)),
('barcode', self.barcode),
2023-03-10 09:21:57 +00:00
*[('url', source.url) for source in self.source_collection]
]
2023-03-10 09:54:15 +00:00
2023-03-10 08:09:35 +00:00
@property
def metadata(self) -> Metadata:
2023-12-19 15:10:02 +00:00
"""
TODO
- barcode
:return:
"""
2023-03-10 08:09:35 +00:00
return Metadata({
id3Mapping.ALBUM: [self.title],
id3Mapping.COPYRIGHT: [self.copyright],
2023-03-31 08:46:56 +00:00
id3Mapping.LANGUAGE: [self.iso_639_2_lang],
2023-03-10 08:09:35 +00:00
id3Mapping.ALBUM_ARTIST: [a.name for a in self.artist_collection],
2023-06-20 17:30:48 +00:00
id3Mapping.DATE: [self.date.strftime("%d%m")] if self.date.has_year and self.date.has_month else [],
id3Mapping.TIME: [self.date.strftime(("%H%M"))] if self.date.has_hour and self.date.has_minute else [],
id3Mapping.YEAR: [str(self.date.year).zfill(4)] if self.date.has_year else [],
id3Mapping.RELEASE_DATE: [self.date.timestamp],
id3Mapping.ORIGINAL_RELEASE_DATE: [self.date.timestamp],
2023-04-16 12:36:33 +00:00
id3Mapping.ALBUMSORTORDER: [str(self.albumsort)] if self.albumsort is not None else []
2023-03-10 08:09:35 +00:00
})
2022-12-16 17:26:05 +00:00
def __repr__(self):
2023-02-08 12:29:01 +00:00
return f"Album(\"{self.title}\")"
2022-12-16 17:26:05 +00:00
2023-03-10 09:54:15 +00:00
@property
def option_string(self) -> str:
return f"{self.__repr__()} " \
2024-04-16 15:50:01 +00:00
f"by Artist({OPTION_STRING_DELIMITER.join([artist.name + str(artist.id) for artist in self.artist_collection])}) " \
2023-03-10 09:54:15 +00:00
f"under Label({OPTION_STRING_DELIMITER.join([label.name for label in self.label_collection])})"
2023-03-10 20:28:13 +00:00
@property
2023-12-19 21:11:46 +00:00
def options(self) -> List[P]:
2023-12-29 19:18:34 +00:00
options = [*self.artist_collection, self, *self.song_collection]
2023-03-10 20:28:13 +00:00
2023-06-12 12:56:14 +00:00
return options
2023-03-10 20:28:13 +00:00
2023-02-23 22:52:41 +00:00
def update_tracksort(self):
"""
This updates the tracksort attributes, of the songs in
`self.song_collection`, and sorts the songs, if possible.
2022-12-09 17:24:58 +00:00
2023-02-23 22:52:41 +00:00
It is advised to only call this function, once all the tracks are
added to the songs.
2022-12-07 14:51:38 +00:00
2023-02-23 22:52:41 +00:00
:return:
"""
2023-04-03 16:09:05 +00:00
if self.song_collection.empty:
return
tracksort_map: Dict[int, Song] = {
2024-04-11 13:44:59 +00:00
song.tracksort: song for song in self.song_collection if song.tracksort != 0
}
2023-02-23 22:52:41 +00:00
2024-04-11 13:44:59 +00:00
existing_list = self.song_collection.shallow_list
for i in range(1, len(existing_list) + 1):
if i not in tracksort_map:
tracksort_map[i] = existing_list.pop(0)
tracksort_map[i].tracksort = i
2023-04-16 12:36:33 +00:00
def compile(self, merge_into: bool = False):
"""
compiles the recursive structures,
and does depending on the object some other stuff.
no need to override if only the recursive structure should be built.
override self.build_recursive_structures() instead
"""
self.update_tracksort()
self._build_recursive_structures(build_version=random.randint(0, 99999), merge=merge_into)
2023-03-10 08:09:35 +00:00
@property
def copyright(self) -> str:
2023-01-30 22:54:21 +00:00
if self.date is None:
2023-02-22 16:56:52 +00:00
return ""
2023-02-23 22:52:41 +00:00
if self.date.has_year or len(self.label_collection) == 0:
2023-02-22 16:56:52 +00:00
return ""
2023-01-13 13:37:15 +00:00
2023-02-23 22:52:41 +00:00
return f"{self.date.year} {self.label_collection[0].name}"
2023-01-13 13:37:15 +00:00
2023-02-27 15:51:55 +00:00
@property
def iso_639_2_lang(self) -> Optional[str]:
2023-01-13 13:37:15 +00:00
if self.language is None:
return None
return self.language.alpha_3
2023-02-28 00:13:53 +00:00
@property
def is_split(self) -> bool:
"""
A split Album is an Album from more than one Artists
usually half the songs are made by one Artist, the other half by the other one.
In this case split means either that or one artist featured by all songs.
:return:
"""
return len(self.artist_collection) > 1
2024-01-15 09:56:59 +00:00
2023-06-15 09:28:35 +00:00
@property
def album_type_string(self) -> str:
return self.album_type.value
2023-02-28 00:13:53 +00:00
2023-03-10 09:54:15 +00:00
2022-12-12 18:30:18 +00:00
"""
All objects dependent on Artist
"""
2023-12-19 12:58:39 +00:00
class Artist(Base):
2023-12-19 21:11:46 +00:00
name: str
unified_name: str
country: Country
formed_in: ID3Timestamp
notes: FormattedText
lyrical_themes: List[str]
2023-09-14 21:35:37 +00:00
2023-12-19 21:11:46 +00:00
general_genre: str
unformated_location: str
2023-05-24 23:27:05 +00:00
2023-12-19 21:11:46 +00:00
source_collection: SourceCollection
contact_collection: Collection[Contact]
2023-02-25 21:16:32 +00:00
2023-12-19 21:11:46 +00:00
feature_song_collection: Collection[Song]
main_album_collection: Collection[Album]
label_collection: Collection[Label]
2022-12-12 18:30:18 +00:00
2023-12-19 21:11:46 +00:00
_default_factories = {
2024-01-15 10:52:31 +00:00
"name": str,
2023-12-29 20:16:09 +00:00
"unified_name": lambda: None,
"country": lambda: None,
"unformated_location": lambda: None,
2023-12-19 21:11:46 +00:00
"formed_in": ID3Timestamp,
"notes": FormattedText,
"lyrical_themes": list,
"general_genre": lambda: "",
2023-12-20 08:55:09 +00:00
2023-12-19 21:11:46 +00:00
"source_collection": SourceCollection,
"feature_song_collection": Collection,
"main_album_collection": Collection,
"contact_collection": Collection,
"label_collection": Collection,
}
2023-08-30 19:14:03 +00:00
2024-04-10 08:25:05 +00:00
TITEL = "name"
2023-12-29 20:16:09 +00:00
# This is automatically generated
2024-01-15 10:52:31 +00:00
def __init__(self, name: str = "", unified_name: str = None, country: Country = None,
2023-12-29 20:50:40 +00:00
formed_in: ID3Timestamp = None, notes: FormattedText = None, lyrical_themes: List[str] = None,
2024-01-15 10:40:48 +00:00
general_genre: str = None, unformated_location: str = None, source_list: List[Source] = None,
2023-12-29 20:16:09 +00:00
contact_list: List[Contact] = None, feature_song_list: List[Song] = None,
main_album_list: List[Album] = None, label_list: List[Label] = None, **kwargs) -> None:
2023-12-29 20:50:40 +00:00
2023-12-29 20:16:09 +00:00
super().__init__(name=name, unified_name=unified_name, country=country, formed_in=formed_in, notes=notes,
lyrical_themes=lyrical_themes, general_genre=general_genre,
unformated_location=unformated_location, source_list=source_list, contact_list=contact_list,
feature_song_list=feature_song_list, main_album_list=main_album_list, label_list=label_list,
**kwargs)
2023-12-19 21:11:46 +00:00
DOWNWARDS_COLLECTION_STRING_ATTRIBUTES = ("feature_song_collection", "main_album_collection")
2024-01-15 09:56:59 +00:00
UPWARDS_COLLECTION_STRING_ATTRIBUTES = ("label_collection",)
2023-01-24 08:40:01 +00:00
2023-12-19 21:11:46 +00:00
def __init_collections__(self):
self.feature_song_collection.append_object_to_attribute = {
"feature_artist_collection": self
}
2023-12-19 21:11:46 +00:00
self.main_album_collection.append_object_to_attribute = {
"artist_collection": self
}
2024-01-15 09:56:59 +00:00
2023-12-19 21:11:46 +00:00
self.label_collection.append_object_to_attribute = {
"current_artist_collection": self
}
2023-04-16 12:36:33 +00:00
2024-01-15 11:48:36 +00:00
def _add_other_db_objects(self, object_type: Type[OuterProxy], object_list: List[OuterProxy]):
if object_type is Song:
# this doesn't really make sense
# self.feature_song_collection.extend(object_list)
return
if object_type is Artist:
return
if object_type is Album:
self.main_album_collection.extend(object_list)
return
if object_type is Label:
self.label_collection.extend(object_list)
return
2023-12-29 15:15:54 +00:00
@property
def options(self) -> List[P]:
options = [self, *self.main_album_collection.shallow_list, *self.feature_album]
print(options)
return options
2023-04-16 12:36:33 +00:00
def update_albumsort(self):
"""
This updates the albumsort attributes, of the albums in
`self.main_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.
:return:
"""
if len(self.main_album_collection) <= 0:
return
2023-12-19 21:11:46 +00:00
type_section: Dict[AlbumType, int] = defaultdict(lambda: 2, {
2023-04-16 15:39:53 +00:00
AlbumType.OTHER: 0, # if I don't know it, I add it to the first section
AlbumType.STUDIO_ALBUM: 0,
AlbumType.EP: 0,
AlbumType.SINGLE: 1
2023-09-10 14:27:09 +00:00
}) if main_settings["sort_album_by_type"] else defaultdict(lambda: 0)
2023-04-16 15:39:53 +00:00
sections = defaultdict(list)
# order albums in the previously defined section
album: Album
for album in self.main_album_collection:
sections[type_section[album.album_type]].append(album)
def sort_section(_section: List[Album], last_albumsort: int) -> int:
# album is just a value used in loops
nonlocal album
2023-09-10 14:27:09 +00:00
if main_settings["sort_by_date"]:
2023-04-16 15:39:53 +00:00
_section.sort(key=lambda _album: _album.date, reverse=True)
new_last_albumsort = last_albumsort
for album_index, album in enumerate(_section):
if album.albumsort is None:
album.albumsort = new_last_albumsort = album_index + 1 + last_albumsort
_section.sort(key=lambda _album: _album.albumsort)
return new_last_albumsort
# sort the sections individually
_last_albumsort = 1
for section_index in sorted(sections):
_last_albumsort = sort_section(sections[section_index], _last_albumsort)
# merge all sections again
album_list = []
for section_index in sorted(sections):
album_list.extend(sections[section_index])
# replace the old collection with the new one
self.main_album_collection: Collection = Collection(data=album_list, element_type=Album)
2023-04-16 12:36:33 +00:00
@property
def indexing_values(self) -> List[Tuple[str, object]]:
return [
('id', self.id),
2024-04-12 12:14:10 +00:00
('name', unify(self.name)),
*[('url', source.url) for source in self.source_collection],
*[('contact', contact.value) for contact in self.contact_collection]
]
2023-03-10 09:54:15 +00:00
2023-03-10 08:09:35 +00:00
@property
def metadata(self) -> Metadata:
metadata = Metadata({
id3Mapping.ARTIST: [self.name]
})
2023-03-10 09:21:57 +00:00
metadata.merge_many([s.get_artist_metadata() for s in self.source_collection])
2023-03-10 08:09:35 +00:00
return metadata
"""
2023-09-13 14:01:01 +00:00
def __str__(self, include_notes: bool = False):
2023-02-06 08:16:28 +00:00
string = self.name or ""
2023-09-13 14:01:01 +00:00
if include_notes:
plaintext_notes = self.notes.get_plaintext()
if plaintext_notes is not None:
string += "\n" + plaintext_notes
2023-02-06 08:16:28 +00:00
return string
"""
2022-12-12 18:30:18 +00:00
2022-12-16 15:59:21 +00:00
def __repr__(self):
2023-02-23 22:52:41 +00:00
return f"Artist(\"{self.name}\")"
2023-03-10 09:54:15 +00:00
@property
def option_string(self) -> str:
return f"{self.__repr__()} " \
f"under Label({OPTION_STRING_DELIMITER.join([label.name for label in self.label_collection])})"
2023-03-10 20:28:13 +00:00
@property
2023-12-19 21:11:46 +00:00
def options(self) -> List[P]:
2023-03-10 20:28:13 +00:00
options = [self]
options.extend(self.main_album_collection)
options.extend(self.feature_song_collection)
2023-06-12 12:56:14 +00:00
return options
2023-03-10 20:28:13 +00:00
2023-03-10 07:27:01 +00:00
@property
def feature_album(self) -> Album:
return Album(
2022-12-12 18:30:18 +00:00
title="features",
2023-02-22 16:56:52 +00:00
album_status=AlbumStatus.UNRELEASED,
album_type=AlbumType.COMPILATION_ALBUM,
2022-12-12 18:30:18 +00:00
is_split=True,
albumsort=666,
2023-02-23 22:52:41 +00:00
dynamic=True,
2023-03-31 08:34:29 +00:00
song_list=self.feature_song_collection.shallow_list
2022-12-12 18:30:18 +00:00
)
2023-02-09 14:49:22 +00:00
def get_all_songs(self) -> List[Song]:
"""
returns a list of all Songs.
2023-02-22 16:56:52 +00:00
probably not that useful, because it is unsorted
2023-02-09 14:49:22 +00:00
"""
2023-02-23 22:52:41 +00:00
collection = self.feature_song_collection.copy()
2023-02-09 14:49:22 +00:00
for album in self.discography:
2023-02-23 22:52:41 +00:00
collection.extend(album.song_collection)
2023-02-09 14:49:22 +00:00
return collection
2022-12-12 18:30:18 +00:00
2023-03-10 07:27:01 +00:00
@property
def discography(self) -> List[Album]:
2023-02-23 22:52:41 +00:00
flat_copy_discography = self.main_album_collection.copy()
2023-03-10 09:21:57 +00:00
flat_copy_discography.append(self.feature_album)
2022-12-12 18:30:18 +00:00
2022-12-16 15:59:21 +00:00
return flat_copy_discography
2022-12-12 18:30:18 +00:00
2023-02-09 08:40:57 +00:00
2023-02-23 22:52:41 +00:00
"""
Label
"""
2023-12-19 12:58:39 +00:00
class Label(Base):
2023-09-14 21:35:37 +00:00
COLLECTION_STRING_ATTRIBUTES = ("album_collection", "current_artist_collection")
2023-12-19 21:11:46 +00:00
2023-09-14 21:35:37 +00:00
DOWNWARDS_COLLECTION_STRING_ATTRIBUTES = COLLECTION_STRING_ATTRIBUTES
2023-12-19 21:11:46 +00:00
name: str
unified_name: str
notes: FormattedText
source_collection: SourceCollection
contact_collection: Collection[Contact]
2023-09-14 21:35:37 +00:00
2023-12-19 21:11:46 +00:00
album_collection: Collection[Album]
current_artist_collection: Collection[Artist]
_default_factories = {
"notes": FormattedText,
"album_collection": Collection,
"current_artist_collection": Collection,
"source_collection": SourceCollection,
2023-12-20 08:55:09 +00:00
"contact_collection": Collection,
2023-12-29 20:50:40 +00:00
"name": lambda: None,
2023-12-20 08:55:09 +00:00
"unified_name": lambda: None,
2023-12-19 21:11:46 +00:00
}
2023-05-24 23:27:05 +00:00
2024-04-10 08:25:05 +00:00
TITEL = "name"
2023-12-29 20:50:40 +00:00
def __init__(self, name: str = None, unified_name: str = None, notes: FormattedText = None,
2024-01-15 10:40:48 +00:00
source_list: List[Source] = None, contact_list: List[Contact] = None,
2023-12-29 20:16:09 +00:00
album_list: List[Album] = None, current_artist_list: List[Artist] = None, **kwargs) -> None:
super().__init__(name=name, unified_name=unified_name, notes=notes, source_list=source_list,
contact_list=contact_list, album_list=album_list, current_artist_list=current_artist_list,
**kwargs)
2023-02-23 22:52:41 +00:00
2024-04-17 12:15:56 +00:00
def __init_collections__(self):
self.album_collection.append_object_to_attribute = {
"label_collection": self
}
self.current_artist_collection.append_object_to_attribute = {
"label_collection": self
}
@property
def indexing_values(self) -> List[Tuple[str, object]]:
return [
('id', self.id),
2024-04-12 12:14:10 +00:00
('name', unify(self.name)),
2023-03-10 09:21:57 +00:00
*[('url', source.url) for source in self.source_collection]
]
2023-03-10 20:28:13 +00:00
2024-01-15 11:48:36 +00:00
def _add_other_db_objects(self, object_type: Type[OuterProxy], object_list: List[OuterProxy]):
if object_type is Song:
return
if object_type is Artist:
self.current_artist_collection.extend(object_list)
return
if object_type is Album:
self.album_collection.extend(object_list)
return
2023-03-10 20:28:13 +00:00
@property
2023-12-19 21:11:46 +00:00
def options(self) -> List[P]:
2023-03-10 20:28:13 +00:00
options = [self]
options.extend(self.current_artist_collection.shallow_list)
2023-03-20 22:11:55 +00:00
options.extend(self.album_collection.shallow_list)
2024-01-15 09:56:59 +00:00
2023-06-12 12:56:14 +00:00
return options
2024-04-10 11:47:35 +00:00
@property
def option_string(self):
return self.__repr__()