fix(media_player): channel-title fallback gated to the channel app (TIVIMATE_PACKAGE or audio_playback membership) — launcher never shows a channel number (F1)

This commit is contained in:
James Mackay committed 2026-10-08 10:52:08 +01:00
1 parent f58be9ed05
commit 392553ee26
2 files changed
+53 -1

No files matched your search

@@ -57,6 +57,7 @@ from .const import (
DOMAIN,
PROTOCOL_MEDIA_KEYS,
PROTOCOL_REMOTE_KEYS,
TIVIMATE_PACKAGE,
)
from .ha_adb_common import PlaybackIntent, running_apps_from_tasks
from .jellyfin import fetch_session_media_info
@@ -651,7 +652,11 @@ class NvidiaShieldMediaPlayer(MediaPlayerEntity):
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:
if title is None and self._last_channel and (
# F1: the channel number belongs to the channel app only — never
# leak it to the launcher or another foreground app.
foreground == TIVIMATE_PACKAGE or foreground in manager.audio_playback
):
title = self._last_channel
if title is None and not self._adb_store_info:
title = self.app_name or self.app_id or foreground
+47
View File
@@ -13,6 +13,7 @@ import entity_stublib
import pytest
from entity_stublib import ENTITIES_STUB_NAMES, install, load_entity_modules
from nsh.connection import ShieldConnectionManager
from nsh.const import TIVIMATE_PACKAGE
@pytest.fixture(autouse=True)
@@ -381,6 +382,20 @@ class TestAppFallback:
assert player.app_id == "com.google.android.youtube.tv"
def _ladder_player(modules, foreground=None, audio=None):
"""Standalone player with a foreground (and optional audio hint) set."""
player, _s, _i = make_player(modules)
manager = player._manager
manager.store.set("awake", True)
if foreground:
manager.store.set("foreground", foreground)
if audio:
manager.store.set("audio_playback", audio)
player._androidtv_entity = ""
player._read = lambda eid: None
return player, manager
class TestForegroundLadderTier:
"""P3-3a: the ladder branch between the media-session tier and ON."""
@@ -470,6 +485,38 @@ class TestForegroundLadderTier:
assert np == {"state": "idle", "title": "101", "source": "app"}
class TestChannelLeakGuard:
"""F1: the channel number never leaks to a non-channel foreground app."""
async def test_launcher_never_shows_the_channel_number(self, modules):
player, _m = _ladder_player(
modules, foreground="com.spocky.projengmenu"
)
player._last_channel = "101" # entered in TiviMate earlier
np = player._get_app_now_playing()
assert np is None # the leak is gone
async def test_channel_app_still_gets_the_channel_title(self, modules):
player, _m = _ladder_player(modules, foreground=TIVIMATE_PACKAGE)
player._last_channel = "101"
np = player._get_app_now_playing()
assert np == {"state": "idle", "title": "101", "source": "app"}
async def test_audio_member_can_carry_the_channel_title(self, modules):
player, manager = _ladder_player(
modules, foreground="ar.tvplayer.tv", audio=["ar.tvplayer.tv"]
)
player._last_channel = "205"
np = player._get_app_now_playing()
assert np["title"] == "205"
class TestVolumeAndPowerLadder:
async def test_volume_readout_from_protocol_push(self, modules):
player, served, _intents = make_player(modules)