diff --git a/assets/02.png b/assets/02.png new file mode 100644 index 0000000..1bc91de Binary files /dev/null and b/assets/02.png differ diff --git a/assets/logo.jpg b/assets/logo.jpg index a4f0a94..c31aed3 100644 Binary files a/assets/logo.jpg and b/assets/logo.jpg differ diff --git a/assets/logo2.jpg b/assets/logo2.jpg deleted file mode 100644 index cfa2081..0000000 Binary files a/assets/logo2.jpg and /dev/null differ diff --git a/assets/logos/.png b/assets/logos/.png new file mode 100644 index 0000000..df21544 Binary files /dev/null and b/assets/logos/.png differ diff --git a/assets/logos/00.jpg b/assets/logos/00.jpg new file mode 100644 index 0000000..a4f0a94 Binary files /dev/null and b/assets/logos/00.jpg differ diff --git a/assets/logos/01.png b/assets/logos/01.png new file mode 100644 index 0000000..e0c807d Binary files /dev/null and b/assets/logos/01.png differ diff --git a/assets/logos/01.svg b/assets/logos/01.svg new file mode 100644 index 0000000..13e2386 --- /dev/null +++ b/assets/logos/01.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + diff --git a/assets/logos/02.png b/assets/logos/02.png new file mode 100644 index 0000000..1bc91de Binary files /dev/null and b/assets/logos/02.png differ diff --git a/assets/logos/02.svg b/assets/logos/02.svg new file mode 100644 index 0000000..306a88d --- /dev/null +++ b/assets/logos/02.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + diff --git a/assets/logos/craiyon_142854_simplistic_black_and_white_logo_of_an_octopus_wearing_headphones__svg__cute__octupus.png b/assets/logos/craiyon_142854_simplistic_black_and_white_logo_of_an_octopus_wearing_headphones__svg__cute__octupus.png new file mode 100644 index 0000000..7c75bb2 Binary files /dev/null and b/assets/logos/craiyon_142854_simplistic_black_and_white_logo_of_an_octopus_wearing_headphones__svg__cute__octupus.png differ diff --git a/assets/logos/craiyon_142854_simplistic_black_and_white_logo_of_an_octopus_wearing_headphones__svg__cute__octupus.svg b/assets/logos/craiyon_142854_simplistic_black_and_white_logo_of_an_octopus_wearing_headphones__svg__cute__octupus.svg new file mode 100644 index 0000000..bac4a90 --- /dev/null +++ b/assets/logos/craiyon_142854_simplistic_black_and_white_logo_of_an_octopus_wearing_headphones__svg__cute__octupus.svg @@ -0,0 +1,137 @@ + + + + + + + + + + + + + diff --git a/assets/logos/craiyon_144924_simplistic__black_and_white_logo__octopus_wearing_headphones__svg__cute__in_frame__ce.png b/assets/logos/craiyon_144924_simplistic__black_and_white_logo__octopus_wearing_headphones__svg__cute__in_frame__ce.png new file mode 100644 index 0000000..df21544 Binary files /dev/null and b/assets/logos/craiyon_144924_simplistic__black_and_white_logo__octopus_wearing_headphones__svg__cute__in_frame__ce.png differ diff --git a/src/music_kraken/objects/__init__.py b/src/music_kraken/objects/__init__.py index 232e379..ae540b7 100644 --- a/src/music_kraken/objects/__init__.py +++ b/src/music_kraken/objects/__init__.py @@ -3,7 +3,8 @@ from . import ( metadata, source, parents, - formatted_text + formatted_text, + album ) MusicObject = parents.DatabaseObject @@ -21,6 +22,8 @@ Source = source.Source Target = song.Target Lyrics = song.Lyrics +AlbumType = album.AlbumType +AlbumStatus = album.AlbumStatus Album = song.Album FormattedText = formatted_text.FormattedText diff --git a/src/music_kraken/objects/album.py b/src/music_kraken/objects/album.py new file mode 100644 index 0000000..2bab8d0 --- /dev/null +++ b/src/music_kraken/objects/album.py @@ -0,0 +1,25 @@ +from enum import Enum + + +class AlbumStatus(Enum): + """ + Enum class representing the possible statuses of an album. + """ + UNRELEASED = "Unreleased" + RELEASED = "Released" + LEAKED = "Leaked" + OFFICIAL = "Official" + BOOTLEG = "Bootleg" + + +class AlbumType(Enum): + """ + Enum class representing the possible types of an album. + """ + STUDIO_ALBUM = "Studio Album" + EP = "EP (Extended Play)" + SINGLE = "Single" + LIVE_ALBUM = "Live Album" + COMPILATION_ALBUM = "Compilation Album" + MIXTAPE = "Mixtape" + OTHER = "Other" diff --git a/src/music_kraken/objects/song.py b/src/music_kraken/objects/song.py index fc4a526..471dff6 100644 --- a/src/music_kraken/objects/song.py +++ b/src/music_kraken/objects/song.py @@ -1,5 +1,5 @@ import os -from typing import List +from typing import List, Optional, Type import pycountry import copy @@ -25,11 +25,14 @@ from .source import ( ) from .formatted_text import FormattedText from .collection import Collection +from .album import AlbumType, AlbumStatus """ All Objects dependent """ +CountryTyping = type(list(pycountry.countries)[0]) + class Target(DatabaseObject, SongAttribute): """ @@ -49,7 +52,7 @@ class Target(DatabaseObject, SongAttribute): def set_file(self, _file: str): self._file = _file - def get_file(self) -> str | None: + def get_file(self) -> Optional[str]: if self._file is None: return None return os.path.join(MUSIC_DIR, self._file) @@ -57,7 +60,7 @@ class Target(DatabaseObject, SongAttribute): def set_path(self, _path: str): self._path = _path - def get_path(self) -> str | None: + def get_path(self) -> Optional[str]: if self._path is None: return None return os.path.join(MUSIC_DIR, self._path) @@ -85,7 +88,7 @@ class Lyrics(DatabaseObject, SongAttribute, SourceAttribute, MetadataAttribute): def __init__( self, text: str, - language: str, + language: pycountry.Languages, id_: str = None, source_list: List[Source] = None ) -> None: @@ -112,7 +115,6 @@ class Song(DatabaseObject, SourceAttribute, MetadataAttribute): def __init__( self, id_: str = None, - mb_id: str = None, title: str = None, isrc: str = None, length: int = None, @@ -121,9 +123,9 @@ class Song(DatabaseObject, SourceAttribute, MetadataAttribute): source_list: List[Source] = None, target: Target = None, lyrics_list: List[Lyrics] = None, - album=None, - main_artist_list: list = None, - feature_artist_list: list = None, + album_list: Type['Album'] = None, + main_artist_list: List[Type['Artist']] = None, + feature_artist_list: List[Type['Artist']] = None, **kwargs ) -> None: """ @@ -135,7 +137,6 @@ class Song(DatabaseObject, SourceAttribute, MetadataAttribute): self.title: str = title self.isrc: str = isrc self.length: int = length - self.mb_id: str | None = mb_id self.tracksort: int = tracksort or 0 self.genre: str = genre @@ -146,7 +147,12 @@ class Song(DatabaseObject, SourceAttribute, MetadataAttribute): # initialize with either a passed in album, or an empty one, # so it can at least properly generate dynamic attributes - self._album = album or Album(empty=True) + + """ + TODO + put in collection + """ + self._album: List[Type['Album']] = album_list or [] self.album = album self.main_artist_collection = Collection( @@ -168,7 +174,7 @@ class Song(DatabaseObject, SourceAttribute, MetadataAttribute): def get_artist_credits(self) -> str: main_artists = ", ".join([artist.name for artist in self.main_artist_collection]) feature_artists = ", ".join([artist.name for artist in self.feature_artist_collection]) - + if len(feature_artists) == 0: return main_artists return f"{main_artists} feat. {feature_artists}" @@ -224,9 +230,9 @@ class Song(DatabaseObject, SourceAttribute, MetadataAttribute): def get_option_string(self) -> str: return f"Song({self.title}) of Album({self.album.title}) from Artists({self.get_artist_credits()})" - tracksort_str = property(fget=get_tracksort_str) - main_artist_list: list = property(fget=lambda self: self.main_artist_collection.copy()) - feature_artist_list: list = property(fget=lambda self: self.feature_artist_collection.copy()) + tracksort_str: List[Type['Album']] = property(fget=get_tracksort_str) + main_artist_list: List[Type['Artist']] = property(fget=lambda self: self.main_artist_collection.copy()) + feature_artist_list: List[Type['Artist']] = property(fget=lambda self: self.feature_artist_collection.copy()) """ @@ -240,10 +246,8 @@ class Album(DatabaseObject, SourceAttribute, MetadataAttribute): id_: str = None, title: str = None, label: str = None, - album_status: str = None, language: pycountry.Languages = None, date: ID3Timestamp = None, - country: str = None, barcode: str = None, is_split: bool = False, albumsort: int = None, @@ -251,7 +255,8 @@ class Album(DatabaseObject, SourceAttribute, MetadataAttribute): source_list: List[Source] = None, artist_list: list = None, tracklist: List[Song] = None, - album_type: str = None, + album_status: AlbumStatus = None, + album_type: AlbumType = None, **kwargs ) -> None: DatabaseObject.__init__(self, id_=id_, dynamic=dynamic, **kwargs) @@ -260,18 +265,17 @@ class Album(DatabaseObject, SourceAttribute, MetadataAttribute): TODO add to db """ - self.album_type = album_type + self.album_type: AlbumType = album_type self.title: str = title - self.album_status: str = album_status + self.album_status: AlbumStatus = album_status self.label = label self.language: pycountry.Languages = language self.date: ID3Timestamp = date or ID3Timestamp() - self.country: str = country """ TODO find out the id3 tag for barcode and implement it - maybee look at how mutagen does it with easy_id3 + maybe look at how mutagen does it with easy_id3 """ self.barcode: str = barcode self.is_split: bool = is_split @@ -280,8 +284,7 @@ class Album(DatabaseObject, SourceAttribute, MetadataAttribute): implement a function in the Artist class, to set albumsort with help of the release year """ - self.albumsort: int | None = albumsort - + self.albumsort: Optional[int] = albumsort self._tracklist = Collection( data=tracklist or [], @@ -295,7 +298,6 @@ class Album(DatabaseObject, SourceAttribute, MetadataAttribute): element_type=Artist ) - def __str__(self) -> str: return f"-----{self.title}-----\n{self.tracklist}" @@ -329,13 +331,13 @@ class Album(DatabaseObject, SourceAttribute, MetadataAttribute): def get_copyright(self) -> str: if self.date is None: - return None + return "" if self.date.year == 1 or self.label is None: - return None + return "" return f"{self.date.year} {self.label}" - def get_iso_639_2_lang(self) -> str: + def get_iso_639_2_lang(self) -> Optional[str]: if self.language is None: return None @@ -350,11 +352,10 @@ class Album(DatabaseObject, SourceAttribute, MetadataAttribute): options.append(new_track) return options - + def get_option_string(self) -> str: return f"Album: {self.title}; Artists {', '.join([i.name for i in self.artists])}" - copyright = property(fget=get_copyright) iso_639_2_language = property(fget=get_iso_639_2_lang) tracklist: Collection = property(fget=lambda self: self._tracklist, fset=set_tracklist) @@ -383,7 +384,7 @@ class Artist(DatabaseObject, SourceAttribute, MetadataAttribute): notes: FormattedText = None, lyrical_themes: List[str] = None, general_genre: str = "", - country=None, + country: CountryTyping = None, formed_in: ID3Timestamp = None ): DatabaseObject.__init__(self, id_=id_) @@ -391,7 +392,7 @@ class Artist(DatabaseObject, SourceAttribute, MetadataAttribute): """ TODO implement album type and notes """ - self.country: pycountry.Country = country + self.country: CountryTyping = country self.formed_in: ID3Timestamp = formed_in """ notes, generall genre, lyrics themes are attributes @@ -429,30 +430,29 @@ class Artist(DatabaseObject, SourceAttribute, MetadataAttribute): def __repr__(self): return self.__str__() - def __eq__(self, __o: object) -> bool: + def __eq__(self, __o: DatabaseObject) -> bool: return self.id_ == __o.id_ def get_features(self) -> Album: feature_release = Album( title="features", - album_status="dynamic", + album_status=AlbumStatus.UNRELEASED, + album_type=AlbumType.COMPILATION_ALBUM, is_split=True, albumsort=666, dynamic=True ) - for feature in self.feature_songs: - feature_release.add_song(feature) return feature_release def get_all_songs(self) -> List[Song]: """ returns a list of all Songs. - probaply not that usefull, because it is unsorted + probably not that useful, because it is unsorted """ collection = [] for album in self.discography: - collection.extend(album) + collection.extend(album.tracklist) return collection diff --git a/src/tests/__init__.py b/src/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/tests/conftest.py b/src/tests/conftest.py new file mode 100644 index 0000000..3bf1e84 --- /dev/null +++ b/src/tests/conftest.py @@ -0,0 +1,5 @@ +import os +import sys + +# Add the parent directory of the current file (i.e., the "tests" directory) to sys.path +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) diff --git a/src/tests/example_data_objects.py b/src/tests/example_data_objects.py new file mode 100644 index 0000000..56252a3 --- /dev/null +++ b/src/tests/example_data_objects.py @@ -0,0 +1,46 @@ +import pycountry + +from ..music_kraken.objects import ( + Song, + Source, + SourcePages, + Target, + Lyrics, + Album +) + +""" +TODO +create enums for Album.album_status +move country from Album to Artist, and use pycountry.Countries +""" + +song = Song( + title="title", + isrc="isrc", + length=666, + tracksort=1, + genre="horrorcore", + source_list=[ + Source(SourcePages.YOUTUBE, "https://www.youtube.com/watch?v=dQw4w9WgXcQ"), + Source(SourcePages.SPOTIFY, "https://open.spotify.com/track/6rqhFgbbKwnb9MLmUQDhG6"), + Source(SourcePages.BANDCAMP, "https://metalband.bandcamp.com/track/song1") + ], + target=Target(file="song.mp3", path="~/Music"), + lyrics_list=[ + Lyrics(text="some song lyrics", language="en") + ], + album=Album( + title="some album", + label="braindead", + album_status="official", + language=pycountry.languages.get(alpha_2='de'), + ) +) + + +song1_sources = [ + Source(SourcePages.YOUTUBE, "https://www.youtube.com/watch?v=dQw4w9WgXcQ"), + Source(SourcePages.SPOTIFY, "https://open.spotify.com/track/6rqhFgbbKwnb9MLmUQDhG6"), + Source(SourcePages.BANDCAMP, "https://metalband.bandcamp.com/track/song1") +] diff --git a/src/try.py b/src/try.py new file mode 100644 index 0000000..24690da --- /dev/null +++ b/src/try.py @@ -0,0 +1,3 @@ +from tests import example_data_objects + +