if not images_list:
return UniqueList([])
+ # Filter out generic images if requested (for artists)
+ filtered_images = []
for img in images_list:
img_url = img["url"]
- # Skip generic placeholder images for artists if requested
if exclude_generic and "2a96cbd8b46e442fc41c2b86b821562f" in img_url:
continue
- return UniqueList(
- [
- MediaItemImage(
- type=ImageType.THUMB,
- path=img_url,
- provider=lookup_key,
- remotely_accessible=True,
- )
- ]
- )
- return UniqueList([])
+ filtered_images.append(img)
+
+ if not filtered_images:
+ return UniqueList([])
+
+ # Spotify orders images from largest to smallest (640x640, 300x300, 64x64)
+ # Select the largest (highest quality) image - the first one
+ best_image = filtered_images[0]
+
+ return UniqueList(
+ [
+ MediaItemImage(
+ type=ImageType.THUMB,
+ path=best_image["url"],
+ provider=lookup_key,
+ remotely_accessible=True,
+ )
+ ]
+ )
def parse_artist(artist_obj: dict[str, Any], provider: SpotifyProvider) -> Artist:
raise MediaNotFoundError(f"Podcast not found: {prov_podcast_id}")
return parse_podcast(podcast_obj, self)
+ @use_cache(43200) # 12 hours - balances freshness with performance
+ async def _get_podcast_episodes_data(self, prov_podcast_id: str) -> list[dict[str, Any]]:
+ """Get raw episode data from Spotify API (cached).
+
+ Args:
+ prov_podcast_id: Spotify podcast ID
+
+ Returns:
+ List of episode data dictionaries
+ """
+ episodes_data: list[dict[str, Any]] = []
+
+ try:
+ async for item in self._get_all_items(
+ f"shows/{prov_podcast_id}/episodes", market="from_token"
+ ):
+ if item and item.get("id"):
+ episodes_data.append(item)
+ except MediaNotFoundError:
+ self.logger.warning("Podcast %s not found", prov_podcast_id)
+ return []
+ except ResourceTemporarilyUnavailable as err:
+ self.logger.warning(
+ "Temporary error fetching episodes for %s: %s", prov_podcast_id, err
+ )
+ raise
+
+ return episodes_data
+
async def get_podcast_episodes(
self, prov_podcast_id: str
) -> AsyncGenerator[PodcastEpisode, None]:
"""Get all podcast episodes."""
- podcast = await self.get_podcast(prov_podcast_id)
- episode_position = 1
+ # Get podcast object for context if available - this should be cached from previous calls
+ podcast: Podcast | None = None
- async for item in self._get_all_items(
- f"shows/{prov_podcast_id}/episodes", market="from_token"
- ):
- if not (item and item["id"]):
- continue
+ try:
+ podcast = await self.mass.music.podcasts.get_provider_item(
+ prov_podcast_id, self.instance_id
+ )
+ except MediaNotFoundError:
+ self.logger.debug("Podcast %s not found in Music Assistant library", prov_podcast_id)
+
+ # If we don't have the podcast from MA context, get it via the API
+ if not podcast:
+ try:
+ podcast = await self.get_podcast(prov_podcast_id) # This is cached
+ except MediaNotFoundError:
+ self.logger.warning(
+ "Podcast with ID %s is no longer available on Spotify", prov_podcast_id
+ )
+
+ # Get cached episode data - this is where the performance improvement happens
+ episodes_data = await self._get_podcast_episodes_data(prov_podcast_id)
- episode = parse_podcast_episode(item, self, podcast=podcast)
- episode.position = episode_position
- episode_position += 1
+ # Parse and yield episodes with position
+ for idx, episode_data in enumerate(episodes_data):
+ episode = parse_podcast_episode(episode_data, self, podcast)
+ episode.position = idx + 1
yield episode
@use_cache(86400) # 24 hours