refactored Song object. I hooooope it works

This commit is contained in:
Lars Noack 2022-11-30 12:55:35 +01:00
parent ddf19c4716
commit 12c453e005
5 changed files with 88 additions and 124 deletions

View File

@ -1,6 +1,7 @@
import music_kraken as mk import music_kraken as mk
print(mk.__file__) print(mk.__file__)
"""
mk.clear_cache() mk.clear_cache()
song_list = mk.cache.get_custom_track([]) song_list = mk.cache.get_custom_track([])
print(mk.cache, len(song_list)) print(mk.cache, len(song_list))
@ -14,4 +15,5 @@ print(song.length)
mk.set_targets(genre="test") mk.set_targets(genre="test")
song = mk.cache.get_track_metadata(musicbrainz_releasetrackid=id_) song = mk.cache.get_track_metadata(musicbrainz_releasetrackid=id_)
mk.fetch_sources([song]) """
mk.fetch_audios(mk.cache.get_tracks_to_download())

View File

@ -16,7 +16,7 @@ calling of the functions do search for a song and to download it.
class AudioSource: class AudioSource:
@classmethod @classmethod
def fetch_source(cls, row: dict): def fetch_source(cls, row: dict):
logger.info(f"try getting source {row['title']} from {cls.__name__}") logger.info(f"try getting source {row.title} from {cls.__name__}")
@classmethod @classmethod
def fetch_audio(cls, song: song_objects.Song, src: song_objects.Source): def fetch_audio(cls, song: song_objects.Song, src: song_objects.Source):

View File

@ -7,6 +7,7 @@ import requests
from pkg_resources import resource_string from pkg_resources import resource_string
from . import song from . import song
from .get_song import get_song_from_response
from ..utils.shared import ( from ..utils.shared import (
DATABASE_LOGGER DATABASE_LOGGER
) )
@ -194,7 +195,7 @@ GROUP BY track.id;
def get_custom_track(self, custom_where: list) -> List[song.Song]: def get_custom_track(self, custom_where: list) -> List[song.Song]:
query = Database.get_custom_track_query(custom_where=custom_where) query = Database.get_custom_track_query(custom_where=custom_where)
return [song.Song(json.loads(i[0])) for i in self.cursor.execute(query)] return [get_song_from_response(json.loads(i[0])) for i in self.cursor.execute(query)]
def get_track_metadata(self, musicbrainz_releasetrackid: str): def get_track_metadata(self, musicbrainz_releasetrackid: str):
# this would be vulnerable if musicbrainz_releasetrackid would be user input # this would be vulnerable if musicbrainz_releasetrackid would be user input

View File

