feat(media_player): foreground tier in the state ladder with app-source now-playing (last-known → last_channel → audio hint), sensor reads the store's foreground priority chain (P3-3a,c)
This commit is contained in:
1 parent
1f0a4b2021
commit
bc457baae7
3 files changed
+140
-2
No files matched your search
@@ -131,6 +131,9 @@ class NvidiaShieldMediaPlayer(MediaPlayerEntity):
|
||||
# In-flight channel digit entry (play_media(channel) — §7); a new
|
||||
# play_media cancels the previous sequence (core task-cancel guard).
|
||||
self._channel_task = None
|
||||
# Last channel entered via play_media(channel) — the foreground
|
||||
# tier's title fallback when an app publishes no session (P3-3a).
|
||||
self._last_channel: str | None = None
|
||||
# Entity-owned background tasks (intent retries, media-info fetch);
|
||||
# cancelled on unload. The manager owns the socket — never touch it
|
||||
# here directly.
|
||||
@@ -468,6 +471,13 @@ class NvidiaShieldMediaPlayer(MediaPlayerEntity):
|
||||
if adb_info.paused:
|
||||
return MediaPlayerState.PAUSED
|
||||
|
||||
# Tier 3.5 (P3-3): foreground fallback — an app is open (protocol
|
||||
# current_app push, else the ADB mResumedActivity parse) but publishes
|
||||
# no media session. The device is still ON; the now-playing tier
|
||||
# carries the last-known/channel/audio-hint identity.
|
||||
if self._manager is not None and self._manager.foreground_app:
|
||||
return MediaPlayerState.ON
|
||||
|
||||
# Tier 4: On but no media
|
||||
return MediaPlayerState.ON
|
||||
|
||||
@@ -622,6 +632,36 @@ class NvidiaShieldMediaPlayer(MediaPlayerEntity):
|
||||
np["album"] = info.album
|
||||
return np
|
||||
|
||||
def _get_app_now_playing(self) -> dict | None:
|
||||
"""Foreground-tier now-playing (P3-3a): an app is open but publishes
|
||||
no media session (TiviMate, R2). Title = last known state, else the
|
||||
last channel entered, else the zero-cost audio-playback hint.
|
||||
"""
|
||||
manager = self._manager
|
||||
if manager is None:
|
||||
return None
|
||||
foreground = manager.foreground_app
|
||||
if not foreground:
|
||||
return None
|
||||
|
||||
state = "idle"
|
||||
title = None
|
||||
info = manager.last_known_session(foreground)
|
||||
if info is not None and (info.playing or info.paused):
|
||||
state = "playing" if info.playing else "paused"
|
||||
# Privacy mode: identity stays the app, never the media title
|
||||
title = None if not self._adb_store_info else info.title
|
||||
if title is None:
|
||||
title = self._last_channel
|
||||
if title is None and not self._adb_store_info:
|
||||
title = self.app_name or self.app_id or foreground
|
||||
if title is None and foreground in manager.audio_playback:
|
||||
# E hint (zero round-trip cost): audio was recently played
|
||||
title = "Media recently active"
|
||||
if title is None:
|
||||
return None # bare foreground app — the state stays ON regardless
|
||||
return {"state": state, "title": title, "source": "app"}
|
||||
|
||||
def _get_power_data(self) -> dict | None:
|
||||
"""Read current values from discovered power sensors."""
|
||||
if not self._power_sensors:
|
||||
@@ -656,10 +696,13 @@ class NvidiaShieldMediaPlayer(MediaPlayerEntity):
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict:
|
||||
# Now playing: prefer Jellyfin, fall back to ADB media session
|
||||
# Now playing: prefer Jellyfin, fall back to ADB media session,
|
||||
# then the foreground tier (P3-3a).
|
||||
now_playing = self._get_now_playing()
|
||||
if not now_playing:
|
||||
now_playing = self._get_adb_now_playing()
|
||||
if not now_playing:
|
||||
now_playing = self._get_app_now_playing()
|
||||
|
||||
attrs = {"app_id": self.app_id, "app_name": self.app_name,
|
||||
ATTR_MEDIA_DAG_ROLE: "source",
|
||||
@@ -802,6 +845,7 @@ class NvidiaShieldMediaPlayer(MediaPlayerEntity):
|
||||
if not digits:
|
||||
_LOGGER.warning("play_media(channel): no digits in %r", media_id)
|
||||
return
|
||||
self._last_channel = "".join(digits)
|
||||
self._cancel_inflight_channel()
|
||||
self._channel_task = self._track_task(
|
||||
self._channel_entry_sequence(digits)
|
||||
|
||||
Reference in new issue
Block a user