From: Eric Munson Date: Sun, 9 Jun 2024 23:09:06 +0000 (-0400) Subject: Two updates to the Subsonic provider (#1335) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=8898ca520a333a4b9d32ef895920cf729d751608;p=music-assistant-server.git Two updates to the Subsonic provider (#1335) --- diff --git a/music_assistant/common/models/errors.py b/music_assistant/common/models/errors.py index 93cf584b..fb0fc9ae 100644 --- a/music_assistant/common/models/errors.py +++ b/music_assistant/common/models/errors.py @@ -121,3 +121,9 @@ class ResourceTemporarilyUnavailable(MusicAssistantError): self.backoff_time = backoff_time error_code = 17 + + +class ProviderPermissionDenied(MusicAssistantError): + """Error thrown when a provider action is denied because of permissions.""" + + error_code = 18 diff --git a/music_assistant/server/providers/opensubsonic/sonic_provider.py b/music_assistant/server/providers/opensubsonic/sonic_provider.py index a03a785d..d77394e0 100644 --- a/music_assistant/server/providers/opensubsonic/sonic_provider.py +++ b/music_assistant/server/providers/opensubsonic/sonic_provider.py @@ -22,7 +22,11 @@ from music_assistant.common.models.enums import ( ProviderFeature, StreamType, ) -from music_assistant.common.models.errors import LoginFailed, MediaNotFoundError +from music_assistant.common.models.errors import ( + LoginFailed, + MediaNotFoundError, + ProviderPermissionDenied, +) from music_assistant.common.models.media_items import ( Album, AlbumType, @@ -123,11 +127,14 @@ class OpenSonicProvider(MusicProvider): ProviderFeature.LIBRARY_ALBUMS, ProviderFeature.LIBRARY_TRACKS, ProviderFeature.LIBRARY_PLAYLISTS, + ProviderFeature.LIBRARY_PLAYLISTS_EDIT, ProviderFeature.BROWSE, ProviderFeature.SEARCH, ProviderFeature.ARTIST_ALBUMS, ProviderFeature.ARTIST_TOPTRACKS, ProviderFeature.SIMILAR_TRACKS, + ProviderFeature.PLAYLIST_TRACKS_EDIT, + ProviderFeature.PLAYLIST_CREATE, ) @property @@ -237,6 +244,7 @@ class OpenSonicProvider(MusicProvider): item_id=sonic_artist.id, name=sonic_artist.name, provider=self.domain, + favorite=bool(sonic_artist.starred), provider_mappings={ ProviderMapping( item_id=sonic_artist.id, @@ -278,6 +286,7 @@ class OpenSonicProvider(MusicProvider): item_id=album_id, provider=self.domain, name=sonic_album.name, + favorite=bool(sonic_album.starred), provider_mappings={ ProviderMapping( item_id=album_id, @@ -675,6 +684,38 @@ class OpenSonicProvider(MusicProvider): ) return [self._parse_track(entry) for entry in songs] + async def create_playlist(self, name: str) -> Playlist: + """Create a new empty playlist on the server.""" + playlist: SonicPlaylist = await self._run_async(self._conn.createPlaylist, name=name) + return self._parse_playlist(playlist) + + async def add_playlist_tracks(self, prov_playlist_id: str, prov_track_ids: list[str]) -> None: + """Append the listed tracks to the selected playlist. + + Note that the configured user must own the playlist to edit this way. + """ + try: + await self._run_async( + self._conn.updatePlaylist, lid=prov_playlist_id, songIdsToAdd=prov_track_ids + ) + except SonicError: + msg = f"Failed to add songs to {prov_playlist_id}, check your permissions." + raise ProviderPermissionDenied(msg) + + async def remove_playlist_tracks( + self, prov_playlist_id: str, positions_to_remove: tuple[int, ...] + ) -> None: + """Remove selected positions from the playlist.""" + try: + await self._run_async( + self._conn.updatePlaylist, + lid=prov_playlist_id, + songIndexesToRemove=list(positions_to_remove), + ) + except SonicError: + msg = f"Failed to remove songs from {prov_playlist_id}, check your permissions." + raise ProviderPermissionDenied(msg) + async def get_stream_details(self, item_id: str) -> StreamDetails: """Get the details needed to process a specified track.""" try: