diff --git a/src/metadata/database.py b/src/metadata/database.py new file mode 100644 index 0000000..4a323ca --- /dev/null +++ b/src/metadata/database.py @@ -0,0 +1,97 @@ +import sqlite3 +import os +import logging + +def get_temp_dir(): + import tempfile + + temp_folder = "music-downloader" + temp_dir = os.path.join(tempfile.gettempdir(), temp_folder) + if not os.path.exists(temp_dir): + os.mkdir(temp_dir) + return temp_dir + +DATABASE_STRUCTURE_FILE = "src/metadata/database_structure.sql" +TEMP_DIR = get_temp_dir() +DATABASE_FILE = "metadata.db" +db_path = os.path.join(TEMP_DIR, DATABASE_FILE) + +connection = sqlite3.connect(db_path) +cursor = connection.cursor() + +def init_db(cursor, connection, reset_anyways: bool = False): + # check if db exists + exists = True + try: + query = 'SELECT * FROM track;' + cursor.execute(query) + _ = cursor.fetchall() + except sqlite3.OperationalError: + exists = False + + if not exists: + logging.info("Database does not exist yet.") + + if reset_anyways or not exists: + # reset the database if reset_anyways is true or if an error has been thrown previously. + logging.info("Creating/Reseting Database.") + + # read the file + with open(DATABASE_STRUCTURE_FILE, "r") as database_structure_file: + query = database_structure_file.read() + cursor.executescript(query) + +init_db(cursor=cursor, connection=connection, reset_anyways=True) + +def add_artist( + musicbrainz_artistid: str, + artist: str = None +): + query = "INSERT INTO artist (id, name) VALUES (?, ?);" + values = musicbrainz_artistid, artist + + cursor.execute(query, values) + connection.commit() + +def add_release_group( + musicbrainz_releasegroupid: str, + artist_ids: list, + albumartist: str = None, + albumsort: int = None, + musicbrainz_albumtype: str = None, + compilation: str = None +): + # add adjacency + adjacency_list = [] + for artist_id in artist_ids: + adjacency_list.append((musicbrainz_releasegroupid, artist_id)) + adjacency_values = tuple(adjacency_list) + adjacency_query = "INSERT INTO artist_release_group (artist_id, release_group_id) VALUES (?, ?);" + cursor.executemany(adjacency_query, adjacency_values) + connection.commit() + + # add release group + query = "INSERT INTO release_group (id, albumartist, albumsort, musicbrainz_albumtype, compilation) VALUES (?, ?, ?, ?, ?);" + values = musicbrainz_releasegroupid, albumartist, albumsort, musicbrainz_albumtype, compilation + cursor.execute(query, values) + connection.commit() + +def add_release( + musicbrainz_albumid: str, + release_group_id: str, + title: str = None, + copyright_: str = None +): + query = "INSERT INTO release_ (id, release_group_id, title, copyright) VALUES (?, ?, ?, ?);" + values = musicbrainz_albumid, release_group_id, title, copyright_ + + cursor.execute(query, values) + connection.commit() + +def add_track( + +): + pass + +if __name__ == "__main__": + logging.basicConfig(level=logging.DEBUG) diff --git a/src/metadata/database_structure.sql b/src/metadata/database_structure.sql new file mode 100644 index 0000000..5d6542f --- /dev/null +++ b/src/metadata/database_structure.sql @@ -0,0 +1,42 @@ +DROP TABLE IF EXISTS artist; +CREATE TABLE artist ( + id TEXT PRIMARY KEY NOT NULL, + name TEXT +); + +DROP TABLE IF EXISTS artist_release_group; +CREATE TABLE artist_release_group ( + artist_id TEXT NOT NULL, + release_group_id TEXT NOT NULL +); + +DROP TABLE IF EXISTS artist_track; +CREATE TABLE artist_track ( + artist_id TEXT NOT NULL, + track_id TEXT NOT NULL +); + +DROP TABLE IF EXISTS release_group; +CREATE TABLE release_group ( + id TEXT PRIMARY KEY NOT NULL, + albumartist TEXT, + albumsort INT, + musicbrainz_albumtype TEXT, + compilation TEXT +); + +DROP TABLE IF EXISTS release_; +CREATE TABLE release_ ( + id TEXT PRIMARY KEY NOT NULL, + release_group_id TEXT NOT NULL, + title TEXT, + copyright TEXT +); + +DROP TABLE IF EXISTS track; +CREATE TABLE track ( + id TEXT PRIMARY KEY NOT NULL, + release_id TEXT NOT NULL, + name TEXT +); + diff --git a/src/metadata/download.py b/src/metadata/download.py index 08ed57d..7dabeb7 100644 --- a/src/metadata/download.py +++ b/src/metadata/download.py @@ -1,18 +1,21 @@ from typing import List - import musicbrainzngs import pandas as pd import logging from datetime import date from object_handeling import get_elem_from_obj, parse_music_brainz_date +import database + +# I don't know if it would be feesable to set up my own mb instance +# https://github.com/metabrainz/musicbrainz-docker mb_log = logging.getLogger("musicbrainzngs") mb_log.setLevel(logging.WARNING) musicbrainzngs.set_useragent("metadata receiver", "0.1", "https://github.com/HeIIow2/music-downloader") -# IMPORTANT +# IMPORTANT DOCUMENTATION WHICH CONTAINS FOR EXAMPLE THE INCLUDES # https://python-musicbrainzngs.readthedocs.io/en/v0.7.1/api/#getting-data class Artist: @@ -34,6 +37,9 @@ class Artist: self.artist = get_elem_from_obj(artist_data, ['name']) + self.save() + + # STARTING TO FETCH' RELEASE GROUPS. IMPORTANT: DON'T WRITE ANYTHING BESIDES THAT HERE if not new_release_groups: return # sort all release groups by date and add album sort to have them in chronological order. @@ -48,11 +54,18 @@ class Artist: artists=[self], albumsort=i + 1 )) - + def __str__(self): newline = "\n" return f"id: {self.musicbrainz_artistid}\nname: {self.artist}\n{newline.join([str(release_group) for release_group in self.release_groups])}" + def save(self): + logging.info(f"artist: {self}") + database.add_artist( + musicbrainz_artistid=self.musicbrainz_artistid, + artist=self.artist + ) + class ReleaseGroup: def __init__( @@ -88,6 +101,8 @@ class ReleaseGroup: self.musicbrainz_albumtype = get_elem_from_obj(release_group_data, ['primary-type']) self.compilation = "1" if self.musicbrainz_albumtype == "Compilation" else None + self.save() + if only_download_distinct_releases: self.append_distinct_releases(release_datas) else: @@ -97,6 +112,17 @@ class ReleaseGroup: newline = "\n" return f"{newline.join([str(release_group) for release_group in self.releases])}" + def save(self): + logging.info(f"caching release_group {self}") + database.add_release_group( + musicbrainz_releasegroupid=self.musicbrainz_releasegroupid, + artist_ids=[artist.musicbrainz_artistid for artist in self.artists], + albumartist = self.albumartist, + albumsort = self.albumsort, + musicbrainz_albumtype = self.musicbrainz_albumtype, + compilation=self.compilation + ) + def append_artist(self, artist_id: str) -> Artist: for existing_artist in self.artists: if artist_id == existing_artist.musicbrainz_artistid: @@ -150,8 +176,21 @@ class Release: self.title = get_elem_from_obj(release_data, ['title']) self.copyright = get_elem_from_obj(label_data, [0, 'label', 'name']) + self.save() self.append_recordings(recording_datas) + def __str__(self): + return f"{self.title} ©{self.copyright}" + + def save(self): + logging.info(f"caching release {self}") + database.add_release( + musicbrainz_albumid=self.musicbrainz_albumid, + release_group_id=self.release_group.musicbrainz_releasegroupid, + title=self.title, + copyright_=self.copyright + ) + def append_recordings(self, recording_datas: dict): for recording_data in recording_datas: musicbrainz_releasetrackid = get_elem_from_obj(recording_data, ['id']) @@ -160,8 +199,6 @@ class Release: self.tracklist.append(musicbrainz_releasetrackid) - def __str__(self): - return f"{self.title} ©{self.copyright}" class Track: @@ -178,6 +215,12 @@ class Track: self.musicbrainz_releasetrackid = musicbrainz_releasetrackid self.release = release + def __str__(self): + return "this is a track" + + def save(self): + logging.info("caching track {self}") + def download(option: dict): type_ = option['type'] @@ -417,6 +460,15 @@ def download_track(mb_id, is_various_artist: bool = None, track: int = None, tot if __name__ == "__main__": + """ + import tempfile + import os + + TEMP_FOLDER = "music-downloader" + TEMP_DIR = os.path.join(tempfile.gettempdir(), TEMP_FOLDER) + if not os.path.exists(TEMP_DIR): + os.mkdir(TEMP_DIR) + """ logging.basicConfig(level=logging.DEBUG) download({'id': '5cfecbe4-f600-45e5-9038-ce820eedf3d1', 'type': 'artist'})