diff --git a/src/goof.py b/src/goof.py index 1e3ae83..2966c77 100644 --- a/src/goof.py +++ b/src/goof.py @@ -1,5 +1,7 @@ import music_kraken +music_kraken.clear_cache() + artist = music_kraken.Artist( name="I'm in a Coffin" ) @@ -11,5 +13,6 @@ song = music_kraken.Song( ) print(song) +print(song.id) -music_kraken.fetch_sources([song]) +# music_kraken.fetch_sources([song]) diff --git a/src/music_kraken/database/__init__.py b/src/music_kraken/database/__init__.py index 58217a1..8730bae 100644 --- a/src/music_kraken/database/__init__.py +++ b/src/music_kraken/database/__init__.py @@ -1,17 +1,13 @@ from . import ( temp_database, - song, - artist, - metadata, - source, - target, + song ) Song = song.Song Artist = song.Artist -Source = source.Source -Target = target.Target -Metadata = metadata.Metadata +Source = song.Source +Target = song.Target +Metadata = song.Metadata Lyrics = song.Lyrics cache = temp_database.TempDatabase() diff --git a/src/music_kraken/database/artist.py b/src/music_kraken/database/artist.py deleted file mode 100644 index 743db33..0000000 --- a/src/music_kraken/database/artist.py +++ /dev/null @@ -1,15 +0,0 @@ -class Artist: - def __init__(self, artist_data) -> None: - self.artist_data = artist_data - - self.id = self.artist_data['id'] - self.name = self.artist_data['name'] - - def __eq__(self, __o: object) -> bool: - if type(__o) != type(self): - return False - return self.id == __o.id - - def __str__(self) -> str: - return self.name - diff --git a/src/music_kraken/database/database.py b/src/music_kraken/database/database.py index 6f7bce4..32ea67a 100644 --- a/src/music_kraken/database/database.py +++ b/src/music_kraken/database/database.py @@ -3,10 +3,12 @@ import sqlite3 import os import logging import json -import requests from pkg_resources import resource_string -from . import song +from .song import ( + Song, + Lyrics +) from .get_song import get_song_from_response from ..utils.shared import ( DATABASE_LOGGER @@ -153,7 +155,24 @@ SELECT DISTINCT ) ) ), + 'lyrics', json_group_array( + ( + SELECT DISTINCT json_object( + 'text', lyrics_table.text + 'language', lyrics_table.language + ) + ) + ), + 'target', json_group_array( + ( + SELECT DISTINCT json_object( + 'file', target.file + 'path', target.path + ) + ) + ), 'id', track.id, + 'mb_id', track.mb_id, 'tracknumber', track.tracknumber, 'titlesort', track.tracknumber, 'musicbrainz_releasetrackid', track.id, @@ -187,13 +206,15 @@ LEFT JOIN release_group ON release_.id = release_group.id LEFT JOIN artist_track ON track.id = artist_track.track_id LEFT JOIN artist ON artist_track.artist_id = artist.id LEFT JOIN source src_table ON track.id = src_table.track_id +LEFT JOIN lyrics lyrics_table ON track.id = lyrics_table.track_id +LEFT JOIN target ON track.id = target.track_id WHERE {where_arg} GROUP BY track.id; """ return query - def get_custom_track(self, custom_where: list) -> List[song.Song]: + def get_custom_track(self, custom_where: list) -> List[Song]: query = Database.get_custom_track_query(custom_where=custom_where) return [get_song_from_response(json.loads(i[0])) for i in self.cursor.execute(query)] @@ -205,22 +226,22 @@ GROUP BY track.id; return resulting_tracks[0] - def get_tracks_to_download(self) -> List[song.Song]: + def get_tracks_to_download(self) -> List[Song]: return self.get_custom_track(['track.downloaded == 0']) - def get_tracks_without_src(self) -> List[song.Song]: + def get_tracks_without_src(self) -> List[Song]: return self.get_custom_track(["(track.url IS NULL OR track.src IS NULL)"]) - def get_tracks_without_isrc(self) -> List[song.Song]: + def get_tracks_without_isrc(self) -> List[Song]: return self.get_custom_track(["track.isrc IS NULL"]) - def get_tracks_without_filepath(self) -> List[song.Song]: + def get_tracks_without_filepath(self) -> List[Song]: return self.get_custom_track(["(track.file IS NULL OR track.path IS NULL OR track.genre IS NULL)"]) - def get_tracks_for_lyrics(self) -> List[song.Song]: + def get_tracks_for_lyrics(self) -> List[Song]: return self.get_custom_track(["track.lyrics IS NULL"]) - def add_lyrics(self, song: song.Song, lyrics: song.Lyrics): + def add_lyrics(self, song: Song, lyrics: Lyrics): query = f""" UPDATE track SET lyrics = ? @@ -264,6 +285,13 @@ WHERE '{track_id}' == id; self.cursor.execute(query, (file, path, genre)) self.connection.commit() + def write_song(self, song: Song): + pass + + def write_many_song(self, songs: List[Song]): + for song in songs: + self.write_song(song=song) + if __name__ == "__main__": import tempfile diff --git a/src/music_kraken/database/database_object.py b/src/music_kraken/database/database_object.py new file mode 100644 index 0000000..d889a23 --- /dev/null +++ b/src/music_kraken/database/database_object.py @@ -0,0 +1,23 @@ +import uuid + +from ..utils.shared import ( + SONG_LOGGER as logger +) + +class DatabaseObject: + def __init__(self, id_: str = None) -> None: + self.id_: str | None = id_ + + def get_id(self): + """ + returns the id if it is set, else + it returns a randomly generated UUID + https://docs.python.org/3/library/uuid.html + """ + if self.id_ is None: + self.id_ = str(uuid.uuid4()) + logger.info(f"id for {self.__str__()} isn't set. Setting to {self.id_}") + + return self.id_ + + id = property(fget=get_id) diff --git a/src/music_kraken/database/metadata.py b/src/music_kraken/database/metadata.py deleted file mode 100644 index b14d4c4..0000000 --- a/src/music_kraken/database/metadata.py +++ /dev/null @@ -1,17 +0,0 @@ -from mutagen.easyid3 import EasyID3 - -class Metadata: - def __init__(self) -> None: - self.data = {} - - def get_all_metadata(self): - return list(self.data.items()) - - def __setitem__(self, item, value): - if item in EasyID3.valid_keys.keys(): - self.data[item] = value - - def __getitem__(self, item): - if item not in self.data: - return None - return self.data[item] diff --git a/src/music_kraken/database/song.py b/src/music_kraken/database/song.py index f31d9de..ff12b7c 100644 --- a/src/music_kraken/database/song.py +++ b/src/music_kraken/database/song.py @@ -1,9 +1,77 @@ from typing import List +import uuid +import os +from mutagen.easyid3 import EasyID3 -from .artist import Artist -from .metadata import Metadata -from .source import Source -from .target import Target +from ..utils.shared import ( + MUSIC_DIR, + SONG_LOGGER as logger +) +from .database_object import DatabaseObject + +class Metadata: + def __init__(self) -> None: + self.data = {} + + def get_all_metadata(self): + return list(self.data.items()) + + def __setitem__(self, item, value): + if item in EasyID3.valid_keys.keys(): + self.data[item] = value + + def __getitem__(self, item): + if item not in self.data: + return None + return self.data[item] + + +class Source: + def __init__(self, src_data) -> None: + self.src_data = src_data + + self.src = self.src_data['src'] + self.url = self.src_data['url'] + + +class Target: + def __init__(self) -> None: + self._file = None + self._path = None + + def set_file(self, _file: str): + self._file = _file + + def get_file(self) -> str | None: + if self._file is None: + return None + return os.path.join(MUSIC_DIR, self._file) + + def set_path(self, _path: str): + self._path = _path + + def get_path(self) -> str | None: + if self._path is None: + return None + return os.path.join(MUSIC_DIR, self._path) + + def get_exists_on_disc(self) -> bool: + """ + returns True when file can be found on disc + returns False when file can't be found on disc or no filepath is set + """ + if not self.is_set(): + return False + + return os.path.exists(self.file) + + def is_set(self) -> bool: + return not (self._file is None or self._path is None) + + file = property(fget=get_file, fset=set_file) + path = property(fget=get_path, fset=set_path) + + exists_on_disc = property(fget=get_exists_on_disc) class Artist: @@ -50,7 +118,7 @@ class LyricsContainer: is_empty = property(fget=lambda self: len(self.lyrics_list) <= 0) -class Song: +class Song(DatabaseObject): def __init__( self, id_: str = None, @@ -71,8 +139,9 @@ class Song: target: Each Song can have exactly one target which can be either full or empty lyrics: There can be multiple lyrics. Each Lyrics object can me added to multiple lyrics """ + super().__init__(id_=id_) # attributes - self.id: str | None = id_ + # self.id_: str | None = id_ self.mb_id: str | None = mb_id self.title: str | None = title self.release: str | None = release diff --git a/src/music_kraken/database/source.py b/src/music_kraken/database/source.py deleted file mode 100644 index 11888f4..0000000 --- a/src/music_kraken/database/source.py +++ /dev/null @@ -1,6 +0,0 @@ -class Source: - def __init__(self, src_data) -> None: - self.src_data = src_data - - self.src = self.src_data['src'] - self.url = self.src_data['url'] diff --git a/src/music_kraken/database/target.py b/src/music_kraken/database/target.py deleted file mode 100644 index ae47f0f..0000000 --- a/src/music_kraken/database/target.py +++ /dev/null @@ -1,45 +0,0 @@ -import os - -from ..utils.shared import ( - MUSIC_DIR -) - - -class Target: - def __init__(self) -> None: - self._file = None - self._path = None - - def set_file(self, _file: str): - self._file = _file - - def get_file(self) -> str | None: - if self._file is None: - return None - return os.path.join(MUSIC_DIR, self._file) - - def set_path(self, _path: str): - self._path = _path - - def get_path(self) -> str | None: - if self._path is None: - return None - return os.path.join(MUSIC_DIR, self._path) - - def get_exists_on_disc(self) -> bool: - """ - returns True when file can be found on disc - returns False when file can't be found on disc or no filepath is set - """ - if not self.is_set(): - return False - - return os.path.exists(self.file) - - def is_set(self) -> bool: - return not (self._file is None or self._path is None) - - file = property(fget=get_file, fset=set_file) - path = property(fget=get_path, fset=set_path) - - exists_on_disc = property(fget=get_exists_on_disc) diff --git a/src/music_kraken/static_files/temp_database_structure.sql b/src/music_kraken/static_files/temp_database_structure.sql index 4b84f1e..1fd36d2 100644 --- a/src/music_kraken/static_files/temp_database_structure.sql +++ b/src/music_kraken/static_files/temp_database_structure.sql @@ -45,6 +45,7 @@ CREATE TABLE track ( id TEXT PRIMARY KEY NOT NULL, downloaded BOOLEAN NOT NULL DEFAULT 0, release_id TEXT NOT NULL, + mb_id TEXT, track TEXT, length INT, tracknumber TEXT, @@ -57,6 +58,20 @@ CREATE TABLE track ( src TEXT ); +DROP TABLE IF EXISTS lyrics; +CREATE TABLE lyrics ( + track_id TEXT NOT NULL, + text TEXT, + language TEXT +); + +DROP TABLE IF EXISTS target; +CREATE TABLE target ( + track_id TEXT NOT NULL, + file TEXT, + path TEXT +); + DROP TABLE IF EXISTS source; CREATE TABLE source ( track_id TEXT NOT NULL, diff --git a/src/music_kraken/utils/shared.py b/src/music_kraken/utils/shared.py index b18d81a..4b5e037 100644 --- a/src/music_kraken/utils/shared.py +++ b/src/music_kraken/utils/shared.py @@ -27,6 +27,7 @@ logging.basicConfig( ] ) +SONG_LOGGER = logging.getLogger("song-obj") SEARCH_LOGGER = logging.getLogger("mb-cli") INIT_PATH_LOGGER = logging.getLogger("init_path") DATABASE_LOGGER = logging.getLogger("database")