Mopidy is an extensible music server written in Python
npx @tessl/cli install tessl/pypi-mopidy@3.4.0Mopidy is an extensible music server written in Python that enables users to play music from various sources including local files, Spotify, SoundCloud, and other cloud services through extensions. It provides a Python-based server architecture with HTTP and MPD protocol support, allowing control from multiple client types (web browsers, MPD clients, mobile apps) across different devices.
pip install Mopidyimport mopidyFor models and data structures:
from mopidy.models import (
Track, Album, Artist, Playlist, Ref, SearchResult, TlTrack, Image,
ValidatedImmutableObject, ImmutableObject, ModelJSONEncoder, model_json_decoder
)For extension development:
from mopidy.ext import Extension
from mopidy.backend import Backend, LibraryProvider, PlaybackProvider, PlaylistsProvider
from mopidy.config.schemas import ConfigSchema
from mopidy.config.types import String, Integer, Boolean, SecretFor core functionality:
from mopidy.core import (
Core, PlaybackController, LibraryController, TracklistController,
PlaylistsController, MixerController, HistoryController, CoreListener, PlaybackState
)For audio system:
from mopidy.audio import Audio, AudioListener
from mopidy.mixer import Mixer, MixerListenerFor exception handling:
from mopidy.exceptions import (
MopidyException, BackendError, CoreError, ExtensionError,
FrontendError, MixerError, ScannerError, AudioException,
ValidationError, TracklistFull
)import mopidy
from mopidy.models import Track, Artist, Album
from mopidy.ext import Extension
from mopidy.config.schemas import ConfigSchema
from mopidy.config.types import String
# Create basic music metadata
artist = Artist(uri="local:artist:example", name="Example Artist")
album = Album(uri="local:album:example", name="Example Album", artists=frozenset([artist]))
track = Track(
uri="local:track:example.mp3",
name="Example Track",
artists=frozenset([artist]),
album=album,
length=180000 # 3 minutes in milliseconds
)
# Define a simple extension
class MyExtension(Extension):
dist_name = "My-Extension"
ext_name = "my_extension"
version = "1.0.0"
def get_default_config(self):
config = super().get_default_config()
config["my_setting"] = "default_value"
return config
def get_config_schema(self):
schema = super().get_config_schema()
schema["my_setting"] = String()
return schema
print(f"Mopidy Version: {mopidy.__version__}")
print(f"Track: {track.name} by {track.artists.pop().name}")Mopidy follows a modular architecture built around these core components:
This architecture enables maximum extensibility for home music server setups, multi-room audio systems, and custom music streaming solutions.
Immutable data models for representing music metadata including tracks, albums, artists, playlists, and search results. These models form the foundation of Mopidy's data layer.
class Track(ValidatedImmutableObject):
uri: str
name: str
artists: frozenset[Artist]
album: Album
length: int # milliseconds
class Artist(ValidatedImmutableObject):
uri: str
name: str
sortname: str
musicbrainz_id: str
class Album(ValidatedImmutableObject):
uri: str
name: str
artists: frozenset[Artist]
num_tracks: int
date: strCentral business logic controllers for managing playback, library browsing, playlist management, tracklist operations, and audio mixing.
class Core(pykka.ThreadingActor):
def __init__(self, config, mixer, backends, audio): ...
class PlaybackController:
def play(self, tl_track=None): ...
def pause(self): ...
def stop(self): ...
def get_state(self): ...
class LibraryController:
def browse(self, uri, **kwargs): ...
def search(self, query=None, uris=None, exact=False): ...
def lookup(self, uris=None): ...Base classes and interfaces for implementing music source backends including library browsing, playback control, and playlist management providers.
class Backend:
def __init__(self, config, audio): ...
uri_schemes: list[str]
library: LibraryProvider
playback: PlaybackProvider
playlists: PlaylistsProvider
class LibraryProvider:
def browse(self, uri): ...
def search(self, query=None, uris=None, exact=False): ...
def lookup(self, uris): ...Plugin architecture for creating Mopidy extensions including configuration schemas, lifecycle management, and integration points.
class Extension:
dist_name: str
ext_name: str
version: str
def get_default_config(self): ...
def get_config_schema(self): ...
def setup(self, registry): ...
def validate_environment(self): ...Schema-based configuration management with validation, type safety, and support for multiple configuration sources.
class ConfigSchema:
def __init__(self, name): ...
def __setitem__(self, key, value): ...
class ConfigValue:
def deserialize(self, value): ...
def serialize(self, value, display=False): ...
def load(files, ext_schemas, ext_defaults, overrides): ...
def format(config, ext_schemas, comments=None, display=True): ...GStreamer-based audio pipeline with playback control, volume management, and audio format support.
class Audio(pykka.ThreadingActor):
def __init__(self, config, mixer): ...
def set_uri(self, uri): ...
def start_playback(self): ...
def pause_playback(self): ...
def stop_playback(self): ...
def supported_uri_schemes(): ...
def calculate_duration(num_samples, sample_rate): ...Mopidy provides comprehensive exception types for error handling across all system components.
from mopidy.exceptions import (
MopidyException, BackendError, CoreError, ExtensionError,
FrontendError, MixerError, ScannerError, TracklistFull,
AudioException, ValidationError
)
class MopidyException(Exception):
"""
Base exception for all Mopidy errors.
All Mopidy-specific exceptions inherit from this base class.
Provides a message property for error details.
Parameters:
- message (str): Error message
"""
def __init__(self, message, *args, **kwargs): ...
@property
def message(self): ...
class BackendError(MopidyException):
"""
Backend-related errors.
Raised when backend operations fail, such as music source
connection issues or playback provider errors.
"""
...
class CoreError(MopidyException):
"""
Core system errors.
Raised when core Mopidy functionality fails.
Parameters:
- message (str): Error message
- errno (int, optional): Error code
"""
def __init__(self, message, errno=None): ...
class ExtensionError(MopidyException):
"""
Extension-related errors.
Raised during extension loading, setup, or validation failures.
"""
...
class FrontendError(MopidyException):
"""
Frontend-related errors.
Raised when frontend components fail to initialize or operate.
"""
...
class MixerError(MopidyException):
"""
Audio mixer errors.
Raised when mixer operations fail, such as volume control issues.
"""
...
class ScannerError(MopidyException):
"""
Library scanning errors.
Raised when media library scanning fails.
"""
...
class TracklistFull(CoreError):
"""
Tracklist capacity exceeded error.
Raised when attempting to add tracks to a full tracklist.
Parameters:
- message (str): Error message
- errno (int, optional): Error code
"""
def __init__(self, message, errno=None): ...
class AudioException(MopidyException):
"""
Audio subsystem errors.
Raised when GStreamer audio pipeline operations fail.
"""
...
class ValidationError(ValueError):
"""
Data validation errors.
Raised when data validation fails, such as invalid model field values.
Note: Inherits from ValueError rather than MopidyException.
"""
...Event listener pattern for receiving notifications about system state changes and events.
from mopidy.core import CoreListener
from mopidy.audio import AudioListener
from mopidy.listener import Listener, send
class CoreListener:
def track_playback_started(self, tl_track): ...
def track_playback_paused(self, tl_track, time_position): ...
def track_playback_ended(self, tl_track, time_position): ...
def playback_state_changed(self, old_state, new_state): ...
def tracklist_changed(self): ...
def volume_changed(self, volume): ...
def send(event, **kwargs):
"""Send events to registered listeners."""
...