Skip to content

Add Bose SoundTouch Favorites provider#3891

Open
Odn0 wants to merge 4 commits into
music-assistant:devfrom
Odn0:bose-soundtouch-favorites
Open

Add Bose SoundTouch Favorites provider#3891
Odn0 wants to merge 4 commits into
music-assistant:devfrom
Odn0:bose-soundtouch-favorites

Conversation

@Odn0
Copy link
Copy Markdown

@Odn0 Odn0 commented May 15, 2026

Hi Music Assistant community,

I created this plugin after the Bose SoundTouch end of life, to keep using the physical preset buttons on SoundTouch speakers with Music Assistant.

Summary

Adds a Bose SoundTouch Favorites plugin provider that listens for physical SoundTouch favorite button presses and maps them to configured Music Assistant media.

Motivation

Following the Bose SoundTouch end of life, SoundTouch speakers lost several connected-service features, including presets through the product buttons and the Bose app.

The purpose of this plugin is to restore a similar workflow in Music Assistant by associating Music Assistant favorites/media with the physical preset buttons on Bose SoundTouch speakers.

Reference: https://www.bose.com/soundtouch-end-of-life

Tested devices

Tested with:

  • Bose SoundTouch 10
  • Bose SoundTouch 20
  • Bose SoundTouch 30

Validation

  • uv run ruff check music_assistant/providers/bose_soundtouch_favorites
  • uv run mypy music_assistant/providers/bose_soundtouch_favorites

Note: full pre-commit run --all-files currently fails on existing mypy errors outside this provider.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 15, 2026

🔒 Dependency Security Report

📦 Modified Dependencies

music_assistant/providers/bose_soundtouch_favorites/manifest.json

Added:


🔍 Vulnerability Scan Results

No known vulnerabilities found

Name Skip Reason
torch Dependency not found on PyPI and could not be audited: torch (2.11.0+cpu)
torchaudio Dependency not found on PyPI and could not be audited: torchaudio (2.11.0+cpu)
✅ No known vulnerabilities found

Automated Security Checks

  • Vulnerability Scan: Passed - No known vulnerabilities
  • Trusted Sources: All packages have verified source repositories
  • Typosquatting Check: No suspicious package names detected
  • License Compatibility: All licenses are OSI-approved and compatible
  • Supply Chain Risk: Passed - packages appear mature and maintained

Manual Review

Maintainer approval required:

  • I have reviewed the changes above and approve these dependency updates

To approve: Comment /approve-dependencies or manually add the dependencies-reviewed label.

Comment thread music_assistant/providers/bose_soundtouch_favorites/__init__.py Outdated
Comment thread music_assistant/providers/bose_soundtouch_favorites/__init__.py Outdated
Comment thread music_assistant/providers/bose_soundtouch_favorites/__init__.py Outdated
Comment thread music_assistant/providers/bose_soundtouch_favorites/__init__.py Outdated
Comment thread music_assistant/providers/bose_soundtouch_favorites/__init__.py Outdated
Comment thread music_assistant/providers/bose_soundtouch_favorites/__init__.py Outdated
Comment thread music_assistant/providers/bose_soundtouch_favorites/__init__.py
Comment thread music_assistant/providers/bose_soundtouch_favorites/__init__.py Outdated
@OzGav OzGav added this to the 2.10.0 milestone May 18, 2026
@Odn0
Copy link
Copy Markdown
Author

Odn0 commented May 18, 2026

Thanks for the review.

I pushed updates addressing the WebSocket session, narrower exceptions, MA-specific setup errors, typed Player properties, MediaType values, config categories, and removed the hardcoded plugin version.

For the categories subject, I consolidated the per-button categories into a single Favorites category and added DIVIDER entries for each favorite. This keeps the UI clean and readable without the need to create six separate categories.

@Odn0 Odn0 force-pushed the bose-soundtouch-favorites branch from 6088ef0 to f47ac7d Compare May 18, 2026 17:05
@marcelveldt
Copy link
Copy Markdown
Member

