/
/
/
1"""
2Helpers for exposing MA library playlists as Yandex input_source modes.
3
4Wraps the few MA APIs used by the playlist-source feature so the rest of
5the provider stays decoupled from `mass.music`/`player_queues` internals
6and so tests can stub a single seam.
7"""
8
9from __future__ import annotations
10
11import asyncio
12import logging
13from typing import TYPE_CHECKING
14
15from music_assistant_models.config_entries import ConfigValueOption
16
17if TYPE_CHECKING:
18 from music_assistant.mass import MusicAssistant
19
20
21_LOGGER = logging.getLogger(__name__)
22
23
24async def fetch_playlist_options(mass: MusicAssistant) -> list[ConfigValueOption]:
25 """
26 Build ConfigValueOption list of all library playlists for the config form.
27
28 Pages through `iter_library_items` so the dropdown is not silently
29 truncated for users with very large libraries (the underlying
30 `library_items(limit=...)` defaults to 500). Used at config-render
31 time only. Fail-soft: returns [] if mass.music or the playlists
32 controller is not yet available (e.g. provider load order).
33 """
34 options: list[ConfigValueOption] = []
35 try:
36 async for playlist in mass.music.playlists.iter_library_items():
37 if not playlist.uri:
38 continue
39 provider_label = playlist.provider or ""
40 title = f"{playlist.name} ({provider_label})" if provider_label else playlist.name
41 options.append(ConfigValueOption(title=title, value=playlist.uri))
42 except asyncio.CancelledError:
43 raise
44 except Exception as exc:
45 # Fail-soft: this runs on every config-form render and races with
46 # provider/database startup. Don't spam stack traces â debug-level
47 # is enough for diagnostics, normal renders stay quiet.
48 _LOGGER.debug("Library playlists not available yet: %s", exc)
49 return []
50 return options
51
52
53async def play_playlist(mass: MusicAssistant, player_id: str, uri: str) -> None:
54 """
55 Start playback of a playlist URI on the given player's queue.
56
57 `play_media` accepts a URI string directly and resolves the playlist's
58 tracks into the queue. queue_id == player_id for the player's own queue.
59 """
60 await mass.player_queues.play_media(queue_id=player_id, media=uri)
61