6868from music_assistant .helpers .api import api_command
6969from music_assistant .helpers .json import JSON_DECODE_EXCEPTIONS , async_json_dumps , async_json_loads
7070from music_assistant .helpers .util import load_provider_module
71+ from music_assistant .models import ProviderModuleType
7172
7273if TYPE_CHECKING :
7374 import asyncio
@@ -244,7 +245,7 @@ async def get_provider_config_value(self, instance_id: str, key: str) -> ConfigV
244245 return val
245246
246247 @api_command ("config/providers/get_entries" )
247- async def get_provider_config_entries (
248+ async def get_provider_config_entries ( # noqa: PLR0915
248249 self ,
249250 provider_domain : str ,
250251 instance_id : str | None = None ,
@@ -260,13 +261,21 @@ async def get_provider_config_entries(
260261 values: the (intermediate) raw values for config entries sent with the action.
261262 """
262263 # lookup provider manifest and module
264+ prov_mod : ProviderModuleType | None
263265 for manifest in self .mass .get_provider_manifests ():
264266 if manifest .domain == provider_domain :
265- prov_mod = await load_provider_module (provider_domain , manifest .requirements )
267+ try :
268+ prov_mod = await load_provider_module (provider_domain , manifest .requirements )
269+ except Exception as e :
270+ msg = f"Failed to load provider module for { provider_domain } : { e } "
271+ LOGGER .exception (msg )
272+ return []
266273 break
267274 else :
268275 msg = f"Unknown provider domain: { provider_domain } "
269- raise KeyError (msg )
276+ LOGGER .exception (msg )
277+ return []
278+
270279 if values is None :
271280 values = self .get (f"{ CONF_PROVIDERS } /{ instance_id } /values" , {}) if instance_id else {}
272281
@@ -416,14 +425,22 @@ async def get_player_configs(
416425 ]
417426
418427 @api_command ("config/players/get" )
419- async def get_player_config (self , player_id : str ) -> PlayerConfig :
428+ async def get_player_config (
429+ self ,
430+ player_id : str ,
431+ action : str | None = None ,
432+ values : dict [str , ConfigValueType ] | None = None ,
433+ ) -> PlayerConfig :
420434 """Return (full) configuration for a single player."""
421435 raw_conf : dict [str , Any ]
422436 if raw_conf := self .get (f"{ CONF_PLAYERS } /{ player_id } " ):
423437 if player := self .mass .players .get (player_id , False ):
424438 raw_conf ["default_name" ] = player .display_name
425439 raw_conf ["provider" ] = player .provider .lookup_key
426- conf_entries = await player .get_config_entries ()
440+ # pass action and values to get_config_entries
441+ if values is None :
442+ values = raw_conf .get ("values" , {})
443+ conf_entries = await player .get_config_entries (action = action , values = values )
427444 else :
428445 # handle unavailable player and/or provider
429446 conf_entries = []
@@ -434,6 +451,29 @@ async def get_player_config(self, player_id: str) -> PlayerConfig:
434451 msg = f"No config found for player id { player_id } "
435452 raise KeyError (msg )
436453
454+ @api_command ("config/players/get_entries" )
455+ async def get_player_config_entries (
456+ self ,
457+ player_id : str ,
458+ action : str | None = None ,
459+ values : dict [str , ConfigValueType ] | None = None ,
460+ ) -> list [ConfigEntry ]:
461+ """
462+ Return Config entries to configure a player.
463+
464+ player_id: id of an existing player instance.
465+ action: [optional] action key called from config entries UI.
466+ values: the (intermediate) raw values for config entries sent with the action.
467+ """
468+ if not (player := self .mass .players .get (player_id , False )):
469+ msg = f"Player { player_id } not found"
470+ raise KeyError (msg )
471+
472+ if values is None :
473+ values = self .get (f"{ CONF_PLAYERS } /{ player_id } /values" , {})
474+
475+ return await player .get_config_entries (action = action , values = values )
476+
437477 @api_command ("config/players/get_value" )
438478 async def get_player_config_value (
439479 self ,
0 commit comments