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.

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-dynamica 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-dynamicDynamic 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-simaAutomagically 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.

Code & Download