@ -5,109 +5,6 @@ from .metadata import Metadata
from .source import Source from .source import Source
from .target import Target from .target import Target
# I don't import cache from the db module because it would lead to circular imports
# from .temp_database import temp_database as cache
# from . import cache
class Song:
def __init__(
self,
json_response: dict,
) -> None:
"""
id: is not NECESARRILY the musicbrainz id, but is DISTINCT for every song
mb_id: is the musicbrainz_id
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
"""
# attributes
self.id: str | None = None
self.mb_id: str | None = None
self.title: str | None = None
self.isrc: str | None = None
self.length: int | None = None
self.metadata: Metadata = Metadata()
# joins
self.artists: List[Artist] = []
self.lyrics: LyricsContainer = LyricsContainer(parent=self)
self.sources: List[Source] = []
self.target: Target = Target()
self.json_data = json_response
# initialize the data
self.id = self.json_data['id']
self.title = self.json_data['title']
self.artists = []
for a in self.json_data['artists']:
new_artist = Artist(a)
exists = False
for existing_artist in self.artists:
if new_artist == existing_artist:
exists = True
break
if not exists:
self.artists.append(new_artist)
self.isrc = self.json_data['isrc']
# initialize the sources
self.sources: List[Source] = []
for src in self.json_data['source']:
if src['src'] is None:
continue
self.sources.append(Source(src))
# initialize the target
self.target = Target()
self.target.file = self.json_data['file']
self.target.path = self.json_data['path']
# initialize id3 metadata
self.metadata = Metadata()
for key, value in self.json_data.items():
self.metadata[key] = value
self.metadata['artist'] = self.get_artist_names()
self.length = self.json_data['length']
# EasyID3.valid_keys.keys()
# the lyrics are not in the metadata class because the field isn't supported
# by easyid3
self.lyrics: LyricsContainer = LyricsContainer(parent=self)
def __str__(self) -> str:
return f"\"{self.title}\" by {', '.join([str(a) for a in self.artists])}"
def __repr__(self) -> str:
return self.__str__()
def get_metadata(self):
return self.metadata.get_all_metadata()
def has_isrc(self) -> bool:
return self.isrc is not None
def get_artist_names(self) -> List[str]:
return [a.name for a in self.artists]
def __getitem__(self, item):
if item not in self.json_data:
return None
return self.json_data[item]
def __setitem__(self, item, value):
if item == "file":
self.target.file = value
return
if item == "path":
self.target.path = value
return
self.json_data[item] = value
class Lyrics: class Lyrics:
@ -117,11 +14,9 @@ class Lyrics:
class LyricsContainer: class LyricsContainer:
def __init__(self, parent: Song): def __init__(self):
self.lyrics_list: List[Lyrics] = [] self.lyrics_list: List[Lyrics] = []
self.parent = parent
def append(self, lyrics: Lyrics): def append(self, lyrics: Lyrics):
# due to my db not supporting multiple Lyrics yet, I just use for doing stuff with the lyrics # due to my db not supporting multiple Lyrics yet, I just use for doing stuff with the lyrics
# the first element. I know this implementation is junk, but take it or leave it, it is going # the first element. I know this implementation is junk, but take it or leave it, it is going
@ -141,3 +36,69 @@ class LyricsContainer:
is_empty = property(fget=lambda self: len(self.lyrics_list) <= 0) is_empty = property(fget=lambda self: len(self.lyrics_list) <= 0)
class Song:
def __init__(
self,
id_: str = None,
mb_id: str = None,
title: str = None,
release: str = None,
isrc: str = None,
length: int = None,
artists: List[Artist] = None,
metadata: Metadata = None,
sources: List[Source] = None,
target: Target = None,
lyrics: LyricsContainer = None
) -> None:
"""
id: is not NECESARRILY the musicbrainz id, but is DISTINCT for every song
mb_id: is the musicbrainz_id
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
"""
# attributes
self.id: str | None = id_
self.mb_id: str | None = mb_id
self.title: str | None = title
self.release: str | None = release
self.isrc: str | None = isrc
self.length: int | None = length
if metadata is None:
metadata = Metadata()
self.metadata: Metadata = metadata
# joins
if artists is None:
artists = []
self.artists: List[Artist] = artists
if sources is None:
sources = []
self.sources: List[Source] = sources
if target is None:
target = Target()
self.target: Target = target
if lyrics is None:
lyrics = LyricsContainer()
self.lyrics: LyricsContainer = lyrics
def __str__(self) -> str:
return f"\"{self.title}\" by {', '.join([str(a) for a in self.artists])}"
def __repr__(self) -> str:
return self.__str__()
def get_metadata(self):
return self.metadata.get_all_metadata()
def has_isrc(self) -> bool:
return self.isrc is not None
def get_artist_names(self) -> List[str]:
return [a.name for a in self.artists]

View File

@ -22,22 +22,22 @@ class UrlPath:
self.genre = genre self.genre = genre
for row in temp_database.get_tracks_without_filepath(): for song in temp_database.get_tracks_without_filepath():
# print(row) # print(song)
file, path = self.get_path_from_row(row) file, path = self.get_path_from_song(song)
logger.info(f"setting target to {file}") logger.info(f"setting target to {file}")
temp_database.set_filepath(row['id'], file, path, genre) temp_database.set_filepath(song.id, file, path, genre)
def get_path_from_row(self, row): def get_path_from_song(self, song):
""" """
genre/artist/song.mp3 genre/artist/song.mp3
:param row: :param song:
:return: path: :return: path:
""" """
return os.path.join(self.get_genre(), self.get_artist(row), self.get_album(row), return os.path.join(self.get_genre(), self.get_artist(song), self.get_album(song),
f"{self.get_song(row)}.mp3"), os.path.join(self.get_genre(), self.get_artist(row), f"{self.get_song(song)}.mp3"), os.path.join(self.get_genre(), self.get_artist(song),
self.get_album(row)) self.get_album(song))
@staticmethod @staticmethod
def escape_part(part: str): def escape_part(part: str):
@ -46,15 +46,15 @@ class UrlPath:
def get_genre(self): def get_genre(self):
return self.escape_part(self.genre) return self.escape_part(self.genre)
def get_album(self, row): def get_album(self, song):
return self.escape_part(row['album']) return self.escape_part(song.release)
def get_artist(self, row): def get_artist(self, song):
artists = [artist['name'] for artist in row['artists']] artists = song.get_artist_names()
return self.escape_part(artists[0]) return self.escape_part(artists[0])
def get_song(self, row): def get_song(self, song):
return self.escape_part(row['title']) return self.escape_part(song.title)
if __name__ == "__main__": if __name__ == "__main__":