diff --git a/src/tv.py b/src/tv.py index 041450d..9c0f0e0 100644 --- a/src/tv.py +++ b/src/tv.py @@ -70,8 +70,6 @@ LONG_PRESS_DELAY: float = 0.8 -HOMESCREEN_IMAGE = None - class Events(IntEnum): """Internal driver events.""" @@ -181,6 +179,8 @@ async def wrapper(self: _AndroidTvT, *args: _P.args, **kwargs: _P.kwargs) -> uca class AndroidTv(CastStatusListener, MediaStatusListener, ConnectionStatusListener): """Representing an Android TV device.""" + _homescreen_image = None + # pylint: disable=R0917 def __init__( self, @@ -253,6 +253,10 @@ async def init(self, max_timeout: int | None = None) -> bool: :param max_timeout: optional maximum timeout in seconds to try connecting to the device. Default: no timeout. :return: True if connected or connecting, False if timeout occurred. """ + # one-time initialization + if self._homescreen_image is None: + self._homescreen_image = await encode_icon_to_data_uri("config://androidtv.png") + if self._state in (DeviceState.INITIALIZING, DeviceState.CONNECTING): _LOG.debug("[%s] Skipping init task: connection task already running", self.log_id) return True @@ -653,89 +657,88 @@ def disconnect(self) -> None: # Callbacks async def _apply_current_app_metadata(self, current_app: str) -> dict: - global HOMESCREEN_IMAGE - update = {} - # one-time initialization - if HOMESCREEN_IMAGE is None: - HOMESCREEN_IMAGE = "" - HOMESCREEN_IMAGE = await encode_icon_to_data_uri("config://androidtv.png") - - # Special handling for homescreen & Android TV system apps: show pre-defined icon & clear media information - homescreen_app = apps.is_homescreen_app(current_app) - if homescreen_app or apps.is_standby_app(current_app): - self._clear_media_information() - update[MediaAttr.SOURCE] = apps.IdMappings[current_app] - update[MediaAttr.MEDIA_TITLE] = "" - update[MediaAttr.MEDIA_ALBUM] = "" - update[MediaAttr.MEDIA_ARTIST] = "" - update[MediaAttr.MEDIA_IMAGE_URL] = HOMESCREEN_IMAGE - update[MediaAttr.MEDIA_POSITION] = 0 - update[MediaAttr.MEDIA_DURATION] = 0 - update[MediaAttr.STATE] = ( - media_player.States.ON.value if homescreen_app else media_player.States.STANDBY.value - ) - return update - - # Track state of data sources - offline_name = None - offline_match = None - external_name = None - external_icon = None - - # Try offline ID mapping first - if current_app in apps.IdMappings: - offline_name = apps.IdMappings[current_app] - self._media_app = offline_name - - # Try fuzzy offline name matching if ID mapping failed - if not offline_name: - for query, name in apps.NameMatching.items(): - if query in current_app: - offline_match = name - self._media_app = name - break - # Try external metadata - metadata = ( - await get_app_metadata(current_app) if current_app and self._device_config.use_external_metadata else None - ) - if metadata: - if _LOG.isEnabledFor(logging.DEBUG): - _LOG.debug("App metadata: %s", filter_data_img_properties(metadata)) - external_name = metadata.get("name") - external_icon = metadata.get("icon") - if external_name: - self._media_app = external_name - if external_icon: - self._app_image_url = external_icon - - # Determine final name/title to use - name_to_use = offline_name or offline_match or external_name or current_app - # TODO why set name to both source & media title fields? - update[MediaAttr.SOURCE] = name_to_use - if not self._media_title and not self._media_image_url: - update[MediaAttr.MEDIA_TITLE] = name_to_use - - # Determine which icon to use - icon_to_use = None - if self._device_config.use_external_metadata or self._use_app_url: - if external_icon: - icon_to_use = external_icon - else: - icon_to_use = "" - elif self._media_image_url: - # TODO what's the intended logic? - # `icon_to_use` is never used because of the inverse `if not self._media_image_url:` check below! - icon_to_use = self._media_image_url - - update[MediaAttr.STATE] = media_player.States.PLAYING.value - # Skip applying app icon if media image from cast is present - if not self._media_image_url: - if not icon_to_use: - update[MediaAttr.MEDIA_IMAGE_URL] = HOMESCREEN_IMAGE - else: - update[MediaAttr.MEDIA_IMAGE_URL] = icon_to_use + try: + # Special handling for homescreen & Android TV system apps: show pre-defined icon & clear media information + homescreen_app = apps.is_homescreen_app(current_app) + if homescreen_app or apps.is_standby_app(current_app): + self._clear_media_information() + update[MediaAttr.SOURCE] = apps.IdMappings.get(current_app, current_app) + update[MediaAttr.MEDIA_TITLE] = "" + update[MediaAttr.MEDIA_ALBUM] = "" + update[MediaAttr.MEDIA_ARTIST] = "" + update[MediaAttr.MEDIA_IMAGE_URL] = self._homescreen_image + update[MediaAttr.MEDIA_POSITION] = 0 + update[MediaAttr.MEDIA_DURATION] = 0 + update[MediaAttr.STATE] = ( + media_player.States.ON.value if homescreen_app else media_player.States.STANDBY.value + ) + return update + + # Track state of data sources + offline_name = None + offline_match = None + external_name = None + external_icon = None + + # Try offline ID mapping first + if current_app in apps.IdMappings: + offline_name = apps.IdMappings[current_app] + self._media_app = offline_name + + # Try fuzzy offline name matching if ID mapping failed + if not offline_name: + for query, name in apps.NameMatching.items(): + if query in current_app: + offline_match = name + self._media_app = name + break + + # Try external metadata + metadata = ( + await get_app_metadata(current_app) + if current_app and self._device_config.use_external_metadata + else None + ) + if metadata: + if _LOG.isEnabledFor(logging.DEBUG): + _LOG.debug("App metadata: %s", filter_data_img_properties(metadata)) + external_name = metadata.get("name") + external_icon = metadata.get("icon") + if external_name: + self._media_app = external_name + if external_icon: + self._app_image_url = external_icon + + # Determine final name/title to use + name_to_use = offline_name or offline_match or external_name or current_app + # TODO why set name to both source & media title fields? + update[MediaAttr.SOURCE] = name_to_use + if not self._media_title and not self._media_image_url: + update[MediaAttr.MEDIA_TITLE] = name_to_use + + # Determine which icon to use + icon_to_use = None + if self._device_config.use_external_metadata or self._use_app_url: + if external_icon: + icon_to_use = external_icon + else: + icon_to_use = "" + elif self._media_image_url: + # TODO what's the intended logic? + # `icon_to_use` is never used because of the inverse `if not self._media_image_url:` check below! + icon_to_use = self._media_image_url + + update[MediaAttr.STATE] = media_player.States.PLAYING.value + # Skip applying app icon if media image from cast is present + if not self._media_image_url: + if not icon_to_use: + update[MediaAttr.MEDIA_IMAGE_URL] = self._homescreen_image + else: + update[MediaAttr.MEDIA_IMAGE_URL] = icon_to_use + except Exception: + _LOG.exception("[%s] Error during app metadata analysis", self.log_id) return update