From e9fff5d8d5ba620c8fcf313e520a60090483b736 Mon Sep 17 00:00:00 2001 From: Tom Darboux <12885430+tjiho@users.noreply.github.com> Date: Sun, 27 Oct 2024 00:24:15 +0200 Subject: [PATCH 1/7] add random albums vdir (#1) Co-authored-by: Andrew Winkelman --- mopidy_subidy/library.py | 8 +++++++- mopidy_subidy/subsonic_api.py | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/mopidy_subidy/library.py b/mopidy_subidy/library.py index bc5e7c2..c7a0dc7 100644 --- a/mopidy_subidy/library.py +++ b/mopidy_subidy/library.py @@ -15,6 +15,7 @@ class SubidyLibraryProvider(backend.LibraryProvider): dict(id="albums", name="Albums"), dict(id="rootdirs", name="Directories"), dict(id="random", name="Random"), + dict(id="randomalbum", name="Random Albums"), ] # Create a dict with the keys being the `id`s in `vdir_templates` # and the values being objects containing the vdir `id`, @@ -56,6 +57,9 @@ class SubidyLibraryProvider(backend.LibraryProvider): def browse_random_songs(self): return self.subsonic_api.get_random_songs_as_refs() + def browse_random_albums(self): + return self.subsonic_api.get_random_albums_as_refs() + def browse_diritems(self, directory_id): return self.subsonic_api.get_diritems_as_refs(directory_id) @@ -86,7 +90,7 @@ class SubidyLibraryProvider(backend.LibraryProvider): def browse(self, browse_uri): if browse_uri == uri.get_vdir_uri("root"): - root_vdir_names = ["rootdirs", "artists", "albums", "random"] + root_vdir_names = ["rootdirs", "artists", "albums", "random", "randomalbum"] root_vdirs = [ self._vdirs[vdir_name] for vdir_name in root_vdir_names ] @@ -102,6 +106,8 @@ class SubidyLibraryProvider(backend.LibraryProvider): return self.browse_albums() elif browse_uri == uri.get_vdir_uri("random"): return self.browse_random_songs() + elif browse_uri == uri.get_vdir_uri("randomalbum"): + return self.browse_random_albums() else: uri_type = uri.get_type(browse_uri) diff --git a/mopidy_subidy/subsonic_api.py b/mopidy_subidy/subsonic_api.py index 50aacf7..077f0e4 100644 --- a/mopidy_subidy/subsonic_api.py +++ b/mopidy_subidy/subsonic_api.py @@ -429,6 +429,27 @@ class SubsonicApi: return songs return [] + def get_raw_random_album(self, size=MAX_LIST_RESULTS): + try: + response = self.connection.getAlbumList2( + ltype='random', size=size, offset=0 + ) + except Exception: + logger.warning( + "Connecting to subsonic failed when loading random album list." + ) + return [] + if response.get("status") != RESPONSE_OK: + logger.warning( + "Got non-okay status code from subsonic: %s" + % response.get("status") + ) + return [] + albums = response.get("albumList2").get("album") + if albums is not None: + return albums + return [] + def get_more_albums(self, ltype, size=MAX_LIST_RESULTS, offset=0): try: response = self.connection.getAlbumList2( @@ -519,6 +540,11 @@ class SubsonicApi: self.raw_song_to_ref(song) for song in self.get_raw_random_song(75) ] + def get_random_albums_as_refs(self): + return [ + self.raw_album_to_ref_with_artist(album) for album in self.get_raw_random_album(20) + ] + def get_random_songs_as_tracks(self): return [ self.raw_song_to_track(song) for song in self.get_raw_random_song() @@ -615,6 +641,16 @@ class SubsonicApi: uri=uri.get_album_uri(album.get("id")), ) + def raw_album_to_ref_with_artist(self, album): + if album is None: + return None + return Ref.album( + name=album.get("artist") + " - " + album.get("title") + or album.get("artist") + " - " + album.get("name") + or UNKNOWN_ALBUM, + uri=uri.get_album_uri(album.get("id")), + ) + def raw_album_to_album(self, album): if album is None: return None From 4c7a5192cbcab42bd748eab9511e3d829947afc7 Mon Sep 17 00:00:00 2001 From: tjiho Date: Sun, 27 Oct 2024 02:46:13 +0100 Subject: [PATCH 2/7] Listing genres --- mopidy_subidy/library.py | 14 ++++++++++++- mopidy_subidy/subsonic_api.py | 37 +++++++++++++++++++++++++++++++++-- mopidy_subidy/uri.py | 8 ++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/mopidy_subidy/library.py b/mopidy_subidy/library.py index c7a0dc7..b1c5520 100644 --- a/mopidy_subidy/library.py +++ b/mopidy_subidy/library.py @@ -16,6 +16,7 @@ class SubidyLibraryProvider(backend.LibraryProvider): dict(id="rootdirs", name="Directories"), dict(id="random", name="Random"), dict(id="randomalbum", name="Random Albums"), + dict(id="genre", name="Genre"), ] # Create a dict with the keys being the `id`s in `vdir_templates` # and the values being objects containing the vdir `id`, @@ -60,6 +61,12 @@ class SubidyLibraryProvider(backend.LibraryProvider): def browse_random_albums(self): return self.subsonic_api.get_random_albums_as_refs() + def browse_albums_by_genre(self, genre): + return self.subsonic_api.get_albums_by_genre_as_refs(genre) + + def browse_genre(self): + return self.subsonic_api.get_genres_as_refs(genre) + def browse_diritems(self, directory_id): return self.subsonic_api.get_diritems_as_refs(directory_id) @@ -90,7 +97,8 @@ class SubidyLibraryProvider(backend.LibraryProvider): def browse(self, browse_uri): if browse_uri == uri.get_vdir_uri("root"): - root_vdir_names = ["rootdirs", "artists", "albums", "random", "randomalbum"] + root_vdir_names = ["rootdirs", "artists", + "albums", "random", "randomalbum", "genre"] root_vdirs = [ self._vdirs[vdir_name] for vdir_name in root_vdir_names ] @@ -108,11 +116,15 @@ class SubidyLibraryProvider(backend.LibraryProvider): return self.browse_random_songs() elif browse_uri == uri.get_vdir_uri("randomalbum"): return self.browse_random_albums() + elif browse_uri == uri.get_vdir_uri("genre"): + return self.browse_genre() else: uri_type = uri.get_type(browse_uri) if uri_type == uri.DIRECTORY: return self.browse_diritems(uri.get_directory_id(browse_uri)) + elif uri_type == uri.GENRE: + return self.browse_albums_by_genre(uri.get_genre_id(browse_uri)) elif uri_type == uri.ARTIST: return self.browse_albums(uri.get_artist_id(browse_uri)) elif uri_type == uri.ALBUM: diff --git a/mopidy_subidy/subsonic_api.py b/mopidy_subidy/subsonic_api.py index 077f0e4..07d3f9a 100644 --- a/mopidy_subidy/subsonic_api.py +++ b/mopidy_subidy/subsonic_api.py @@ -450,6 +450,28 @@ class SubsonicApi: return albums return [] + def get_raw_genres(self): + try: + response = self.connection.getGenres() + except Exception: + logger.warning( + "Connecting to subsonic failed when loading genres." + ) + return [] + + if response.get("status") != RESPONSE_OK: + logger.warning( + "Got non-okay status code from subsonic: %s" + % response.get("status") + ) + return [] + + genres = response.get("genres").get("genre") + + if genres is not None: + return genres + return [] + def get_more_albums(self, ltype, size=MAX_LIST_RESULTS, offset=0): try: response = self.connection.getAlbumList2( @@ -597,6 +619,16 @@ class SubsonicApi: else: yield self.raw_song_to_track(item) + def get_albums_by_genre_as_refs(self, genre): + return [] + + def get_genres_as_refs(self): + genres = self.get_raw_genres() + return [Ref.directory( + name=genre.value, + uri=uri.get_genre_uri(genre.value) + ) for genre in genres] + def raw_song_to_ref(self, song): if song is None: return None @@ -646,8 +678,8 @@ class SubsonicApi: return None return Ref.album( name=album.get("artist") + " - " + album.get("title") - or album.get("artist") + " - " + album.get("name") - or UNKNOWN_ALBUM, + or album.get("artist") + " - " + album.get("name") + or UNKNOWN_ALBUM, uri=uri.get_album_uri(album.get("id")), ) @@ -712,3 +744,4 @@ class SubsonicApi: uri=uri.get_playlist_uri(playlist.get("id")), name=playlist.get("name"), ) + diff --git a/mopidy_subidy/uri.py b/mopidy_subidy/uri.py index a4d8464..3b64170 100644 --- a/mopidy_subidy/uri.py +++ b/mopidy_subidy/uri.py @@ -6,6 +6,7 @@ PLAYLIST = "playlist" ALBUM = "album" DIRECTORY = "directory" VDIR = "vdir" +GENRE = "genre" PREFIX = "subidy" SEARCH = "search" RANDOM = "random" @@ -70,6 +71,11 @@ def get_vdir_id(uri): return None return result.group(3) +def get_genre_id(uri): + result = regex.match(uri) + if not is_id_result_valid(result, GENRE): + return None + return result.group(3) def get_type(uri): result = regex.match(uri) @@ -97,6 +103,8 @@ def get_song_uri(id): def get_directory_uri(id): return get_type_uri(DIRECTORY, id) +def get_genre_uri(id): + return get_type_uri(GENRE, id) def get_vdir_uri(id): return get_type_uri(VDIR, id) From 62f1fc806240cf75b74c872fe27c2689bc8bee16 Mon Sep 17 00:00:00 2001 From: tjiho Date: Sun, 27 Oct 2024 02:56:10 +0100 Subject: [PATCH 3/7] Fix browsing genre --- mopidy_subidy/library.py | 2 +- mopidy_subidy/subsonic_api.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mopidy_subidy/library.py b/mopidy_subidy/library.py index b1c5520..26868c0 100644 --- a/mopidy_subidy/library.py +++ b/mopidy_subidy/library.py @@ -65,7 +65,7 @@ class SubidyLibraryProvider(backend.LibraryProvider): return self.subsonic_api.get_albums_by_genre_as_refs(genre) def browse_genre(self): - return self.subsonic_api.get_genres_as_refs(genre) + return self.subsonic_api.get_genres_as_refs() def browse_diritems(self, directory_id): return self.subsonic_api.get_diritems_as_refs(directory_id) diff --git a/mopidy_subidy/subsonic_api.py b/mopidy_subidy/subsonic_api.py index 07d3f9a..758cdb3 100644 --- a/mopidy_subidy/subsonic_api.py +++ b/mopidy_subidy/subsonic_api.py @@ -625,8 +625,8 @@ class SubsonicApi: def get_genres_as_refs(self): genres = self.get_raw_genres() return [Ref.directory( - name=genre.value, - uri=uri.get_genre_uri(genre.value) + name=genre['value'], + uri=uri.get_genre_uri(genre['value']) ) for genre in genres] def raw_song_to_ref(self, song): From 29d77244fcbd470e17692aacd2aa3e4bfcc7b020 Mon Sep 17 00:00:00 2001 From: tjiho Date: Sun, 27 Oct 2024 03:03:31 +0100 Subject: [PATCH 4/7] Add listing album inside genre dir --- mopidy_subidy/subsonic_api.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/mopidy_subidy/subsonic_api.py b/mopidy_subidy/subsonic_api.py index 758cdb3..1c2d870 100644 --- a/mopidy_subidy/subsonic_api.py +++ b/mopidy_subidy/subsonic_api.py @@ -450,6 +450,27 @@ class SubsonicApi: return albums return [] + def get_raw_albums_by_genre(self, genre): + try: + response = self.connection.getAlbumList2( + ltype='genre', size=size, offset=0, genre=genre + ) + except Exception: + logger.warning( + "Connecting to subsonic failed when loading genre album list." + ) + return [] + if response.get("status") != RESPONSE_OK: + logger.warning( + "Got non-okay status code from subsonic: %s" + % response.get("status") + ) + return [] + albums = response.get("albumList2").get("album") + if albums is not None: + return albums + return [] + def get_raw_genres(self): try: response = self.connection.getGenres() @@ -620,7 +641,9 @@ class SubsonicApi: yield self.raw_song_to_track(item) def get_albums_by_genre_as_refs(self, genre): - return [] + return [ + self.raw_album_to_ref_with_artist(album) for album in self.get_raw_albums_by_genre(genre) + ] def get_genres_as_refs(self): genres = self.get_raw_genres() From 022d7e8f0641e42b5a4212b94e6756ea4890b1e3 Mon Sep 17 00:00:00 2001 From: tjiho Date: Sun, 27 Oct 2024 03:24:23 +0100 Subject: [PATCH 5/7] Fix listing albums by genre --- mopidy_subidy/subsonic_api.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mopidy_subidy/subsonic_api.py b/mopidy_subidy/subsonic_api.py index 1c2d870..1b45478 100644 --- a/mopidy_subidy/subsonic_api.py +++ b/mopidy_subidy/subsonic_api.py @@ -453,12 +453,13 @@ class SubsonicApi: def get_raw_albums_by_genre(self, genre): try: response = self.connection.getAlbumList2( - ltype='genre', size=size, offset=0, genre=genre + ltype='byGenre', genre=genre ) except Exception: logger.warning( "Connecting to subsonic failed when loading genre album list." ) + logging.exception('') return [] if response.get("status") != RESPONSE_OK: logger.warning( From 3c38ed32f411896cc5b47195a6a3b4af43a11868 Mon Sep 17 00:00:00 2001 From: tjiho Date: Sun, 27 Oct 2024 03:35:56 +0100 Subject: [PATCH 6/7] Fix raw_album_to_ref_with_artist --- mopidy_subidy/subsonic_api.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mopidy_subidy/subsonic_api.py b/mopidy_subidy/subsonic_api.py index 1b45478..fea7206 100644 --- a/mopidy_subidy/subsonic_api.py +++ b/mopidy_subidy/subsonic_api.py @@ -700,10 +700,12 @@ class SubsonicApi: def raw_album_to_ref_with_artist(self, album): if album is None: return None + + album_name = album.get("title") or album.get("name") or UNKNOWN_ALBUM + artist = album.get("artist") or UNKNOWN_ARTIST + return Ref.album( - name=album.get("artist") + " - " + album.get("title") - or album.get("artist") + " - " + album.get("name") - or UNKNOWN_ALBUM, + name=artist + " ยท " + album_name, uri=uri.get_album_uri(album.get("id")), ) From 388551bd9b2e02e54983a438891707719263821b Mon Sep 17 00:00:00 2001 From: tjiho Date: Sun, 27 Oct 2024 14:47:19 +0100 Subject: [PATCH 7/7] Increase size when listing albums by genre --- mopidy_subidy/subsonic_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mopidy_subidy/subsonic_api.py b/mopidy_subidy/subsonic_api.py index fea7206..e93498b 100644 --- a/mopidy_subidy/subsonic_api.py +++ b/mopidy_subidy/subsonic_api.py @@ -453,7 +453,7 @@ class SubsonicApi: def get_raw_albums_by_genre(self, genre): try: response = self.connection.getAlbumList2( - ltype='byGenre', genre=genre + ltype='byGenre', size=MAX_LIST_RESULTS, genre=genre, ) except Exception: logger.warning(