Skip to content

Commit

Permalink
Fix: chromecast: Provide an advanced option to downscale the image me…
Browse files Browse the repository at this point in the history
…tadata

My Chromecast Ultra crashes when presented with cover images on the order of
5000x5000 pixels (I've not determined the actual limit, 2048x2048 is ok
though).

Address this by providing an advanced option per player which downscales the
image to a specified size.

Fixes: https://github.com/music-assistant/hass-music-assistant/issues/3285
  • Loading branch information
ijc committed Dec 16, 2024
1 parent 5660ad3 commit d0b7a6f
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
11 changes: 11 additions & 0 deletions music_assistant/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
CONF_GROUP_MEMBERS: Final[str] = "group_members"
CONF_HIDE_PLAYER: Final[str] = "hide_player"
CONF_ENFORCE_MP3: Final[str] = "enforce_mp3"
CONF_LIMIT_IMAGE_SIZE: Final[str] = "limit_image_size"
CONF_SYNC_ADJUST: Final[str] = "sync_adjust"
CONF_TTS_PRE_ANNOUNCE: Final[str] = "tts_pre_announce"
CONF_ANNOUNCE_VOLUME_STRATEGY: Final[str] = "announce_volume_strategy"
Expand Down Expand Up @@ -287,6 +288,16 @@
{**CONF_ENTRY_ENFORCE_MP3.to_dict(), "default_value": True, "hidden": True}
)

CONF_ENTRY_LIMIT_IMAGE_SIZE = ConfigEntry(
key=CONF_LIMIT_IMAGE_SIZE,
type=ConfigEntryType.INTEGER,
label="Limit image size",
default_value=0,
description="Limit the size of image to send to this player (when non-zero). "
"Some players cannot cope with high-resolution images",
category="advanced",
)

CONF_ENTRY_SYNC_ADJUST = ConfigEntry(
key=CONF_SYNC_ADJUST,
type=ConfigEntryType.INTEGER,
Expand Down
38 changes: 38 additions & 0 deletions music_assistant/providers/chromecast/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
CONF_ENTRY_CROSSFADE_DURATION,
CONF_ENTRY_CROSSFADE_FLOW_MODE_REQUIRED,
CONF_ENTRY_ENFORCE_MP3,
CONF_ENTRY_LIMIT_IMAGE_SIZE,
CONF_LIMIT_IMAGE_SIZE,
CONF_PLAYERS,
MASS_LOGO_ONLINE,
VERBOSE_LOG_LEVEL,
Expand All @@ -51,6 +53,7 @@
CONF_ENTRY_CROSSFADE_FLOW_MODE_REQUIRED,
CONF_ENTRY_CROSSFADE_DURATION,
CONF_ENTRY_ENFORCE_MP3,
CONF_ENTRY_LIMIT_IMAGE_SIZE,
)

# originally/officially cast supports 96k sample rate (even for groups)
Expand Down Expand Up @@ -237,6 +240,33 @@ async def cmd_volume_mute(self, player_id: str, muted: bool) -> None:
castplayer = self.castplayers[player_id]
await asyncio.to_thread(castplayer.cc.set_volume_muted, muted)

def _handle_limit_image_size(self, limit: int, orig_url: str | None) -> str | None:
"""Handle CONF_LIMIT_IMAGE_SIZE for media item."""
if not orig_url or limit == 0:
return orig_url

try:
from urllib.parse import parse_qsl, urlencode, urlparse

url = urlparse(orig_url)
qsl = dict(parse_qsl(url.query))

size = int(qsl.get("size", "0"))
if size != 0 and size <= limit:
return orig_url

qsl["size"] = str(limit)
url = url._replace(query=urlencode(qsl))
return url.geturl()
except Exception as err:
self.logger.warning(
"Error while limiting image url size: %s",
str(err),
exc_info=err if self.logger.isEnabledFor(10) else None,
)

return orig_url

async def play_media(
self,
player_id: str,
Expand All @@ -246,6 +276,10 @@ async def play_media(
castplayer = self.castplayers[player_id]
if self.mass.config.get_raw_player_config_value(player_id, CONF_ENFORCE_MP3, False):
media.uri = media.uri.replace(".flac", ".mp3")
media.image_url = self._handle_limit_image_size(
self.mass.config.get_raw_player_config_value(player_id, CONF_LIMIT_IMAGE_SIZE),
media.image_url,
)
queuedata = {
"type": "LOAD",
"media": self._create_cc_media_item(media),
Expand All @@ -261,6 +295,10 @@ async def enqueue_next_media(self, player_id: str, media: PlayerMedia) -> None:
castplayer = self.castplayers[player_id]
if self.mass.config.get_raw_player_config_value(player_id, CONF_ENFORCE_MP3, False):
media.uri = media.uri.replace(".flac", ".mp3")
media.image_url = self._handle_limit_image_size(
self.mass.config.get_raw_player_config_value(player_id, CONF_LIMIT_IMAGE_SIZE),
media.image_url,
)
next_item_id = None
status = castplayer.cc.media_controller.status
# lookup position of current track in cast queue
Expand Down

0 comments on commit d0b7a6f

Please sign in to comment.