Playing sources and browse actions¶
BluOS exposes two different kinds of URL-like values. They are invoked differently.
Source URLs¶
Player.play_url accepts a stream URL or BluOS source identifier and constructs a
/Play?url=... request. The url values returned by Player.inputs and
Player.presets are source URLs:
inputs = await player.inputs()
await player.play_url(inputs[0].url)
presets = await player.presets()
await player.play_url(presets[0].url)
await player.play_url("https://example.com/radio.mp3")
Browse action URLs¶
The browse API instead returns complete, opaque action URIs. These values may start with /Play, /Add, or
another endpoint, and may contain service-specific query parameters. Pass them unchanged to
Player.execute_action; do not pass them to
Player.play_url.
A BrowseItem may provide two playback actions:
play_action_urlThe item’s default play action.
autoplay_action_urlAn optional auto-fill action. Depending on the service and item, it may play the item and add subsequent tracks from the containing album, playlist, or other object to the auto-fill section of the play queue.
Both fields are optional, so check for None before invoking them:
root = await player.browse()
browse_item = next(item for item in root.items if item.browse_key is not None)
result = await player.browse(key=browse_item.browse_key)
item = result.items[0]
if item.play_action_url is not None:
await player.execute_action(item.play_action_url)
# Use this instead when the service provides an auto-fill action.
if item.autoplay_action_url is not None:
await player.execute_action(item.autoplay_action_url)
For example, an action URI might be /Add?service=Service&albumid=1&playnow=1. It is already a complete player
request. Calling player.play_url(item.play_action_url) would incorrectly place that complete URI inside a second
/Play?url=... request.
Audio settings¶
Audio settings are available through player.settings. Each read fetches fresh
state; availability means the player advertises the setting. Unsupported settings
return None from get().
if await player.settings.treble.is_available():
print(await player.settings.treble.get())
print(await player.settings.treble.range()) # Bounds, step, and units.
for choice in await player.settings.output_mode.choices():
print(choice.name, choice.display_name, choice.active)
For replay_gain and output_mode, getters and setters both use raw names.
Their getters preserve unlisted active names and return None only when the
setting is absent. choices() returns a list of SettingValue
entries, empty when unavailable; use display_name for presentation.
Numeric range() methods return SettingRange or None.
Legacy choice settings¶
listening_mode and subwoofer_mode retain their original behavior for
backward compatibility. Unlike replay_gain and output_mode:
get()returns a display label, such as"Movie"or"Off", not a raw name.set(name)still requires the raw name, such as"MOVIE"or"default".Choices are read through
values(), notchoices().An unlisted active name produces
Nonefromget(), rather than the raw name.is_available()requires at least one choice, rather than just a present setting.
Warning
Do not pass a legacy setting’s get() result directly to set().
To save a value for later restoration, read the active choice’s raw name:
choices = await player.settings.subwoofer_mode.values()
original_name = next((choice.name for choice in choices if choice.active), None)
# Restore with set(original_name) only if original_name is not None.
listening_mode.values() returns ListeningModeValue entries,
which include an icon. subwoofer_mode.values() returns
SubwooferModeValue entries. The newer choices() methods return
SettingValue entries. All expose name, display_name, and
active.
Writing settings¶
Setters mutate the player. They do not check advertised choices/ranges or read back the result. Numeric setters reject booleans and non-finite numbers; volume limits must also be in ascending order.
All methods accept timeout in seconds, defaulting to the player’s timeout.
See Settings and the API Reference for all setting classes.