Hi @Odn0, heads-up: #3938 just landed a refactor of the plugin sources architecture. The old PluginProvider.get_source() only allowed one source per provider instance — that limit is gone in the new model, so a SoundTouch Favorites provider can now naturally return one AudioSource per favorite.

The new contract on the provider:

  • async def get_audio_sources() -> list[AudioSource] — return one AudioSource per favorite
  • async def get_stream_details(source_id, queue_id) -> StreamDetails per session (raises ResourceBusyError on exclusive collisions if applicable)
  • async def get_audio_stream(streamdetails, seek_position) for CUSTOM streams (matches the MusicProvider signature)
  • async def on_source_control(source_id, action, value) for proxying play/pause/next/prev/seek/volume to the device
  • Optional async def on_source_selected(source_id, player_id, queue_id) hook for reacting to selection

AudioSources are browseable under the new top-level "Live Inputs" node, are favoritable, and play through the standard play_media flow. Canonical example: vban_receiver; the demo template at _demo_plugin_provider shows the recommended shape.

@Odn0
Copy link
Copy Markdown
Author

Odn0 commented May 21, 2026

Hi @Odn0, heads-up: #3938 just landed a refactor of the plugin sources architecture. The old PluginProvider.get_source() only allowed one source per provider instance — that limit is gone in the new model, so a SoundTouch Favorites provider can now naturally return one AudioSource per favorite.

The new contract on the provider:

  • async def get_audio_sources() -> list[AudioSource] — return one AudioSource per favorite
  • async def get_stream_details(source_id, queue_id) -> StreamDetails per session (raises ResourceBusyError on exclusive collisions if applicable)
  • async def get_audio_stream(streamdetails, seek_position) for CUSTOM streams (matches the MusicProvider signature)
  • async def on_source_control(source_id, action, value) for proxying play/pause/next/prev/seek/volume to the device
  • Optional async def on_source_selected(source_id, player_id, queue_id) hook for reacting to selection

AudioSources are browseable under the new top-level "Live Inputs" node, are favoritable, and play through the standard play_media flow. Canonical example: vban_receiver; the demo template at _demo_plugin_provider shows the recommended shape.

Thanks for the heads-up. I’m trying to make sure I understand the intended model before changing the plugin.

In this provider, a SoundTouch favorite button is currently only a physical trigger: when preset 1-6 is pressed, the plugin maps that preset to a configured MA media item and calls play_media for the configured target player. That target player is one Bose speaker; if the user wants to handle multiple Bose speakers, they would configure multiple instances of the plugin.

Do you expect each configured SoundTouch favorite to be exposed as its own AudioSource, even though it is not really an external/live audio source by itself, but rather a shortcut to an existing MA media item?

Or should the physical button handling remain separate, and only true live/external inputs be modeled as AudioSources?

@Hedda
Copy link
Copy Markdown

Hedda commented May 21, 2026

@Odn0 not sure but believe that you might want to consider maybe renaming this plugin provider from "bose_soundtouch_favorites" to just "soundtouch_favorites" as that name chance removes that company name which would better follow the naming scheme / naming convention of other providers in MA, or if @marcelveldt have better suggestion for the best name to use for this and other providers for long-term standardization of provider names(?).

Maybe its just my OCD, however does not look to be an a single standard naming scheme / naming convention guideline for providers, like for example the Apple AirPlay Receiver is only called "AirPlay Receiver", and the Amazon Alexa Player Provider is called only Alexa, while the Google Cast Player Provider is only called "Chromecast" in the manifest but refered to as "Google Cast" in the end-user documentation, as well as there are other providers which uses the manufacturer name when they use it in the brand, such as AriaCast Receiver, Spotify Connect, LastFM Scrobbler, and Plex Connect.

