Skip to content

Commit

Permalink
Opensubsonic tests for artist 'parsing' (#1859)
Browse files Browse the repository at this point in the history
* chore: add parsing test for opensubsonic artist

* chore: make sure test json is covered by pre-commit

* chore: tidy json
  • Loading branch information
Jc2k authored Jan 13, 2025
1 parent 3749351 commit 16afa3e
Show file tree
Hide file tree
Showing 10 changed files with 391 additions and 47 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ repos:
language: system
types: [json]
entry: scripts/run-in-env.sh check-json
files: ^(music_assistant/.+/manifest\.json)$
files: ^(music_assistant/.+/manifest\.json)|(tests/providers/.+/fixtures/.+\.json)$
- id: check-merge-conflict
name: 💥 Check for merge conflicts
language: system
Expand Down
58 changes: 58 additions & 0 deletions music_assistant/providers/opensubsonic/parsers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""Parse objects from py-opensonic into Music Assistant types."""

from __future__ import annotations

from typing import TYPE_CHECKING

from music_assistant_models.enums import ImageType
from music_assistant_models.media_items import Artist, MediaItemImage, ProviderMapping
from music_assistant_models.unique_list import UniqueList

if TYPE_CHECKING:
from libopensonic.media import Artist as SonicArtist
from libopensonic.media import ArtistInfo as SonicArtistInfo


def parse_artist(
instance_id: str, sonic_artist: SonicArtist, sonic_info: SonicArtistInfo = None
) -> Artist:
"""Parse artist and artistInfo into a Music Assistant Artist."""
artist = Artist(
item_id=sonic_artist.id,
name=sonic_artist.name,
provider="opensubsonic",
favorite=bool(sonic_artist.starred),
provider_mappings={
ProviderMapping(
item_id=sonic_artist.id,
provider_domain="opensubsonic",
provider_instance=instance_id,
)
},
)

artist.metadata.images = UniqueList()
if sonic_artist.cover_id:
artist.metadata.images.append(
MediaItemImage(
type=ImageType.THUMB,
path=sonic_artist.cover_id,
provider=instance_id,
remotely_accessible=False,
)
)

if sonic_info:
if sonic_info.biography:
artist.metadata.description = sonic_info.biography
if sonic_info.small_url:
artist.metadata.images.append(
MediaItemImage(
type=ImageType.THUMB,
path=sonic_info.small_url,
provider=instance_id,
remotely_accessible=True,
)
)

return artist
51 changes: 5 additions & 46 deletions music_assistant/providers/opensubsonic/sonic_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,14 @@
)
from music_assistant.models.music_provider import MusicProvider

from .parsers import parse_artist

if TYPE_CHECKING:
from collections.abc import AsyncGenerator, Callable

from libopensonic.media import Album as SonicAlbum
from libopensonic.media import AlbumInfo as SonicAlbumInfo
from libopensonic.media import Artist as SonicArtist
from libopensonic.media import ArtistInfo as SonicArtistInfo
from libopensonic.media import Playlist as SonicPlaylist
from libopensonic.media import PodcastChannel as SonicPodcast
from libopensonic.media import PodcastEpisode as SonicEpisode
Expand Down Expand Up @@ -178,48 +179,6 @@ def _get_item_mapping(self, media_type: MediaType, key: str, name: str) -> ItemM
name=name,
)

def _parse_artist(
self, sonic_artist: SonicArtist, sonic_info: SonicArtistInfo = None
) -> Artist:
artist = Artist(
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,
provider_domain=self.domain,
provider_instance=self.instance_id,
)
},
)

artist.metadata.images = UniqueList()
if sonic_artist.cover_id:
artist.metadata.images.append(
MediaItemImage(
type=ImageType.THUMB,
path=sonic_artist.cover_id,
provider=self.instance_id,
remotely_accessible=False,
)
)

if sonic_info:
if sonic_info.biography:
artist.metadata.description = sonic_info.biography
if sonic_info.small_url:
artist.metadata.images.append(
MediaItemImage(
type=ImageType.THUMB,
path=sonic_info.small_url,
provider=self.instance_id,
remotely_accessible=True,
)
)
return artist

def _parse_album(self, sonic_album: SonicAlbum, sonic_info: SonicAlbumInfo = None) -> Album:
album_id = sonic_album.id
album = Album(
Expand Down Expand Up @@ -525,7 +484,7 @@ async def search(
musicFolderId=None,
)
return SearchResults(
artists=[self._parse_artist(entry) for entry in answer["artists"]],
artists=[parse_artist(self.instance_id, entry) for entry in answer["artists"]],
albums=[self._parse_album(entry) for entry in answer["albums"]],
tracks=[self._parse_track(entry) for entry in answer["songs"]],
)
Expand All @@ -535,7 +494,7 @@ async def get_library_artists(self) -> AsyncGenerator[Artist, None]:
indices = await self._run_async(self._conn.getArtists)
for index in indices:
for artist in index.artists:
yield self._parse_artist(artist)
yield parse_artist(self.instance_id, artist)

async def get_library_albums(self) -> AsyncGenerator[Album, None]:
"""
Expand Down Expand Up @@ -675,7 +634,7 @@ async def get_artist(self, prov_artist_id: str) -> Artist:
except (ParameterError, DataNotFoundError) as e:
msg = f"Artist {prov_artist_id} not found"
raise MediaNotFoundError(msg) from e
return self._parse_artist(sonic_artist, sonic_info)
return parse_artist(self.instance_id, sonic_artist, sonic_info)

async def get_track(self, prov_track_id: str) -> Track:
"""Return the specified track."""
Expand Down
1 change: 1 addition & 0 deletions tests/providers/opensubsonic/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Tests for opensubsonic."""
Loading

0 comments on commit 16afa3e

Please sign in to comment.