From: Eric Munson Date: Tue, 10 Jun 2025 21:16:03 +0000 (-0400) Subject: Chore: Subsonic: Clean up last of the typing errors and add tests (#2225) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=9290abb0bea6077610d4e81ca85893de78352219;p=music-assistant-server.git Chore: Subsonic: Clean up last of the typing errors and add tests (#2225) Take the time to clean up the last of the strict type checker errors. While in here, lets add test cases that excercise some of the work aroudns we have for various subsonic servers. Signed-off-by: Eric B Munson --- diff --git a/music_assistant/providers/opensubsonic/parsers.py b/music_assistant/providers/opensubsonic/parsers.py index 1f7d2609..95a1f8b0 100644 --- a/music_assistant/providers/opensubsonic/parsers.py +++ b/music_assistant/providers/opensubsonic/parsers.py @@ -7,7 +7,7 @@ from datetime import datetime from typing import TYPE_CHECKING from music_assistant_models.enums import ContentType, ImageType, MediaType -from music_assistant_models.errors import MediaNotFoundError +from music_assistant_models.errors import InvalidDataError, MediaNotFoundError from music_assistant_models.media_items import ( Album, Artist, @@ -125,14 +125,14 @@ def parse_track( available=True, audio_format=AudioFormat( content_type=ContentType.try_parse(sonic_song.content_type or "?"), - sample_rate=sonic_song.sampling_rate if sonic_song.sampling_rate else 44100, - bit_depth=sonic_song.bit_depth if sonic_song.bit_depth else 16, - channels=sonic_song.channel_count if sonic_song.channel_count else 2, - bit_rate=sonic_song.bit_rate if sonic_song.bit_rate else None, + sample_rate=sonic_song.sampling_rate or 44100, + bit_depth=sonic_song.bit_depth or 16, + channels=sonic_song.channel_count or 2, + bit_rate=sonic_song.bit_rate, ), ) }, - track_number=sonic_song.track if sonic_song.track else 0, + track_number=sonic_song.track or 0, ) if sonic_song.music_brainz_id: @@ -151,17 +151,18 @@ def parse_track( instance_id, MediaType.ARTIST, sonic_song.artist_id, - sonic_song.artist if sonic_song.artist else UNKNOWN_ARTIST, + sonic_song.artist or UNKNOWN_ARTIST, ) ) - for entry in sonic_song.artists: - if entry.id == sonic_song.artist_id: - continue - if entry.id is not None and entry.name is not None: - track.artists.append( - get_item_mapping(instance_id, MediaType.ARTIST, entry.id, entry.name) - ) + if sonic_song.artists: + for entry in sonic_song.artists: + if entry.id == sonic_song.artist_id: + continue + if entry.id is not None and entry.name is not None: + track.artists.append( + get_item_mapping(instance_id, MediaType.ARTIST, entry.id, entry.name) + ) if not track.artists: if sonic_song.artist and not sonic_song.artist_id: @@ -257,7 +258,7 @@ def parse_artist( provider_instance=instance_id, ) }, - sort_name=sonic_artist.sort_name if sonic_artist.sort_name else None, + sort_name=sonic_artist.sort_name, ) if sonic_artist.music_brainz_id: @@ -340,7 +341,7 @@ def parse_album( media_type=MediaType.ARTIST, item_id=sonic_album.artist_id, provider=instance_id, - name=sonic_album.artist if sonic_album.artist else UNKNOWN_ARTIST, + name=sonic_album.artist or UNKNOWN_ARTIST, ) ) elif not sonic_album.artists: @@ -408,12 +409,16 @@ def parse_playlist(instance_id: str, sonic_playlist: SonicPlaylist) -> Playlist: def parse_podcast(instance_id: str, sonic_podcast: SonicPodcast) -> Podcast: """Parse Subsonic PodcastChannel into MA Podcast.""" + if not sonic_podcast.title: + raise InvalidDataError( + f"Subsonic Podcast ({sonic_podcast.id})is missing required name field." + ) podcast = Podcast( item_id=sonic_podcast.id, provider=SUBSONIC_DOMAIN, name=sonic_podcast.title, uri=sonic_podcast.url, - total_episodes=len(sonic_podcast.episode), + total_episodes=len(sonic_podcast.episode) if sonic_podcast.episode else 0, provider_mappings={ ProviderMapping( item_id=sonic_podcast.id, @@ -465,7 +470,7 @@ def parse_epsiode( provider_instance=instance_id, ) }, - duration=sonic_episode.duration, + duration=sonic_episode.duration or 0, ) if sonic_episode.publish_date: diff --git a/music_assistant/providers/opensubsonic/sonic_provider.py b/music_assistant/providers/opensubsonic/sonic_provider.py index 54de11b6..bdff0adb 100644 --- a/music_assistant/providers/opensubsonic/sonic_provider.py +++ b/music_assistant/providers/opensubsonic/sonic_provider.py @@ -89,18 +89,17 @@ class OpenSonicProvider(MusicProvider): async def handle_async_init(self) -> None: """Set up the music provider and test the connection.""" port = self.config.get_value(CONF_PORT) - if port is None: - port = 443 + port = int(str(port)) or 443 path = self.config.get_value(CONF_PATH) if path is None: path = "" self.conn = SonicConnection( - self.config.get_value(CONF_BASE_URL), - username=self.config.get_value(CONF_USERNAME), - password=self.config.get_value(CONF_PASSWORD), - legacy_auth=self.config.get_value(CONF_ENABLE_LEGACY_AUTH), + str(self.config.get_value(CONF_BASE_URL)), + username=str(self.config.get_value(CONF_USERNAME)), + password=str(self.config.get_value(CONF_PASSWORD)), + legacy_auth=bool(self.config.get_value(CONF_ENABLE_LEGACY_AUTH)), port=port, - server_path=path, + server_path=str(path), app_name="Music Assistant", ) try: @@ -308,7 +307,7 @@ class OpenSonicProvider(MusicProvider): album: Album | None = None for entry in results.song: aid = entry.album_id if entry.album_id else entry.parent - if album is None or album.item_id != aid: + if aid is not None and (album is None or album.item_id != aid): album = await self.get_album(prov_album_id=aid) yield parse_track(self.logger, self.instance_id, entry, album=album) offset += count @@ -447,6 +446,9 @@ class OpenSonicProvider(MusicProvider): self.conn.get_podcasts, inc_episodes=True, pid=prov_podcast_id ) channel = channels[0] + if not channel.episode: + return + for episode in channel.episode: yield parse_epsiode(self.instance_id, episode, channel) @@ -492,7 +494,7 @@ class OpenSonicProvider(MusicProvider): aid = sonic_song.album_id if sonic_song.album_id else sonic_song.parent if not aid: self.logger.warning("Unable to find album for track %s", sonic_song.id) - if not album or album.item_id != aid: + if aid is not None and (not album or album.item_id != aid): album = await self.get_album(prov_album_id=aid) track = parse_track(self.logger, self.instance_id, sonic_song, album=album) track.position = index diff --git a/tests/providers/opensubsonic/__snapshots__/test_parsers.ambr b/tests/providers/opensubsonic/__snapshots__/test_parsers.ambr index 30ba1af1..4bb485d0 100644 --- a/tests/providers/opensubsonic/__snapshots__/test_parsers.ambr +++ b/tests/providers/opensubsonic/__snapshots__/test_parsers.ambr @@ -1,4 +1,270 @@ # serializer version: 1 +# name: test_parse_albums[no-artist.album] + dict({ + 'album_type': 'unknown', + 'artists': list([ + dict({ + 'external_ids': list([ + ]), + 'favorite': False, + 'is_playable': True, + 'item_id': 'fake_artist_unknown', + 'media_type': 'artist', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': None, + 'explicit': None, + 'genres': None, + 'images': None, + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': None, + 'performers': None, + 'popularity': None, + 'preview': None, + 'release_date': None, + 'review': None, + 'style': None, + }), + 'name': '[unknown]', + 'position': None, + 'provider': 'xx-instance-id-xx', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': 'fake_artist_unknown', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'sort_name': 'unknown]', + 'translation_key': None, + 'uri': 'xx-instance-id-xx://artist/fake_artist_unknown', + 'version': '', + }), + ]), + 'external_ids': list([ + list([ + 'musicbrainz_albumid', + '189002e7-3285-4e2e-92a3-7f6c30d407a2', + ]), + ]), + 'favorite': True, + 'is_playable': True, + 'item_id': 'ad0f112b6dcf83de5e9cae85d07f0d35', + 'media_type': 'album', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': None, + 'explicit': None, + 'genres': list([ + 'East coast', + 'Hip-Hop', + ]), + 'images': list([ + dict({ + 'path': 'al-ad0f112b6dcf83de5e9cae85d07f0d35_640a93a8', + 'provider': 'xx-instance-id-xx', + 'remotely_accessible': False, + 'type': 'thumb', + }), + ]), + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': 'slow', + 'performers': None, + 'popularity': None, + 'preview': None, + 'release_date': None, + 'review': None, + 'style': None, + }), + 'name': '8-bit lagerfeuer', + 'position': None, + 'provider': 'opensubsonic', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': 'ad0f112b6dcf83de5e9cae85d07f0d35', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'sort_name': 'lagerfeuer (8-bit)', + 'translation_key': None, + 'uri': 'opensubsonic://album/ad0f112b6dcf83de5e9cae85d07f0d35', + 'version': '', + 'year': 2007, + }) +# --- +# name: test_parse_albums[no-artist.album].1 + dict({ + 'album_type': 'unknown', + 'artists': list([ + dict({ + 'external_ids': list([ + ]), + 'favorite': False, + 'is_playable': True, + 'item_id': 'fake_artist_unknown', + 'media_type': 'artist', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': None, + 'explicit': None, + 'genres': None, + 'images': None, + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': None, + 'performers': None, + 'popularity': None, + 'preview': None, + 'release_date': None, + 'review': None, + 'style': None, + }), + 'name': '[unknown]', + 'position': None, + 'provider': 'xx-instance-id-xx', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': 'fake_artist_unknown', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'sort_name': 'unknown]', + 'translation_key': None, + 'uri': 'xx-instance-id-xx://artist/fake_artist_unknown', + 'version': '', + }), + ]), + 'external_ids': list([ + list([ + 'musicbrainz_albumid', + '189002e7-3285-4e2e-92a3-7f6c30d407a2', + ]), + ]), + 'favorite': True, + 'is_playable': True, + 'item_id': 'ad0f112b6dcf83de5e9cae85d07f0d35', + 'media_type': 'album', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': 'Download the full release here (creative commons). These cripsy beats are ripe with thumping funk and techno influences, sample wizardry and daring shuffles. Composed with the help of unique sound plugins which were especially programmed to measure Comfort Fit’s needs and wishes, we think the chances aren’t bad that you’ll fall for the unique sound signature, bounce and elegance of this unusual Hip Hop production. Ltj bukem / Good looking Rec., UK: "Really love this music." Velanche / XLR8R, UK: "Awesome job he\'s done... overall production is dope." Kwesi / BBE Music, UK: "Wooooooowwwww... WHAT THE FUCK! THIS IS WHAT', + 'explicit': None, + 'genres': list([ + 'East coast', + 'Hip-Hop', + ]), + 'images': list([ + dict({ + 'path': 'al-ad0f112b6dcf83de5e9cae85d07f0d35_640a93a8', + 'provider': 'xx-instance-id-xx', + 'remotely_accessible': False, + 'type': 'thumb', + }), + dict({ + 'path': 'http://localhost:8989/play/art/0f8c3cbd6b0b22c3b5402141351ac812/album/21/thumb34.jpg', + 'provider': 'xx-instance-id-xx', + 'remotely_accessible': True, + 'type': 'thumb', + }), + ]), + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': 'slow', + 'performers': None, + 'popularity': None, + 'preview': None, + 'release_date': None, + 'review': None, + 'style': None, + }), + 'name': '8-bit lagerfeuer', + 'position': None, + 'provider': 'opensubsonic', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': 'ad0f112b6dcf83de5e9cae85d07f0d35', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'sort_name': 'lagerfeuer (8-bit)', + 'translation_key': None, + 'uri': 'opensubsonic://album/ad0f112b6dcf83de5e9cae85d07f0d35', + 'version': '', + 'year': 2007, + }) +# --- # name: test_parse_albums[spec.album] dict({ 'album_type': 'unknown', @@ -245,7 +511,7 @@ 'year': 2007, }) # --- -# name: test_parse_artists[spec-artistid3.artist] +# name: test_parse_artists[no-sort-name.artist] dict({ 'external_ids': list([ list([ @@ -313,13 +579,13 @@ 'url': None, }), ]), - 'sort_name': 'Mello (2)', + 'sort_name': '2 mello', 'translation_key': None, 'uri': 'opensubsonic://artist/37ec820ca7193e17040c98f7da7c4b51', 'version': '', }) # --- -# name: test_parse_artists[spec-artistid3.artist].1 +# name: test_parse_artists[no-sort-name.artist].1 dict({ 'external_ids': list([ list([ @@ -393,19 +659,23 @@ 'url': None, }), ]), - 'sort_name': 'Mello (2)', + 'sort_name': '2 mello', 'translation_key': None, 'uri': 'opensubsonic://artist/37ec820ca7193e17040c98f7da7c4b51', 'version': '', }) # --- -# name: test_parse_artists[spec-sample.artist] +# name: test_parse_artists[spec-artistid3.artist] dict({ 'external_ids': list([ + list([ + 'musicbrainz_artistid', + '189002e7-3285-4e2e-92a3-7f6c30d407a2', + ]), ]), 'favorite': True, 'is_playable': True, - 'item_id': '100000002', + 'item_id': '37ec820ca7193e17040c98f7da7c4b51', 'media_type': 'artist', 'metadata': dict({ 'chapters': None, @@ -415,7 +685,13 @@ 'genres': None, 'images': list([ dict({ - 'path': 'ar-100000002', + 'path': 'https://demo.org/image.jpg', + 'provider': 'xx-instance-id-xx', + 'remotely_accessible': True, + 'type': 'thumb', + }), + dict({ + 'path': 'ar-37ec820ca7193e17040c98f7da7c4b51_0', 'provider': 'xx-instance-id-xx', 'remotely_accessible': False, 'type': 'thumb', @@ -435,7 +711,7 @@ 'review': None, 'style': None, }), - 'name': 'Synthetic', + 'name': '2 Mello', 'position': None, 'provider': 'opensubsonic', 'provider_mappings': list([ @@ -451,25 +727,29 @@ }), 'available': True, 'details': None, - 'item_id': '100000002', + 'item_id': '37ec820ca7193e17040c98f7da7c4b51', 'provider_domain': 'opensubsonic', 'provider_instance': 'xx-instance-id-xx', 'url': None, }), ]), - 'sort_name': 'synthetic', + 'sort_name': 'Mello (2)', 'translation_key': None, - 'uri': 'opensubsonic://artist/100000002', + 'uri': 'opensubsonic://artist/37ec820ca7193e17040c98f7da7c4b51', 'version': '', }) # --- -# name: test_parse_artists[spec-sample.artist].1 +# name: test_parse_artists[spec-artistid3.artist].1 dict({ 'external_ids': list([ + list([ + 'musicbrainz_artistid', + '189002e7-3285-4e2e-92a3-7f6c30d407a2', + ]), ]), 'favorite': True, 'is_playable': True, - 'item_id': '100000002', + 'item_id': '37ec820ca7193e17040c98f7da7c4b51', 'media_type': 'artist', 'metadata': dict({ 'chapters': None, @@ -479,7 +759,13 @@ 'genres': None, 'images': list([ dict({ - 'path': 'ar-100000002', + 'path': 'https://demo.org/image.jpg', + 'provider': 'xx-instance-id-xx', + 'remotely_accessible': True, + 'type': 'thumb', + }), + dict({ + 'path': 'ar-37ec820ca7193e17040c98f7da7c4b51_0', 'provider': 'xx-instance-id-xx', 'remotely_accessible': False, 'type': 'thumb', @@ -505,7 +791,7 @@ 'review': None, 'style': None, }), - 'name': 'Synthetic', + 'name': '2 Mello', 'position': None, 'provider': 'opensubsonic', 'provider_mappings': list([ @@ -521,35 +807,40 @@ }), 'available': True, 'details': None, - 'item_id': '100000002', + 'item_id': '37ec820ca7193e17040c98f7da7c4b51', 'provider_domain': 'opensubsonic', 'provider_instance': 'xx-instance-id-xx', 'url': None, }), ]), - 'sort_name': 'synthetic', + 'sort_name': 'Mello (2)', 'translation_key': None, - 'uri': 'opensubsonic://artist/100000002', + 'uri': 'opensubsonic://artist/37ec820ca7193e17040c98f7da7c4b51', 'version': '', }) # --- -# name: test_parse_episode[gonic-sample.episode] +# name: test_parse_artists[spec-sample.artist] dict({ - 'duration': 1878, 'external_ids': list([ ]), - 'favorite': False, - 'fully_played': None, + 'favorite': True, 'is_playable': True, - 'item_id': 'pd-5$!$pe-1860', - 'media_type': 'podcast_episode', + 'item_id': '100000002', + 'media_type': 'artist', 'metadata': dict({ 'chapters': None, 'copyright': None, - 'description': 'The history of The History of Rome...Why the Western Empire Fell when it did...Some thoughts on the future...Thank you, goodnight.', + 'description': None, 'explicit': None, 'genres': None, - 'images': None, + 'images': list([ + dict({ + 'path': 'ar-100000002', + 'provider': 'xx-instance-id-xx', + 'remotely_accessible': False, + 'type': 'thumb', + }), + ]), 'label': None, 'languages': None, 'last_refresh': None, @@ -560,11 +851,264 @@ 'performers': None, 'popularity': None, 'preview': None, - 'release_date': '2012-05-06T18:18:38+00:00', + 'release_date': None, 'review': None, 'style': None, }), - 'name': '179- The End', + 'name': 'Synthetic', + 'position': None, + 'provider': 'opensubsonic', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': '100000002', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'sort_name': 'synthetic', + 'translation_key': None, + 'uri': 'opensubsonic://artist/100000002', + 'version': '', + }) +# --- +# name: test_parse_artists[spec-sample.artist].1 + dict({ + 'external_ids': list([ + ]), + 'favorite': True, + 'is_playable': True, + 'item_id': '100000002', + 'media_type': 'artist', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': 'Empty biography', + 'explicit': None, + 'genres': None, + 'images': list([ + dict({ + 'path': 'ar-100000002', + 'provider': 'xx-instance-id-xx', + 'remotely_accessible': False, + 'type': 'thumb', + }), + dict({ + 'path': 'http://localhost:8989/play/art/f20070e8e11611cc53542a38801d60fa/artist/2/thumb34.jpg', + 'provider': 'xx-instance-id-xx', + 'remotely_accessible': True, + 'type': 'thumb', + }), + ]), + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': None, + 'performers': None, + 'popularity': None, + 'preview': None, + 'release_date': None, + 'review': None, + 'style': None, + }), + 'name': 'Synthetic', + 'position': None, + 'provider': 'opensubsonic', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': '100000002', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'sort_name': 'synthetic', + 'translation_key': None, + 'uri': 'opensubsonic://artist/100000002', + 'version': '', + }) +# --- +# name: test_parse_episode[gonic-sample.episode] + dict({ + 'duration': 1878, + 'external_ids': list([ + ]), + 'favorite': False, + 'fully_played': None, + 'is_playable': True, + 'item_id': 'pd-5$!$pe-1860', + 'media_type': 'podcast_episode', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': 'The history of The History of Rome...Why the Western Empire Fell when it did...Some thoughts on the future...Thank you, goodnight.', + 'explicit': None, + 'genres': None, + 'images': None, + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': None, + 'performers': None, + 'popularity': None, + 'preview': None, + 'release_date': '2012-05-06T18:18:38+00:00', + 'review': None, + 'style': None, + }), + 'name': '179- The End', + 'podcast': dict({ + 'external_ids': list([ + ]), + 'favorite': False, + 'is_playable': True, + 'item_id': 'pd-5', + 'media_type': 'podcast', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': 'A weekly podcast tracing the rise, decline and fall of the Roman Empire. Now complete!', + 'explicit': None, + 'genres': None, + 'images': list([ + dict({ + 'path': 'pd-5', + 'provider': 'xx-instance-id-xx', + 'remotely_accessible': False, + 'type': 'thumb', + }), + ]), + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': None, + 'performers': None, + 'popularity': None, + 'preview': None, + 'release_date': None, + 'review': None, + 'style': None, + }), + 'name': 'The History of Rome', + 'position': None, + 'provider': 'opensubsonic', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': 'pd-5', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'publisher': None, + 'sort_name': 'history of rome, the', + 'total_episodes': 5, + 'translation_key': None, + 'uri': 'http://feeds.feedburner.com/TheHistoryOfRome', + 'version': '', + }), + 'position': 5, + 'provider': 'opensubsonic', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': 'pd-5$!$pe-1860', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'resume_position_ms': None, + 'sort_name': '179- the end', + 'translation_key': None, + 'uri': 'opensubsonic://podcast_episode/pd-5$!$pe-1860', + 'version': '', + }) +# --- +# name: test_parse_episode[no-duration.episode] + dict({ + 'duration': 0, + 'external_ids': list([ + ]), + 'favorite': False, + 'fully_played': None, + 'is_playable': True, + 'item_id': 'pd-5$!$pe-1860', + 'media_type': 'podcast_episode', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': 'The history of The History of Rome...Why the Western Empire Fell when it did...Some thoughts on the future...Thank you, goodnight.', + 'explicit': None, + 'genres': None, + 'images': None, + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': None, + 'performers': None, + 'popularity': None, + 'preview': None, + 'release_date': '2012-05-06T18:18:38+00:00', + 'review': None, + 'style': None, + }), + 'name': '179- The End', 'podcast': dict({ 'external_ids': list([ ]), @@ -790,6 +1334,750 @@ 'version': '', }) # --- +# name: test_parse_podcast[no-episodes.podcast] + dict({ + 'external_ids': list([ + ]), + 'favorite': False, + 'is_playable': True, + 'item_id': 'pd-5', + 'media_type': 'podcast', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': 'A weekly podcast tracing the rise, decline and fall of the Roman Empire. Now complete!', + 'explicit': None, + 'genres': None, + 'images': list([ + dict({ + 'path': 'pd-5', + 'provider': 'xx-instance-id-xx', + 'remotely_accessible': False, + 'type': 'thumb', + }), + ]), + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': None, + 'performers': None, + 'popularity': None, + 'preview': None, + 'release_date': None, + 'review': None, + 'style': None, + }), + 'name': 'The History of Rome', + 'position': None, + 'provider': 'opensubsonic', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': 'pd-5', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'publisher': None, + 'sort_name': 'history of rome, the', + 'total_episodes': 0, + 'translation_key': None, + 'uri': 'http://feeds.feedburner.com/TheHistoryOfRome', + 'version': '', + }) +# --- +# name: test_parse_track[missing-items.track] + dict({ + 'album': dict({ + 'available': True, + 'external_ids': list([ + ]), + 'image': None, + 'is_playable': True, + 'item_id': 'e8a0685e3f3ec6f251649af2b58b8617', + 'media_type': 'album', + 'name': 'Live at The Casbah - 2005-04-29', + 'provider': 'xx-instance-id-xx', + 'sort_name': 'live at the casbah - 2005-04-29', + 'translation_key': None, + 'uri': 'xx-instance-id-xx://album/e8a0685e3f3ec6f251649af2b58b8617', + 'version': '', + }), + 'artists': list([ + dict({ + 'external_ids': list([ + ]), + 'favorite': False, + 'is_playable': True, + 'item_id': 'fake_artist_unknown', + 'media_type': 'artist', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': None, + 'explicit': None, + 'genres': None, + 'images': None, + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': None, + 'performers': None, + 'popularity': None, + 'preview': None, + 'release_date': None, + 'review': None, + 'style': None, + }), + 'name': '[unknown]', + 'position': None, + 'provider': 'xx-instance-id-xx', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': 'fake_artist_unknown', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'sort_name': 'unknown]', + 'translation_key': None, + 'uri': 'xx-instance-id-xx://artist/fake_artist_unknown', + 'version': '', + }), + ]), + 'disc_number': 0, + 'duration': 0, + 'external_ids': list([ + list([ + 'musicbrainz_recordingid', + '189002e7-3285-4e2e-92a3-7f6c30d407a2', + ]), + ]), + 'favorite': True, + 'is_playable': True, + 'item_id': '082f435a363c32c57d5edb6a678a28d4', + 'media_type': 'track', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': None, + 'explicit': True, + 'genres': list([ + 'East coast', + 'Hip-Hop', + ]), + 'images': None, + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': 'slow', + 'performers': list([ + 'Artist 3', + 'Artist 4', + 'Artist 5', + ]), + 'popularity': None, + 'preview': None, + 'release_date': None, + 'review': None, + 'style': None, + }), + 'name': '"polar expedition"', + 'position': None, + 'provider': 'xx-instance-id-xx', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': '082f435a363c32c57d5edb6a678a28d4', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'sort_name': 'Polar expedition', + 'track_number': 0, + 'translation_key': None, + 'uri': 'xx-instance-id-xx://track/082f435a363c32c57d5edb6a678a28d4', + 'version': '', + }) +# --- +# name: test_parse_track[missing-items.track].1 + dict({ + 'album': dict({ + 'artist': 'pornophonique', + 'artistId': '97e0398acf63f9fb930d7d4ce209a52b', + 'artists': list([ + dict({ + 'id': 'ar-1', + 'name': 'Artist 1', + }), + dict({ + 'id': 'ar-2', + 'name': 'Artist 2', + }), + ]), + 'coverArt': 'al-ad0f112b6dcf83de5e9cae85d07f0d35_640a93a8', + 'created': '2023-03-10T02:19:35.784818075Z', + 'discTitles': list([ + dict({ + 'disc': 0, + 'title': 'Disc 0 title', + }), + dict({ + 'disc': 2, + 'title': 'Disc 1 title', + }), + ]), + 'displayArtist': 'Artist 1 feat. Artist 2', + 'duration': 1954, + 'explicitStatus': 'explicit', + 'genre': 'Hip-Hop', + 'genres': list([ + dict({ + 'name': 'Hip-Hop', + }), + dict({ + 'name': 'East coast', + }), + ]), + 'id': 'e8a0685e3f3ec6f251649af2b58b8617', + 'isCompilation': False, + 'moods': list([ + 'slow', + 'cool', + ]), + 'musicBrainzId': '189002e7-3285-4e2e-92a3-7f6c30d407a2', + 'name': 'Live at The Casbah - 2005-04-29', + 'originalReleaseDate': dict({ + 'day': 10, + 'month': 3, + 'year': 2001, + }), + 'playCount': 97, + 'played': '2023-03-28T00:45:13Z', + 'releaseDate': dict({ + 'day': 10, + 'month': 3, + 'year': 2001, + }), + 'releaseTypes': list([ + 'Album', + 'Remixes', + ]), + 'songCount': 8, + 'sortName': 'lagerfeuer (8-bit)', + 'starred': '2023-03-22T01:51:06Z', + 'userRating': 4, + 'version': 'Deluxe Edition', + 'year': 2007, + }), + 'artists': list([ + dict({ + 'external_ids': list([ + ]), + 'favorite': False, + 'is_playable': True, + 'item_id': 'fake_artist_unknown', + 'media_type': 'artist', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': None, + 'explicit': None, + 'genres': None, + 'images': None, + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': None, + 'performers': None, + 'popularity': None, + 'preview': None, + 'release_date': None, + 'review': None, + 'style': None, + }), + 'name': '[unknown]', + 'position': None, + 'provider': 'xx-instance-id-xx', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': 'fake_artist_unknown', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'sort_name': 'unknown]', + 'translation_key': None, + 'uri': 'xx-instance-id-xx://artist/fake_artist_unknown', + 'version': '', + }), + ]), + 'disc_number': 0, + 'duration': 0, + 'external_ids': list([ + list([ + 'musicbrainz_recordingid', + '189002e7-3285-4e2e-92a3-7f6c30d407a2', + ]), + ]), + 'favorite': True, + 'is_playable': True, + 'item_id': '082f435a363c32c57d5edb6a678a28d4', + 'media_type': 'track', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': None, + 'explicit': True, + 'genres': list([ + 'East coast', + 'Hip-Hop', + ]), + 'images': None, + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': 'slow', + 'performers': list([ + 'Artist 3', + 'Artist 4', + 'Artist 5', + ]), + 'popularity': None, + 'preview': None, + 'release_date': None, + 'review': None, + 'style': None, + }), + 'name': '"polar expedition"', + 'position': None, + 'provider': 'xx-instance-id-xx', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': '082f435a363c32c57d5edb6a678a28d4', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'sort_name': 'Polar expedition', + 'track_number': 0, + 'translation_key': None, + 'uri': 'xx-instance-id-xx://track/082f435a363c32c57d5edb6a678a28d4', + 'version': '', + }) +# --- +# name: test_parse_track[navi-various.track] + dict({ + 'album': dict({ + 'available': True, + 'external_ids': list([ + ]), + 'image': None, + 'is_playable': True, + 'item_id': 'e8a0685e3f3ec6f251649af2b58b8617', + 'media_type': 'album', + 'name': 'Live at The Casbah - 2005-04-29', + 'provider': 'xx-instance-id-xx', + 'sort_name': 'live at the casbah - 2005-04-29', + 'translation_key': None, + 'uri': 'xx-instance-id-xx://album/e8a0685e3f3ec6f251649af2b58b8617', + 'version': '', + }), + 'artists': list([ + dict({ + 'external_ids': list([ + ]), + 'favorite': False, + 'is_playable': True, + 'item_id': 'MA-NAVIDROME-The New Deal', + 'media_type': 'artist', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': None, + 'explicit': None, + 'genres': None, + 'images': None, + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': None, + 'performers': None, + 'popularity': None, + 'preview': None, + 'release_date': None, + 'review': None, + 'style': None, + }), + 'name': 'The New Deal', + 'position': None, + 'provider': 'opensubsonic', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': 'MA-NAVIDROME-The New Deal', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'sort_name': 'new deal, the', + 'translation_key': None, + 'uri': 'opensubsonic://artist/MA-NAVIDROME-The New Deal', + 'version': '', + }), + ]), + 'disc_number': 0, + 'duration': 0, + 'external_ids': list([ + list([ + 'musicbrainz_recordingid', + '189002e7-3285-4e2e-92a3-7f6c30d407a2', + ]), + ]), + 'favorite': True, + 'is_playable': True, + 'item_id': '082f435a363c32c57d5edb6a678a28d4', + 'media_type': 'track', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': None, + 'explicit': True, + 'genres': list([ + 'East coast', + 'Hip-Hop', + ]), + 'images': None, + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': 'slow', + 'performers': list([ + 'Artist 3', + 'Artist 4', + 'Artist 5', + ]), + 'popularity': None, + 'preview': None, + 'release_date': None, + 'review': None, + 'style': None, + }), + 'name': '"polar expedition"', + 'position': None, + 'provider': 'xx-instance-id-xx', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': '082f435a363c32c57d5edb6a678a28d4', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'sort_name': 'Polar expedition', + 'track_number': 0, + 'translation_key': None, + 'uri': 'xx-instance-id-xx://track/082f435a363c32c57d5edb6a678a28d4', + 'version': '', + }) +# --- +# name: test_parse_track[navi-various.track].1 + dict({ + 'album': dict({ + 'artist': 'pornophonique', + 'artistId': '97e0398acf63f9fb930d7d4ce209a52b', + 'artists': list([ + dict({ + 'id': 'ar-1', + 'name': 'Artist 1', + }), + dict({ + 'id': 'ar-2', + 'name': 'Artist 2', + }), + ]), + 'coverArt': 'al-ad0f112b6dcf83de5e9cae85d07f0d35_640a93a8', + 'created': '2023-03-10T02:19:35.784818075Z', + 'discTitles': list([ + dict({ + 'disc': 0, + 'title': 'Disc 0 title', + }), + dict({ + 'disc': 2, + 'title': 'Disc 1 title', + }), + ]), + 'displayArtist': 'Artist 1 feat. Artist 2', + 'duration': 1954, + 'explicitStatus': 'explicit', + 'genre': 'Hip-Hop', + 'genres': list([ + dict({ + 'name': 'Hip-Hop', + }), + dict({ + 'name': 'East coast', + }), + ]), + 'id': 'e8a0685e3f3ec6f251649af2b58b8617', + 'isCompilation': False, + 'moods': list([ + 'slow', + 'cool', + ]), + 'musicBrainzId': '189002e7-3285-4e2e-92a3-7f6c30d407a2', + 'name': 'Live at The Casbah - 2005-04-29', + 'originalReleaseDate': dict({ + 'day': 10, + 'month': 3, + 'year': 2001, + }), + 'playCount': 97, + 'played': '2023-03-28T00:45:13Z', + 'releaseDate': dict({ + 'day': 10, + 'month': 3, + 'year': 2001, + }), + 'releaseTypes': list([ + 'Album', + 'Remixes', + ]), + 'songCount': 8, + 'sortName': 'lagerfeuer (8-bit)', + 'starred': '2023-03-22T01:51:06Z', + 'userRating': 4, + 'version': 'Deluxe Edition', + 'year': 2007, + }), + 'artists': list([ + dict({ + 'external_ids': list([ + ]), + 'favorite': False, + 'is_playable': True, + 'item_id': 'MA-NAVIDROME-The New Deal', + 'media_type': 'artist', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': None, + 'explicit': None, + 'genres': None, + 'images': None, + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': None, + 'performers': None, + 'popularity': None, + 'preview': None, + 'release_date': None, + 'review': None, + 'style': None, + }), + 'name': 'The New Deal', + 'position': None, + 'provider': 'opensubsonic', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': 'MA-NAVIDROME-The New Deal', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'sort_name': 'new deal, the', + 'translation_key': None, + 'uri': 'opensubsonic://artist/MA-NAVIDROME-The New Deal', + 'version': '', + }), + ]), + 'disc_number': 0, + 'duration': 0, + 'external_ids': list([ + list([ + 'musicbrainz_recordingid', + '189002e7-3285-4e2e-92a3-7f6c30d407a2', + ]), + ]), + 'favorite': True, + 'is_playable': True, + 'item_id': '082f435a363c32c57d5edb6a678a28d4', + 'media_type': 'track', + 'metadata': dict({ + 'chapters': None, + 'copyright': None, + 'description': None, + 'explicit': True, + 'genres': list([ + 'East coast', + 'Hip-Hop', + ]), + 'images': None, + 'label': None, + 'languages': None, + 'last_refresh': None, + 'links': None, + 'lrc_lyrics': None, + 'lyrics': None, + 'mood': 'slow', + 'performers': list([ + 'Artist 3', + 'Artist 4', + 'Artist 5', + ]), + 'popularity': None, + 'preview': None, + 'release_date': None, + 'review': None, + 'style': None, + }), + 'name': '"polar expedition"', + 'position': None, + 'provider': 'xx-instance-id-xx', + 'provider_mappings': list([ + dict({ + 'audio_format': dict({ + 'bit_depth': 16, + 'bit_rate': 0, + 'channels': 2, + 'codec_type': '?', + 'content_type': '?', + 'output_format_str': '?', + 'sample_rate': 44100, + }), + 'available': True, + 'details': None, + 'item_id': '082f435a363c32c57d5edb6a678a28d4', + 'provider_domain': 'opensubsonic', + 'provider_instance': 'xx-instance-id-xx', + 'url': None, + }), + ]), + 'sort_name': 'Polar expedition', + 'track_number': 0, + 'translation_key': None, + 'uri': 'xx-instance-id-xx://track/082f435a363c32c57d5edb6a678a28d4', + 'version': '', + }) +# --- # name: test_parse_track[spec-child.track] dict({ 'album': dict({ diff --git a/tests/providers/opensubsonic/fixtures/albums/no-artist.album.json b/tests/providers/opensubsonic/fixtures/albums/no-artist.album.json new file mode 100644 index 00000000..ee448cb9 --- /dev/null +++ b/tests/providers/opensubsonic/fixtures/albums/no-artist.album.json @@ -0,0 +1,61 @@ +{ + "id": "ad0f112b6dcf83de5e9cae85d07f0d35", + "name": "8-bit lagerfeuer", + "artist": "pornophonique", + "year": 2007, + "coverArt": "al-ad0f112b6dcf83de5e9cae85d07f0d35_640a93a8", + "starred": "2023-03-22T01:51:06Z", + "duration": 1954, + "playCount": 97, + "genre": "Hip-Hop", + "created": "2023-03-10T02:19:35.784818075Z", + "songCount": 8, + "played": "2023-03-28T00:45:13Z", + "userRating": 4, + "recordLabels": [ + { + "name": "Sony" + } + ], + "musicBrainzId": "189002e7-3285-4e2e-92a3-7f6c30d407a2", + "genres": [ + { + "name": "Hip-Hop" + }, + { + "name": "East coast" + } + ], + "displayArtist": "Artist 1 feat. Artist 2", + "releaseTypes": [ + "Album", + "Remixes" + ], + "moods": [ + "slow", + "cool" + ], + "sortName": "lagerfeuer (8-bit)", + "originalReleaseDate": { + "year": 2001, + "month": 3, + "day": 10 + }, + "releaseDate": { + "year": 2001, + "month": 3, + "day": 10 + }, + "isCompilation": false, + "explicitStatus": "explicit", + "discTitles": [ + { + "disc": 0, + "title": "Disc 0 title" + }, + { + "disc": 2, + "title": "Disc 1 title" + } + ] +} diff --git a/tests/providers/opensubsonic/fixtures/albums/no-artist.info.json b/tests/providers/opensubsonic/fixtures/albums/no-artist.info.json new file mode 100644 index 00000000..b971e1be --- /dev/null +++ b/tests/providers/opensubsonic/fixtures/albums/no-artist.info.json @@ -0,0 +1,7 @@ +{ + "notes": "Download the full release here (creative commons). These cripsy beats are ripe with thumping funk and techno influences, sample wizardry and daring shuffles. Composed with the help of unique sound plugins which were especially programmed to measure Comfort Fit’s needs and wishes, we think the chances aren’t bad that you’ll fall for the unique sound signature, bounce and elegance of this unusual Hip Hop production. Ltj bukem / Good looking Rec., UK: \"Really love this music.\" Velanche / XLR8R, UK: \"Awesome job he's done... overall production is dope.\" Kwesi / BBE Music, UK: \"Wooooooowwwww... WHAT THE FUCK! THIS IS WHAT", + "musicBrainzId": "6e1d48f7-717c-416e-af35-5d2454a13af2", + "smallImageUrl": "http://localhost:8989/play/art/0f8c3cbd6b0b22c3b5402141351ac812/album/21/thumb34.jpg", + "mediumImageUrl": "http://localhost:8989/play/art/41b16680dc1b3aaf5dfba24ddb6a1712/album/21/thumb64.jpg", + "largeImageUrl": "http://localhost:8989/play/art/e6fd8d4e0d35c4436e56991892bfb27b/album/21/thumb174.jpg" +} diff --git a/tests/providers/opensubsonic/fixtures/artists/no-sort-name.artist.json b/tests/providers/opensubsonic/fixtures/artists/no-sort-name.artist.json new file mode 100644 index 00000000..2b151c6a --- /dev/null +++ b/tests/providers/opensubsonic/fixtures/artists/no-sort-name.artist.json @@ -0,0 +1,15 @@ +{ + "id": "37ec820ca7193e17040c98f7da7c4b51", + "name": "2 Mello", + "coverArt": "ar-37ec820ca7193e17040c98f7da7c4b51_0", + "albumCount": 1, + "userRating": 5, + "artistImageUrl": "https://demo.org/image.jpg", + "starred": "2017-04-11T10:42:50.842Z", + "musicBrainzId": "189002e7-3285-4e2e-92a3-7f6c30d407a2", + "roles": [ + "artist", + "albumartist", + "composer" + ] +} diff --git a/tests/providers/opensubsonic/fixtures/artists/no-sort-name.info.json b/tests/providers/opensubsonic/fixtures/artists/no-sort-name.info.json new file mode 100644 index 00000000..8e64ec6c --- /dev/null +++ b/tests/providers/opensubsonic/fixtures/artists/no-sort-name.info.json @@ -0,0 +1,7 @@ +{ + "biography": "Empty biography", + "musicBrainzId": "1", + "smallImageUrl": "http://localhost:8989/play/art/f20070e8e11611cc53542a38801d60fa/artist/2/thumb34.jpg", + "mediumImageUrl": "http://localhost:8989/play/art/2b9b6c057cd4bf21089ce7572e7792b6/artist/2/thumb64.jpg", + "largeImageUrl": "http://localhost:8989/play/art/e18287c23a75e263b64c31b3d64c1944/artist/2/thumb174.jpg" +} diff --git a/tests/providers/opensubsonic/fixtures/episodes/no-duration.episode.json b/tests/providers/opensubsonic/fixtures/episodes/no-duration.episode.json new file mode 100644 index 00000000..d44fd3d1 --- /dev/null +++ b/tests/providers/opensubsonic/fixtures/episodes/no-duration.episode.json @@ -0,0 +1,18 @@ +{ + "id": "pe-1860", + "isDir": false, + "title": "179- The End", + "parent": "", + "year": 2012, + "genre": "Podcast", + "coverArt": "pd-5", + "size": 15032655, + "contentType": "audio/mpeg", + "suffix": "mp3", + "path": "", + "channelId": "pd-5", + "status": "completed", + "streamId": "pe-1860", + "description": "The history of The History of Rome...Why the Western Empire Fell when it did...Some thoughts on the future...Thank you, goodnight.", + "publishDate": "2012-05-06T18:18:38Z" +} diff --git a/tests/providers/opensubsonic/fixtures/episodes/no-duration.podcast.json b/tests/providers/opensubsonic/fixtures/episodes/no-duration.podcast.json new file mode 100644 index 00000000..2cac9bc8 --- /dev/null +++ b/tests/providers/opensubsonic/fixtures/episodes/no-duration.podcast.json @@ -0,0 +1,101 @@ +{ + "id": "pd-5", + "url": "http://feeds.feedburner.com/TheHistoryOfRome", + "status": "skipped", + "title": "The History of Rome", + "description": "A weekly podcast tracing the rise, decline and fall of the Roman Empire. Now complete!", + "coverArt": "pd-5", + "originalImageUrl": "https://static.libsyn.com/p/assets/1/2/f/c/12fc067020662e91/THoR_Logo_1500x1500.jpg", + "episode": [ + { + "id": "pe-4805", + "isDir": false, + "title": "Ad-Free History of Rome Patreon", + "parent": "", + "year": 2024, + "genre": "Podcast", + "coverArt": "pd-5", + "size": 1717520, + "contentType": "audio/mpeg", + "suffix": "mp3", + "path": "", + "channelId": "pd-5", + "status": "completed", + "streamId": "pe-4805", + "description": "Become a patron and get the entire History of Rome backcatalog ad-fre, plus bonus content, behind the scenes peeks at the new book, plus a chat community where you can talk to me directly. Join today! Patreon: patreon.com/thehistoryofrome Merch Store: cottonbureau.com/mikeduncan", + "publishDate": "2024-11-05T02:35:00Z" + }, + { + "id": "pe-1857", + "isDir": false, + "title": "The Storm Before The Storm: Chapter 1- The Beasts of Italy", + "parent": "", + "year": 2017, + "genre": "Podcast", + "coverArt": "pd-5", + "size": 80207374, + "contentType": "audio/mpeg", + "suffix": "mp3", + "path": "", + "channelId": "pd-5", + "status": "completed", + "streamId": "pe-1857", + "description": "Audio excerpt from The Storm Before the Storm: The Beginning of the End of the Roman Republic by Mike Duncan. Forthcoming Oct. 24, 2017. Pre-order a copy today! Amazon Powells Barnes & Noble Indibound Books-a-Million Or visit us at: revolutionspodcast.com thehistoryofrome.com", + "publishDate": "2017-07-27T11:30:00Z" + }, + { + "id": "pe-1858", + "isDir": false, + "title": "Revolutions Launch", + "parent": "", + "year": 2013, + "genre": "Podcast", + "coverArt": "pd-5", + "size": 253200, + "contentType": "audio/mpeg", + "suffix": "mp3", + "path": "", + "channelId": "pd-5", + "status": "completed", + "streamId": "pe-1858", + "description": "Available at revolutionspodcast.com, iTunes, or anywhere else fine podcasts can be found.", + "publishDate": "2013-09-16T15:39:57Z" + }, + { + "id": "pe-1859", + "isDir": false, + "title": "Update- One Year Later", + "parent": "", + "year": 2013, + "genre": "Podcast", + "coverArt": "pd-5", + "size": 1588998, + "contentType": "audio/mpeg", + "suffix": "mp3", + "path": "", + "channelId": "pd-5", + "status": "completed", + "streamId": "pe-1859", + "description": "Next show coming soon!", + "publishDate": "2013-05-30T15:18:57Z" + }, + { + "id": "pe-1860", + "isDir": false, + "title": "179- The End", + "parent": "", + "year": 2012, + "genre": "Podcast", + "coverArt": "pd-5", + "size": 15032655, + "contentType": "audio/mpeg", + "suffix": "mp3", + "path": "", + "channelId": "pd-5", + "status": "completed", + "streamId": "pe-1860", + "description": "The history of The History of Rome...Why the Western Empire Fell when it did...Some thoughts on the future...Thank you, goodnight.", + "publishDate": "2012-05-06T18:18:38Z" + } + ] +} diff --git a/tests/providers/opensubsonic/fixtures/podcasts/no-episodes.podcast.json b/tests/providers/opensubsonic/fixtures/podcasts/no-episodes.podcast.json new file mode 100644 index 00000000..4c3f6e53 --- /dev/null +++ b/tests/providers/opensubsonic/fixtures/podcasts/no-episodes.podcast.json @@ -0,0 +1,9 @@ +{ + "id": "pd-5", + "url": "http://feeds.feedburner.com/TheHistoryOfRome", + "status": "skipped", + "title": "The History of Rome", + "description": "A weekly podcast tracing the rise, decline and fall of the Roman Empire. Now complete!", + "coverArt": "pd-5", + "originalImageUrl": "https://static.libsyn.com/p/assets/1/2/f/c/12fc067020662e91/THoR_Logo_1500x1500.jpg" +} diff --git a/tests/providers/opensubsonic/fixtures/tracks/missing-items.album.json b/tests/providers/opensubsonic/fixtures/tracks/missing-items.album.json new file mode 100644 index 00000000..2f81a242 --- /dev/null +++ b/tests/providers/opensubsonic/fixtures/tracks/missing-items.album.json @@ -0,0 +1,75 @@ + + +{ + "id": "e8a0685e3f3ec6f251649af2b58b8617", + "name": "Live at The Casbah - 2005-04-29", + "version": "Deluxe Edition", + "artist": "pornophonique", + "year": 2007, + "coverArt": "al-ad0f112b6dcf83de5e9cae85d07f0d35_640a93a8", + "starred": "2023-03-22T01:51:06Z", + "duration": 1954, + "playCount": 97, + "genre": "Hip-Hop", + "created": "2023-03-10T02:19:35.784818075Z", + "artistId": "97e0398acf63f9fb930d7d4ce209a52b", + "songCount": 8, + "played": "2023-03-28T00:45:13Z", + "userRating": 4, + "recordLabels": [ + { + "name": "Sony" + } + ], + "musicBrainzId": "189002e7-3285-4e2e-92a3-7f6c30d407a2", + "genres": [ + { + "name": "Hip-Hop" + }, + { + "name": "East coast" + } + ], + "artists": [ + { + "id": "ar-1", + "name": "Artist 1" + }, + { + "id": "ar-2", + "name": "Artist 2" + } + ], + "displayArtist": "Artist 1 feat. Artist 2", + "releaseTypes": [ + "Album", + "Remixes" + ], + "moods": [ + "slow", + "cool" + ], + "sortName": "lagerfeuer (8-bit)", + "originalReleaseDate": { + "year": 2001, + "month": 3, + "day": 10 + }, + "releaseDate": { + "year": 2001, + "month": 3, + "day": 10 + }, + "isCompilation": false, + "explicitStatus": "explicit", + "discTitles": [ + { + "disc": 0, + "title": "Disc 0 title" + }, + { + "disc": 2, + "title": "Disc 1 title" + } + ] +} diff --git a/tests/providers/opensubsonic/fixtures/tracks/missing-items.track.json b/tests/providers/opensubsonic/fixtures/tracks/missing-items.track.json new file mode 100644 index 00000000..6c0d7896 --- /dev/null +++ b/tests/providers/opensubsonic/fixtures/tracks/missing-items.track.json @@ -0,0 +1,78 @@ +{ + "id": "082f435a363c32c57d5edb6a678a28d4", + "parent": "e8a0685e3f3ec6f251649af2b58b8617", + "isDir": false, + "title": "\"polar expedition\"", + "album": "Live at The Casbah - 2005-04-29", + "year": 2005, + "coverArt": "mf-082f435a363c32c57d5edb6a678a28d4_6410b3ce", + "size": 19866778, + "suffix": "flac", + "starred": "2023-03-27T09:45:27Z", + "path": "The New Deal/Live at The Casbah - 2005-04-29/04 - \"polar expedition\".flac", + "playCount": 8, + "played": "2023-03-26T22:27:46Z", + "created": "2023-03-14T17:51:22.112827504Z", + "albumId": "e8a0685e3f3ec6f251649af2b58b8617", + "type": "music", + "mediaType": "song", + "isVideo": false, + "bpm": 134, + "comment": "This is a song comment", + "sortName": "Polar expedition", + "musicBrainzId": "189002e7-3285-4e2e-92a3-7f6c30d407a2", + "genres": [ + { + "name": "Hip-Hop" + }, + { + "name": "East coast" + } + ], + "displayArtist": "Artist 1 feat. Artist 2", + "displayAlbumArtist": "Artist 6 & Artist 7", + "contributors": [ + { + "role": "composer", + "artist": { + "id": "ar-3", + "name": "Artist 3" + } + }, + { + "role": "composer", + "artist": { + "id": "ar-4", + "name": "Artist 4" + } + }, + { + "role": "lyricist", + "artist": { + "id": "ar-5", + "name": "Artist 5" + } + }, + { + "role": "performer", + "subRole": "Bass", + "artist": { + "id": "ar-5", + "name": "Artist 5" + } + } + ], + "displayComposer": "Artist 3, Artist 4", + "moods": [ + "slow", + "cool" + ], + "explicitStatus": "explicit", + "replayGain": { + "trackGain": 0.1, + "albumGain": 1.1, + "trackPeak": 9.2, + "albumPeak": 9, + "baseGain": 0 + } +} diff --git a/tests/providers/opensubsonic/fixtures/tracks/navi-various.album.json b/tests/providers/opensubsonic/fixtures/tracks/navi-various.album.json new file mode 100644 index 00000000..2f81a242 --- /dev/null +++ b/tests/providers/opensubsonic/fixtures/tracks/navi-various.album.json @@ -0,0 +1,75 @@ + + +{ + "id": "e8a0685e3f3ec6f251649af2b58b8617", + "name": "Live at The Casbah - 2005-04-29", + "version": "Deluxe Edition", + "artist": "pornophonique", + "year": 2007, + "coverArt": "al-ad0f112b6dcf83de5e9cae85d07f0d35_640a93a8", + "starred": "2023-03-22T01:51:06Z", + "duration": 1954, + "playCount": 97, + "genre": "Hip-Hop", + "created": "2023-03-10T02:19:35.784818075Z", + "artistId": "97e0398acf63f9fb930d7d4ce209a52b", + "songCount": 8, + "played": "2023-03-28T00:45:13Z", + "userRating": 4, + "recordLabels": [ + { + "name": "Sony" + } + ], + "musicBrainzId": "189002e7-3285-4e2e-92a3-7f6c30d407a2", + "genres": [ + { + "name": "Hip-Hop" + }, + { + "name": "East coast" + } + ], + "artists": [ + { + "id": "ar-1", + "name": "Artist 1" + }, + { + "id": "ar-2", + "name": "Artist 2" + } + ], + "displayArtist": "Artist 1 feat. Artist 2", + "releaseTypes": [ + "Album", + "Remixes" + ], + "moods": [ + "slow", + "cool" + ], + "sortName": "lagerfeuer (8-bit)", + "originalReleaseDate": { + "year": 2001, + "month": 3, + "day": 10 + }, + "releaseDate": { + "year": 2001, + "month": 3, + "day": 10 + }, + "isCompilation": false, + "explicitStatus": "explicit", + "discTitles": [ + { + "disc": 0, + "title": "Disc 0 title" + }, + { + "disc": 2, + "title": "Disc 1 title" + } + ] +} diff --git a/tests/providers/opensubsonic/fixtures/tracks/navi-various.track.json b/tests/providers/opensubsonic/fixtures/tracks/navi-various.track.json new file mode 100644 index 00000000..38c4ebbb --- /dev/null +++ b/tests/providers/opensubsonic/fixtures/tracks/navi-various.track.json @@ -0,0 +1,79 @@ +{ + "id": "082f435a363c32c57d5edb6a678a28d4", + "parent": "e8a0685e3f3ec6f251649af2b58b8617", + "isDir": false, + "title": "\"polar expedition\"", + "album": "Live at The Casbah - 2005-04-29", + "artist": "The New Deal", + "year": 2005, + "coverArt": "mf-082f435a363c32c57d5edb6a678a28d4_6410b3ce", + "size": 19866778, + "suffix": "flac", + "starred": "2023-03-27T09:45:27Z", + "path": "The New Deal/Live at The Casbah - 2005-04-29/04 - \"polar expedition\".flac", + "playCount": 8, + "played": "2023-03-26T22:27:46Z", + "created": "2023-03-14T17:51:22.112827504Z", + "albumId": "e8a0685e3f3ec6f251649af2b58b8617", + "type": "music", + "mediaType": "song", + "isVideo": false, + "bpm": 134, + "comment": "This is a song comment", + "sortName": "Polar expedition", + "musicBrainzId": "189002e7-3285-4e2e-92a3-7f6c30d407a2", + "genres": [ + { + "name": "Hip-Hop" + }, + { + "name": "East coast" + } + ], + "displayArtist": "Artist 1 feat. Artist 2", + "displayAlbumArtist": "Artist 6 & Artist 7", + "contributors": [ + { + "role": "composer", + "artist": { + "id": "ar-3", + "name": "Artist 3" + } + }, + { + "role": "composer", + "artist": { + "id": "ar-4", + "name": "Artist 4" + } + }, + { + "role": "lyricist", + "artist": { + "id": "ar-5", + "name": "Artist 5" + } + }, + { + "role": "performer", + "subRole": "Bass", + "artist": { + "id": "ar-5", + "name": "Artist 5" + } + } + ], + "displayComposer": "Artist 3, Artist 4", + "moods": [ + "slow", + "cool" + ], + "explicitStatus": "explicit", + "replayGain": { + "trackGain": 0.1, + "albumGain": 1.1, + "trackPeak": 9.2, + "albumPeak": 9, + "baseGain": 0 + } +}