From 9d9c7960c9bd493d59218c00991692235255269a Mon Sep 17 00:00:00 2001 From: Lars Noack Date: Fri, 14 Oct 2022 15:23:47 +0200 Subject: [PATCH] some progress with musicbrainz --- .idea/.gitignore | 8 + .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 4 + .idea/modules.xml | 8 + .idea/music-downloader.iml | 10 ++ .idea/vcs.xml | 6 + README.md | 4 + src/__pycache__/metadata.cpython-310.pyc | Bin 0 -> 1020 bytes src/metadata.py | 155 ++++++++++++++++++ src/test.py | 24 +++ 10 files changed, 225 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/music-downloader.iml create mode 100644 .idea/vcs.xml create mode 100644 src/__pycache__/metadata.cpython-310.pyc create mode 100644 src/metadata.py create mode 100644 src/test.py diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..6468d4f --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..14e8adf --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/music-downloader.iml b/.idea/music-downloader.iml new file mode 100644 index 0000000..f40abef --- /dev/null +++ b/.idea/music-downloader.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 17b05f5..deef63d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,6 @@ # music-downloader This programm will first get the metadata of various songs from metadata provider like musicbrainz, and then search for download links on pages like bandcamp. Then it will download the song and edit the metadata according. + +## Metadata +![Musicbrainz Data Scheme](https://wiki.musicbrainz.org/-/images/9/9e/pymb3-model-core.png) + diff --git a/src/__pycache__/metadata.cpython-310.pyc b/src/__pycache__/metadata.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..80e806b5f0e3913924b5eb517d1f77ed40ea9f7c GIT binary patch literal 1020 zcmZ8fTWb?R6rR~zw#jDGiWGgzn=I0-icca%P|+X+vCxNrEZd!Fvh7~dGqWuXDT3{5 z|ARjEFU_k@{)HmcGm}neTk(n^SkYZGz*^r(yQZBIK9etPU49Z_vaSbc`@s zkTK!p2W1wsne)@8t0fd zI6KCo-fzSuqxnY3Wy(^S_JLp@!8)S7Ef8@hqeexnM z8K2F!exa2HP<01tS@76_A^7u2<2mDZqcrTx5zyqG) z=Dr%SfD9imRUOPum7gSemCGb)A+Ye!ty7=+H}l@I?7`jrl{Fegu8yzLk|&93CrMee zrqJskNsgMdxV^E31kfF1*si!WeWrENd4#UWCy%H(QLPEDIHZLsG}A$MLzl13h`Wu8 z1xjedy%qURTuBcs-GP_%%tGOv$K)OP>YY((FHn3+jy8?-?g(@bsP;^pX4AS#8yQiP zcHUY3?N)&w966wAs?cb-2Wei-tBFvdF#V7$Lxpl@kXJIYVI89ljPihsrjYk4SKjhv zfN?@Qt#n`qR+~CEu&HyQx+UgGl6ml-T>mA~GvFPJi9C3qL%V{@q!B0?3MY+*(8CJ@ i1R8!Nz3v*&>MQ^C^3%2{?nH>rC!rPE4?VvVB9Fg`3Gw>? literal 0 HcmV?d00001 diff --git a/src/metadata.py b/src/metadata.py new file mode 100644 index 0000000..21acdba --- /dev/null +++ b/src/metadata.py @@ -0,0 +1,155 @@ +import musicbrainzngs + +musicbrainzngs.set_useragent("metadata receiver", "0.1", "https://github.com/HeIIow2/music-downloader") + +KNOWN_KIND_OF_OPTIONS = ["artist", "release", "track"] + +class Search: + def __init__(self, query: str = None, artist: str = None): + if query is None and artist is None: + raise ValueError("no query provided") + + self.options_history = [] + self.current_options = None + self.current_chosen_option = None + + # initial search + if query is not None: + self.set_options([musicbrainzngs.search_artists(query), musicbrainzngs.search_release_groups(query), musicbrainzngs.search_releases(query)]) + elif artist is not None: + self.set_options([musicbrainzngs.search_artists(artist=artist)]) + + def browse_artist(self, artist): + return + + def browse_option(self, option, index: int): + if not option.choose(index): + return False + + self.current_chosen_option = option.get_current_option() + option_kind = self.current_chosen_option['kind'] + if option_kind == "artist": + return self.browse_artist(self.current_chosen_option) + + def choose(self, index): + if not self.current_options.choose(index): + return self.current_options + + + def get_options(self): + return self.current_options + + def set_options(self, results): + option_instance = self.Options(results=results) + self.options_history.append(option_instance) + self.current_options = option_instance + + return option_instance + + options = property(fget=get_options) + + class Options: + def __init__(self, results: list): + self.results = results + + self.headers = { + "artist": "found {count} artists:\n" + } + + self.artist_count = 0 + self.release_count = 0 + self.track_count = 0 + self.result_list = [] + self.set_options_values() + + self.current_option_ind = None + + def get_current_option(self): + if self.current_option_ind is None: + raise Exception("It must first be chosen, which option to get, before getting it") + + return self.result_list[self.current_option_ind] + + def choose(self, index: int) -> bool: + if len(self.result_list) <= index -1: + return False + self.current_option_ind = index + return True + + def get_string_for_artist(self, artist: dict) -> str: + string = f"'{artist['name']}'" + if "country" in artist: + string += f" from {artist['country']}" + if 'disambiguation' in artist: + string += f", '{artist['disambiguation']}'" + return string + "\n" + + def get_string_for_release(self, release: dict) -> str: + string = "" + print(release) + if "type" in release: + string += f"the {release['type']} titled " + string += f"'{release['title']}'" + if "artist-credit-phrase" in release: + string += f" by: {release['artist-credit-phrase']}" + + return string + "\n" + + def get_string_for_tracks(self, tracks: dict) -> str: + # I know it's not the best practice but whatever + return self.get_string_for_release(tracks) + + def get_string_for_option(self, option: dict) -> str: + kind = option['kind'] + if kind == "artist": + return self.get_string_for_artist(option) + if kind == "release": + return self.get_string_for_release(option) + if kind == "track": + return self.get_string_for_tracks(option) + return "Error\n" + + def __str__(self) -> str: + string = f"artists: {self.artist_count}; releases {self.release_count}; tracks {self.track_count}\n" + for i, option in enumerate(self.result_list): + string += f"{i})\t{option['kind']}:\t" + self.get_string_for_option(option) + return string + + def set_options_values(self): + for option_set in self.results: + if "artist-list" in option_set: + self.set_artist_values(option_set) + continue + if "release-group-list" in option_set: + self.set_release_values(option_set) + continue + if "release-list" in option_set: + self.set_track_values(option_set) + continue + print(option_set) + + def set_artist_values(self, option_set: dict): + self.artist_count += option_set['artist-count'] + for artist in option_set['artist-list']: + artist['kind'] = "artist" + self.result_list.append(artist) + + def set_release_values(self, option_set: dict): + self.release_count += option_set['release-group-count'] + for release in option_set['release-group-list']: + release['kind'] = "release" + self.result_list.append(release) + + def set_track_values(self, option_set: dict): + self.artist_count += option_set['release-count'] + for track in option_set['release-list']: + track['kind'] = "track" + self.result_list.append(track) + + + + +if __name__ == "__main__": + search = Search(query="psychonaut 4") + print(search.options) + search.choose(0) diff --git a/src/test.py b/src/test.py new file mode 100644 index 0000000..65ee2f2 --- /dev/null +++ b/src/test.py @@ -0,0 +1,24 @@ +import metadata + + +def test(): + passed = 0 + failed = 0 + + # testing search + metadata.Search(artist="Psychonaut") + passed += 1 + metadata.Search(query="Psychonaut") + passed += 1 + try: + metadata.Search() + failed += 1 + except ValueError: + print("throwing error on not giving metadata search a query works") + passed += 1 + + return passed, failed + +if __name__ == "__main__": + p,f = test() + print(f"{p}-{f}")