How Music Assistant's Provider Architecture (Music, Player, Metadata) Works
Music Assistant uses a modular provider architecture where all external integrations inherit from a common Provider base class and implement specialized interfaces for music libraries, playback devices, or metadata enrichment.
Music Assistant organizes every external integration through a hierarchical provider system defined in the music-assistant/server repository. This architecture categorizes integrations into three distinct provider types—MUSIC, PLAYER, and METADATA—each extending a shared foundation that handles configuration, logging, and feature declaration. Understanding this structure is essential for developing new integrations or troubleshooting existing ones.
The Three Provider Types
Music Assistant splits external services into three specialized domains, each with a dedicated abstract base class.
Music Provider
The Music Provider (music_assistant/models/music_provider.py) supplies catalogues of media items and synchronizes user libraries with Music Assistant. These providers handle artists, albums, tracks, playlists, radios, podcasts, and audiobooks.
Key responsibilities include:
- Search and browse operations via
search()and library methods likeget_library_artists() - Library synchronization through the
sync_library()method, which orchestrates full syncs for specificMediaTypevalues - Stream detail handling for custom audio streams
The sync_library() method iterates over provider library methods, creates or updates database items, and tracks processed IDs using CACHE_CATEGORY_PREV_LIBRARY_IDS to detect deletions.
Player Provider
The Player Provider (music_assistant/models/player_provider.py) controls playback devices including speakers, smart displays, and media players. These providers manage device discovery, grouping, and lifecycle events.
Core functionality includes:
- Device discovery via
discover_players() - Exposing a
playersproperty that returns allPlayerobjects belonging to the provider - Lifecycle callbacks:
on_player_enabled()andon_player_disabled() - Optional group player creation when
ProviderFeature.CREATE_GROUP_PLAYERis declared
Metadata Provider
The Metadata Provider (music_assistant/models/metadata_provider.py) enriches existing media items with supplementary information such as cover art, descriptions, similar items, and recommendations.
These providers operate on a priority basis:
- Each provider declares a
priorityattribute - Music Assistant queries providers in priority order until one returns a non-
Noneresult - Typical methods include
get_album_metadata(),get_similar_tracks(), andget_top_tracks()
The Common Provider Base Class
All provider types inherit from the Provider class in music_assistant/models/provider.py. This base implements shared infrastructure:
Configuration Handling
Each provider receives a ProviderConfig object during instantiation and can react to changes via update_config().
Feature Declaration
Providers expose capabilities through a supported_features set containing ProviderFeature enum values (defined in music_assistant/constants.py). The base class provides supports_feature() and check_feature() methods for runtime capability checks.
Logging
Providers receive a dedicated logger whose level is automatically configured based on the provider's settings via _set_log_level_from_config().
Lifecycle Hooks
The base class defines loaded_in_mass(), unload(), and async initialization hooks for startup and cleanup operations.
How the Provider System Functions
The architecture follows a strict discovery and enforcement pattern:
-
Discovery & Registration During startup, Music Assistant scans
providers/directories formanifest.jsonfiles. Each manifest declares the provider's type (ProviderType.MUSIC,PLAYER, orMETADATA), domain, and implemented features. -
Instantiation For each manifest, the system creates an instance of the appropriate concrete class, passing the global
MusicAssistantobject, manifest, config, and optional supported features to the constructor. -
Feature Enforcement Core actions are guarded by feature checks. For example,
MusicProvider.get_similar_tracks()is only invoked if the provider declaresProviderFeature.SIMILAR_TRACKS. Missing features raiseNotImplementedErrorin the base implementation. -
Library Synchronization For music providers, the
sync_library()method orchestrates full synchronizations by iterating over library methods, updating database records, and comparing cached IDs against current sets to detect removals. -
Metadata Enrichment When enrichment is needed, Music Assistant iterates over registered metadata providers by priority, stopping at the first successful result.
Implementation Examples
Declaring a Music Provider
# my_music_provider/__init__.py
from music_assistant.models.music_provider import MusicProvider
from music_assistant.constants import ProviderFeature
class MyMusicProvider(MusicProvider):
async def search(self, query: str, media_types: list[MediaType], limit: int = 5):
# Implementation of your service's search endpoint
pass
async def get_library_artists(self):
# Yield Artist objects from the remote service
pass
# manifest.json (placed next to the package)
{
"domain": "my_music",
"name": "My Music Service",
"type": "music",
"stage": "stable",
"features": [
"SEARCH",
"LIBRARY_ARTISTS",
"LIBRARY_ALBUMS",
"LIBRARY_TRACKS"
]
}
Using Metadata Providers for Album Art
async def enrich_album(album: Album) -> Album:
# Iterate over all metadata providers by priority
for prov in mass.providers.get_by_type("metadata"):
try:
md = await prov.get_album_metadata(album)
if md:
album.metadata = md
break
except NotImplementedError:
continue
return album
Summary
- Music Assistant's provider architecture centers on three specialized types: MusicProvider, PlayerProvider, and MetadataProvider.
- All providers inherit from the common
Providerbase class inmusic_assistant/models/provider.py, which handles configuration, logging, and feature checks. - Features are declared via the
ProviderFeatureenum and enforced at runtime usingsupports_feature()andcheck_feature(). - Music providers synchronize libraries using
sync_library()and track deletions via cache categories likeCACHE_CATEGORY_PREV_LIBRARY_IDS. - Player providers manage device lifecycles through
discover_players()and theplayersproperty, with optional group player support. - Metadata providers enrich content based on priority ordering, with the first successful result winning.
- New integrations require only a concrete subclass, a manifest JSON file, and proper feature declaration.
Frequently Asked Questions
What is the difference between a Music Provider and a Metadata Provider in Music Assistant?
A Music Provider supplies the actual catalog of media items (artists, albums, tracks) and handles library synchronization, while a Metadata Provider only enriches existing items with supplemental data like cover art, descriptions, or recommendations. Music providers are the source of truth for media existence, whereas metadata providers enhance information about items already in the system.
How does Music Assistant determine which provider method to call?
Music Assistant checks the supported_features set exposed by each provider instance. Before calling methods like get_similar_tracks() or create_group_player(), the core code verifies that the provider declares the corresponding ProviderFeature enum value. If the feature is missing, the system either skips the call or catches the NotImplementedError raised by the base class.
What files must I create to implement a new provider in Music Assistant?
You must create a Python class inheriting from the appropriate base (MusicProvider, PlayerProvider, or MetadataProvider) and place it in the providers/ directory. Additionally, you need a manifest.json file declaring the provider's domain, type, and features. The base class in music_assistant/models/provider.py handles configuration and logging automatically.
How does the Metadata Provider priority system work?
Each Metadata Provider declares a priority attribute. When Music Assistant needs enrichment data (such as album artwork), it queries providers in descending order of priority. The first provider that returns a non-None result wins, and subsequent providers are skipped. This allows high-priority sources (like local databases) to override lower-priority remote services.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →