#!/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] <body> 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 · Album<TAB>file" 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