feat(media): SmtcController.pause() erkennt und pausiert PLAYING-Sessions
This commit is contained in:
@@ -73,3 +73,79 @@ async def test_pause_skips_reconnect_after_smtc_failure(monkeypatch):
|
|||||||
await controller.pause()
|
await controller.pause()
|
||||||
|
|
||||||
assert call_count == 1
|
assert call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_pause_with_no_sessions_is_noop(monkeypatch):
|
||||||
|
from whisper_local.media._smtc import SmtcController
|
||||||
|
|
||||||
|
controller = SmtcController()
|
||||||
|
monkeypatch.setattr(
|
||||||
|
controller, "_ensure_manager", AsyncMock(return_value=_make_manager([]))
|
||||||
|
)
|
||||||
|
|
||||||
|
await controller.pause()
|
||||||
|
|
||||||
|
assert controller._paused == []
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_pause_pauses_all_playing_sessions(monkeypatch):
|
||||||
|
from whisper_local.media._smtc import SmtcController
|
||||||
|
|
||||||
|
s1 = _make_session("Spotify", PLAYING)
|
||||||
|
s2 = _make_session("msedge", PLAYING)
|
||||||
|
controller = SmtcController()
|
||||||
|
monkeypatch.setattr(
|
||||||
|
controller,
|
||||||
|
"_ensure_manager",
|
||||||
|
AsyncMock(return_value=_make_manager([s1, s2])),
|
||||||
|
)
|
||||||
|
|
||||||
|
await controller.pause()
|
||||||
|
|
||||||
|
s1.try_pause_async.assert_awaited_once()
|
||||||
|
s2.try_pause_async.assert_awaited_once()
|
||||||
|
assert controller._paused == ["Spotify", "msedge"]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_pause_skips_already_paused_sessions(monkeypatch):
|
||||||
|
from whisper_local.media._smtc import SmtcController
|
||||||
|
|
||||||
|
playing = _make_session("Spotify", PLAYING)
|
||||||
|
already_paused = _make_session("msedge", PAUSED)
|
||||||
|
controller = SmtcController()
|
||||||
|
monkeypatch.setattr(
|
||||||
|
controller,
|
||||||
|
"_ensure_manager",
|
||||||
|
AsyncMock(return_value=_make_manager([playing, already_paused])),
|
||||||
|
)
|
||||||
|
|
||||||
|
await controller.pause()
|
||||||
|
|
||||||
|
playing.try_pause_async.assert_awaited_once()
|
||||||
|
already_paused.try_pause_async.assert_not_awaited()
|
||||||
|
assert controller._paused == ["Spotify"]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_pause_logs_and_continues_when_session_fails(monkeypatch, caplog):
|
||||||
|
from whisper_local.media._smtc import SmtcController
|
||||||
|
|
||||||
|
broken = _make_session("broken", PLAYING)
|
||||||
|
broken.try_pause_async = AsyncMock(side_effect=RuntimeError("Verbindung verloren"))
|
||||||
|
good = _make_session("Spotify", PLAYING)
|
||||||
|
controller = SmtcController()
|
||||||
|
monkeypatch.setattr(
|
||||||
|
controller,
|
||||||
|
"_ensure_manager",
|
||||||
|
AsyncMock(return_value=_make_manager([broken, good])),
|
||||||
|
)
|
||||||
|
|
||||||
|
with caplog.at_level("WARNING"):
|
||||||
|
await controller.pause()
|
||||||
|
|
||||||
|
good.try_pause_async.assert_awaited_once()
|
||||||
|
assert controller._paused == ["Spotify"]
|
||||||
|
assert any("broken" in r.message for r in caplog.records)
|
||||||
|
|||||||
@@ -24,12 +24,32 @@ class SmtcController:
|
|||||||
)
|
)
|
||||||
return self._manager
|
return self._manager
|
||||||
|
|
||||||
|
async def _pause_session(self, session: Any) -> str | None:
|
||||||
|
"""Pausiert eine Session wenn sie spielt. Gibt AUMID zurück, sonst None."""
|
||||||
|
from winrt.windows.media.control import (
|
||||||
|
GlobalSystemMediaTransportControlsSessionPlaybackStatus,
|
||||||
|
)
|
||||||
|
aumid = session.source_app_user_model_id
|
||||||
|
try:
|
||||||
|
info = session.get_playback_info()
|
||||||
|
if (
|
||||||
|
info.playback_status
|
||||||
|
!= GlobalSystemMediaTransportControlsSessionPlaybackStatus.PLAYING
|
||||||
|
):
|
||||||
|
return None
|
||||||
|
await session.try_pause_async()
|
||||||
|
return aumid
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("Konnte Session %s nicht pausieren: %s", aumid, e)
|
||||||
|
return None
|
||||||
|
|
||||||
async def pause(self) -> None:
|
async def pause(self) -> None:
|
||||||
if self._broken:
|
if self._broken:
|
||||||
self._paused = []
|
self._paused = []
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await self._ensure_manager()
|
manager = await self._ensure_manager()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"SMTC nicht erreichbar, Media-Pause dauerhaft deaktiviert: %s", e
|
"SMTC nicht erreichbar, Media-Pause dauerhaft deaktiviert: %s", e
|
||||||
@@ -38,5 +58,13 @@ class SmtcController:
|
|||||||
self._paused = []
|
self._paused = []
|
||||||
return
|
return
|
||||||
|
|
||||||
|
sessions = list(manager.get_sessions())
|
||||||
|
paused = []
|
||||||
|
for session in sessions:
|
||||||
|
result = await self._pause_session(session)
|
||||||
|
if result is not None:
|
||||||
|
paused.append(result)
|
||||||
|
self._paused = paused
|
||||||
|
|
||||||
async def resume(self) -> None:
|
async def resume(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|||||||
Reference in New Issue
Block a user