mpdcontrol

Sometimes I want to listen to an album, or two or three, or a genre and an album artist, or a stream and then let mpdq take over, or, or… and I just want to have one simple interface that can be as flexible as my music taste might be.

Hence, this program.

mpdc in action

(The very pretty interface on the left is rmpc, the Rusty Music Player Client.)

mpdcontrol.sh (or mpdc) builds an fzf picker from several music and radio sources, then sends the selected result to MPD or mpdq.

It can combine:

There’s icons in the picker to indicate what sort of thing you’re selecting, and then it’ll queue up the appropriate things. Or you can have it instantly change clear whatever’s playing. Or have it change after the currently-playing track (unless that’s a stream, since streams often don’t end).

Also, if you have anything in the “Bumper” genre, like “radio changing static” sounds, it’ll play that to signify the new change. It amuses me.

The additional script, add_soundclip.sh will add a random track from the “Sound Clip” genre to the end of the queue, if there is not already a track from that genre in the queue. It uses the same config files as mpdcontrol, and can be called on demand or on a timer.

Use Cases

Dependencies

System packages installable with apt (I’m using Debian Trixie):

sudo apt update
sudo apt install -y bash mpd mpc fzf jq grep sed coreutils mawk

Notes:

External tools referenced by this project:

mpdq is required for --stations.

simple_listen_to_di is optional, but has a script in it needed if you want the playlists for --listentodi.

Installation

Clone this repository and make the script executable:

chmod +x mpdcontrol.sh

If you want station support, install mpdq from: https://github.com/uriel1998/mpdq

If you want your .pls radio stations from Digitally Imported, look at: https://github.com/uriel1998/simple_listen_to_di

Configuration

The script looks for configuration in this order:

  1. Existing environment variables
  2. ./mpdc.ini
  3. $XDG_CONFIG_HOME/mpdc
  4. $HOME/.config/mpdc
  5. Built-in defaults

An example config is provided in mpdc.ini.example.

Common keys:

musicdir=/media/_Music
mpdserver=localhost
mpdport=6600
mpdpass=secret
DI_PLS_DIR=/path/to/pls/files
ADDMODE=2

ADDMODE values:

Usage

Show help:

./mpdcontrol.sh --help

Choose from everything:

./mpdcontrol.sh --all

Choose genres and albums, clearing the queue first:

./mpdcontrol.sh --genre --album --clear

Choose items and append them without clearing or cropping first:

./mpdcontrol.sh --genre --artist --append

Limit genre or album-artist additions to a fixed number of entries:

./mpdcontrol.sh --genre --limit 25

Shuffle album, genre, or album-artist tracks before adding them:

./mpdcontrol.sh --artist --shuffle

Choose from mpdq stations:

./mpdcontrol.sh --stations

--station and --stations are equivalent.

If multiple station entries are selected in the same run, the script keeps only one of them and chooses it at random.

Choose from ListenToDI .pls files in a custom directory:

./mpdcontrol.sh --listentodi --playlist-dir /path/to/pls

Emit the list of choices that would be shown in fzf, without opening fzf or changing playback:

./mpdcontrol.sh --emit --stations

Emit the raw internal records, using the unit separator character (0x1f) between fields:

./mpdcontrol.sh --emit-raw --stations

Emit JSON lines for external tooling:

./mpdcontrol.sh --emit-json --stations

Skip source collection and fzf entirely by providing one JSON input record:

./mpdcontrol.sh --input '{"source":"station","payload":"/home/steven/.config/mpdq/General_mix.cfg"}'

The script also accepts the shell-expanded unquoted form:

./mpdcontrol.sh --input {"source":"station","payload":"/home/steven/.config/mpdq/General_mix.cfg"}

For example, to directly add shuffled psytrance tracks with a limit of 10:

./mpdcontrol.sh --shuffle --limit 10 --input '{"source":"genre","payload":"psytrance"}'

--input accepts only one JSON object per run. To directly process multiple items, call mpdcontrol.sh once per item; the --input JSON is case-sensitive.

Enable verbose output:

./mpdcontrol.sh --all --loud

Supported Options

--playlist, --playlists
--station, --stations
--listentodi
--radiotray
--genre
--artist
--album
--all
--append
--clear
--crop
--limit NUMBER
--shuffle
--emit
--input JSON
--emit-raw
--emit-json
--playlist-dir PATH
--loud
-e, --emit
-i, --input
-h, --help

Behavior

The script dispatches by source:

Internal record format:

--emit-raw returns those fields separated by the ASCII unit separator character (0x1f).

--emit-json returns one JSON object per line, for example:

{"icon":"🎛️","source":"station","title":"Pop","payload":"/home/steven/apps/mpdq/config/Pop.cfg"}

--input accepts JSON with:

Accepted --input forms:

--input skips source collection and fzf, then immediately processes the provided item as if it had been selected by the user.

If you choose more than one thing, then:

Icon derived from sources including Control room icons created by Freepik - Flaticon, Quaver icons created by Freepik - Flaticon, and Terminal icons created by Smashicons - Flaticon