Rockbox open source high quality audio player as a Music Player Daemon
mpris
rockbox
mpd
libadwaita
audio
rust
zig
deno
1"""06 — Plugin: sleep timer.
2
3Stops playback after N minutes. If the user stops playback manually before the
4timer fires, the plugin cancels itself.
5
6 uv run python examples/06_plugin_sleep_timer.py # default 30 min
7 uv run python examples/06_plugin_sleep_timer.py 5 # 5 minutes
8"""
9
10from __future__ import annotations
11
12import asyncio
13import contextlib
14import sys
15from datetime import datetime, timedelta
16
17from _client import create_client # type: ignore[import-not-found]
18
19from rockbox_sdk import PlaybackStatus, PluginContext
20
21
22class SleepTimer:
23 name = "sleep-timer"
24 version = "1.0.0"
25
26 def __init__(self, minutes: int) -> None:
27 self.minutes = minutes
28 self.description = f"Stop playback after {minutes} minute(s)"
29 self._task: asyncio.Task[None] | None = None
30
31 def install(self, ctx: PluginContext) -> None:
32 fire_at = datetime.now() + timedelta(minutes=self.minutes)
33 print(f"💤 Sleep timer armed — will stop playback at {fire_at:%H:%M:%S}")
34
35 async def fire() -> None:
36 try:
37 await asyncio.sleep(self.minutes * 60)
38 except asyncio.CancelledError:
39 return
40 print("💤 Time's up — stopping playback.")
41 await ctx.query("mutation { hardStop }")
42
43 self._task = asyncio.create_task(fire())
44
45 @ctx.events.on("status:changed")
46 def cancel_on_stop(status: int) -> None:
47 if status == PlaybackStatus.STOPPED and self._task and not self._task.done():
48 self._task.cancel()
49 print("💤 Playback stopped manually — sleep timer cancelled.")
50
51 def uninstall(self) -> None:
52 if self._task and not self._task.done():
53 self._task.cancel()
54
55
56async def main(minutes: int) -> None:
57 async with create_client() as client:
58 await client.connect()
59 await client.use(SleepTimer(minutes))
60
61 print("Plugin installed. Press Ctrl+C to cancel and exit.")
62 with contextlib.suppress(asyncio.CancelledError):
63 await asyncio.Event().wait()
64
65
66if __name__ == "__main__":
67 minutes = int(sys.argv[1]) if len(sys.argv) > 1 else 30
68 try:
69 asyncio.run(main(minutes))
70 except KeyboardInterrupt:
71 print("\nbye")