MPD Dynamic Playlist Daemon
Watch the MPD playlist and automatically add similar songs before the queue runs out. Suggestions are based on LastFM or local heuristics such as genre tags.
Services such as for example Spotify or Last.fm provide a dynamic playlist feature of some sort: Once “seeded” with an artist, collection, or listening profile, a virtually unlimited amount of “similar” songs is continuously added – and thereby reactively creating a bubble for a certain mood.
For locally maintained music collections, the Music Player Daemon with its server/client architecture provides an API that allows external scripts to extend it with similar functionality.
Mode of Operation
The mpd_dynamic
Python script connects to the local (or remote) MPD port and starts watching the playlist in order to ensure there is always a certain number of songs in the queue after the currently played title.
Basis for suggesting new songs is the playlist history: Initially seeded with the current queue, most recently played – i.e., not timely skipped – titles provide the context for further searching similar songs. For example, when starting with a certain album, the general mood will be maintained by reinforcing a set of corresponding artists and genres over time.
By treating the current state of the playlist history as set of “approved” songs, their artist and genre tags are used to heuristically generate a pool of future candidates by searching the music library.
In total four methods are currently supported: Same artist, same genre, partially matching genre, and the online Last.fm similarArtists
API.
Each method or even result has an own (possibly configurable) weight which gets summed up per track and forms the probability when randomly selecting the amount of songs needed for filling up the playlist ahead of time.
Usage
No additional arguments are needed if MPD is running on its local TCP port.
usage: mpd_dynamic.py [-h] [--debug] [--host HOST] [--port PORT] [--config CONFIG.INI]
MPD Dynamic Playlist Daemon.
Uses playlist history context to heuristically determine similar songs which are then added to the
playlist in order to ensure there always is a certain number ahead of the currently played title.
Enabled when neither random, repeat, nor consume is set.
optional arguments:
-h, --help show this help message and exit
--debug enable more verbose log output (default: False)
--host HOST MPD hostname or ip address for TCP connections (default: 127.0.0.1)
--port PORT MPD port number for TCP connections (default: 6600)
--config CONFIG.INI configuration file (default: None)
After connecting, the playlist will be watched and corresponding suggestions are added when needed.
In general, mpd_dynamic
stays inactive when not playing or random, repeat, or consume is set – one of these flags can thus be used to toggle or reset the history and state.
Graceful shutdown with Ctrl^C (KeyboardInterrupt
).
Configuration
No configuration file is required but can be given for a more fine-grained control on the inner workings. If not explicitly provided, the defaults are equivalent to the following settings:
[playlist]
suggest_len = 5
blacklist = ""
[history]
history_len = 10
approved_timeout = 30.0
duplicate_history_max_len = 100
duplicate_history_len = 25
[weights]
artist = 1.0
genre = 0.5
fuzzy_genre = 0.2
lastfm = 1.0
The playlist
and history
sections mainly configure how the history is maintained:
suggest_len
- Ensure that the playlist is always ahead of the currently played song by appending generated suggestions.
blacklist
- Regular expression applied to library filenames. Matching songs are not accounted for in the history and will not be automatically added to the playlist.
history_len
- Number of songs that are tracked for the basis of generated suggestions. These are the last songs in the current playlist on startup and will be updated with actually played songs.
approved_timeout
- Only add songs to the history that are listened to for this long (in seconds). Songs that are skipped before this timeout are thus not counted.
duplicate_history_max_len
- Discourage adding duplicate songs by checking the end of the current playlist. Zero to not treat already existing songs special.
duplicate_history_len
- Try to avoid adding duplicates even harder for this amount of songs.
For each entry in the history, multiple methods are tried for deriving suggestions from it.
How much each module contributes to the overall result can be tweaked in the weights
section.
artist
- Search the library for songs of the current artist.
genre
- Search the library for all songs with the current genre.
fuzzy_genre
- Split the genre in question into substrings before searching the library. For example, Progressive Rock could yield Rock, Progressive Metal, Hard Rock, etc.
lastfm
- Query Last.fm for similar artists (includes individual weights) and search the library correspondingly.
This method currently requires the
LASTFM_API_KEY
environment variable to be set.
All weights will accumulate to a probability before randomly selecting a result, so tracks that are suggested by multiple methods are favored. A value of zero effectively disables the respective module.
Please note that library (and API) search results are locally cached to improve performance, so changes might not be reflected during runtime.
Installation
No installation is needed if the Python requirements (namely python-mpd2
and requests
) are already present as the locally executable mpd_dynamic.py
script is self-contained.
The standard way for installing mpd_dynamic
with its dependencies user- or system-wide is via pip
:
pip install .
pip uninstall mpd_dynamic
This is basically also what make install
and make uninstall
will do.
Related Work
There already exist at least three other closely related projects, with some having minor limitations leading to not quiet satisfying results for my setup. However, all should be credited as inspiration for my take on this topic.
mpd-dynamic – a dynamic playlist for mpd – Perl, on CPAN
This program implements a dynamic playlist for MPD, built on top of the Audio::MPD perl module.
Seems to unconditionally select random songs to be added, based on a minimum per-file rating that is manually maintained in a database. No notion of “similarity” is involved.
mpd-dynamic – Dynamic playlists for MPD using Spotify and LastFM – Python, on GitHub
This script will auto-complete your MPD playlist using track recommendations from Spotify and LastFM.
Seems to randomly select from all similar artists returned from the APIs. No “offline mode”, fully relies on Last.fm and/or Spotify without individual weights.
MPD-sima – Automagically add titles to MPD playlist – Python, on PyPI
MPD_sima is a non-interactive MPD autoqueue client running in the background. It will queue new tracks chosen among artists similar to your current queued tracks, provided a title is found in your music library.
Seems quite elaborate and even superior in complexity and functionality.