IMHO naming conventions that establish a unified standardized rules for file names and code elements are vitally importnat because they establish a predictable framework, ensuring your team and external developers can instantly find and understand critical directories/files without relying on guesswork. And recently having and using a single naming scheme has also become important to make different AI agent tools work properly.

@marcelveldt
Copy link
Copy Markdown
Member

@Odn0 you can ignore my previous message. I was trying to be smart/lazy by tagging all pluginsoure related PR's that a change was upcoming to PluginSources but your feature is not about that.

@Odn0
Copy link
Copy Markdown
Author

Odn0 commented May 23, 2026

No worries @marcelveldt, I understand. Thanks for clarifying.

@Hedda, regarding the provider name, I’m happy to follow the project’s preferred naming convention if there is one, and I can rename it if needed.

I originally included bose in bose_soundtouch_favorites to make the provider more explicit and easier to find for non-technical users. I initially built this plugin for my father, who uses a Home Assistant Green and has Bose speakers, but does not have a strong technical background.

If the maintainers prefer soundtouch_favorites or another name for consistency, no problem, I’ll update it.

@Odn0 Odn0 requested a review from OzGav May 24, 2026 20:39
@OzGav
Copy link
Copy Markdown
Contributor

OzGav commented May 26, 2026

mass.music.search has a stable, known signature — search_query, media_types, limit, library_only — and returns a typed SearchResults object. The entire _search_media_items function with its multiple kwargs/positional arg attempts, and _iter_search_result_items with its attribute probing, should be replaced with a single direct call. Similarly _media_item_title and _media_item_value should use the typed attributes on the SearchResults member models rather than getattr chains.

SearchResults has typed attributes, artists, albums, genres, tracks, playlists, radio, audiobooks, podcasts . So _media_item_title, _media_item_value, and _iter_search_result_items should all be rewritten against the actual typed models (Artist, Album, Track, Radio etc.) which all have a name attribute and uri from their base class. Additionally, MEDIA_TYPE_OPTIONS includes types like FOLDER, ANNOUNCEMENT, FLOW_STREAM that have no corresponding field on SearchResults and can never return search results so these should either be removed or handled explicitly

Comment thread music_assistant/providers/bose_soundtouch_favorites/__init__.py Outdated
@MarvinSchenkel MarvinSchenkel requested a review from Copilot May 26, 2026 11:19
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@Odn0
Copy link
Copy Markdown
Author

Odn0 commented May 26, 2026

mass.music.search has a stable, known signature — search_query, media_types, limit, library_only — and returns a typed SearchResults object. The entire _search_media_items function with its multiple kwargs/positional arg attempts, and _iter_search_result_items with its attribute probing, should be replaced with a single direct call. Similarly _media_item_title and _media_item_value should use the typed attributes on the SearchResults member models rather than getattr chains.

SearchResults has typed attributes, artists, albums, genres, tracks, playlists, radio, audiobooks, podcasts . So _media_item_title, _media_item_value, and _iter_search_result_items should all be rewritten against the actual typed models (Artist, Album, Track, Radio etc.) which all have a name attribute and uri from their base class. Additionally, MEDIA_TYPE_OPTIONS includes types like FOLDER, ANNOUNCEMENT, FLOW_STREAM that have no corresponding field on SearchResults and can never return search results so these should either be removed or handled explicitly

Thanks for the review. I updated the provider to use the stable mass.music.search signature directly and to work against the typed SearchResults fields instead of probing runtime shapes.

I also removed unsupported media types from the search options, switched the provider logging to self.logger, and cleaned up a few overly broad helpers/casts around config values and media result handling.

pre-commit run --all-files passes locally.

@Odn0 Odn0 requested a review from OzGav May 26, 2026 22:18
Comment thread music_assistant/providers/bose_soundtouch_favorites/__init__.py Outdated
@OzGav
Copy link
Copy Markdown
Contributor

OzGav commented May 26, 2026

Just one last comment from me. One of the others will have a look as well soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants