#!/bin/sh
# mpd-add: fuzzy-pick a track from the MPD library and play it right away.
# Works in a terminal (fzf) or launched from a menu (aurora-run).
#
# Usage: mpd-add [-q]
# -q queue the track right after the current one, but don't jump to it
QUEUE_ONLY=0
[ "${1:-}" = "-q" ] && QUEUE_ONLY=1
# Notifications replace each other instead of stacking (dunst/mako/swaync).
notify() { # notify [-u urgency]
urgency=normal
if [ "$1" = "-u" ]; then urgency=$2; shift 2; fi
echo "$1: $2" >&2
command -v notify-send >/dev/null 2>&1 || return 0
notify-send -a mpd-add -u "$urgency" \
-h string:x-canonical-private-synchronous:mpd-add \
-h string:x-dunst-stack-tag:mpd-add \
"$1" "$2"
}
if ! mpc status >/dev/null 2>&1; then
notify -u critical "MPD unreachable" "Is mpd running?"
exit 1
fi
# One "Artist - Title · Albumfile" line per track (the album makes typing an
# album name list its songs). Untagged tracks fall back to the file name (minus
# extension and a leading track number), and the artist is only prefixed when
# that name doesn't already contain one. Singles (album = title) skip the album.
library=$(mpc listall -f '%artist%\t%title%\t%album%\t%file%' | awk -F'\t' '{
artist = $1; title = $2; album = $3; file = $4
if (title == "") {
title = file
sub(/.*\//, "", title); sub(/\.[^.]*$/, "", title); sub(/^[0-9]+[.)]? *-? */, "", title)
if (index(title, " - ")) artist = ""
}
line = artist != "" ? artist " - " title : title
sub(/ - (Single|EP)$/, "", album)
if (album != "" && album != title) line = line " · " album
print line "\t" file
}')
if [ -z "$library" ]; then
notify -u critical "MPD library is empty" "Try: mpc update"
exit 1
fi
if [ -t 0 ]; then
filename=$(printf '%s\n' "$library" | fzf -d '\t' --with-nth 1 | cut -f2)
else
# aurora-run can't hide a column: show the names, map the index back to the file.
n=$(printf '%s\n' "$library" | cut -f1 | aurora-run -d -l 30 -p 'play: ' --index) || exit 0
[ "$n" -ge 0 ] 2>/dev/null || exit 0
filename=$(printf '%s\n' "$library" | sed -n "$((n + 1))p" | cut -f2)
fi
# Cancelled (Esc): nothing to do.
[ -z "$filename" ] && exit 0
# Position of the current song (1-based); empty if nothing is playing/paused.
cur=$(mpc -f '%position%' current)
if ! mpc insert "$filename" >/dev/null; then
notify -u critical "Couldn't add track" "$filename"
exit 1
fi
if [ "$QUEUE_ONLY" -eq 1 ]; then
notify "Queued next" "$filename"
exit 0
fi
# Jump straight to the song we just inserted. It lands right after the current
# song, or at the end of the queue when nothing is playing. Using an explicit
# position avoids `mpc next`, which misbehaves when stopped or paused.
if [ -n "$cur" ]; then
target=$((cur + 1))
else
target=$(mpc playlist | wc -l)
fi
if mpc play $target >/dev/null; then
now=$(mpc current)
notify "Now playing" "${now:-$filename}"
else
notify -u critical "Couldn't start playback" "$filename"
exit 1
fi