123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- #!/usr/bin/env bash
-
- declare -r esc=$(printf '\033')
- declare -r c_reset="${esc}[0m"
- declare -r c_red="${esc}[31m"
- declare -r track_format='[[[%artist% / ][[(%date%) ]%album% / ][%track%] - [%title%]]|%file%]'
-
- usage() {
- LESS=-FEXR less <<HELP
- fzmp [OPTIONS]
-
- -A --all search all songs in the library (or F1 when running)
- -a --artist search artist then filter by album (or F2 when running)
- -p --playlist search the current playlist (or F3 when running)
- -h --help print this help
- HELP
- }
-
- isRunning() {
- pgrep "$1" &> /dev/null
- }
-
- err() {
- printf "${c_red}%s${c_reset}\n" "$*" >&2
- }
-
- die() {
- [[ -n "$1" ]] && err "$*"
- exit 1
- }
-
- has() {
- local verbose=false
- if [[ $1 == '-v' ]]; then
- verbose=true
- shift
- fi
- for c in "$@"; do c="${c%% *}"
- if ! command -v "$c" &> /dev/null; then
- [[ "$verbose" == true ]] && err "$c not found"
- return 1
- fi
- done
- }
-
- fzf() {
- command fzf -e -i --reverse --cycle --inline-info "$@"
- }
-
- filterAllSongs() {
- local choice
- mapfile -t choice < <( mpc search -f "%file%\t$track_format" filename '' |
- fzf --multi \
- --with-nth='2..' \
- --delimiter='\t' \
- --expect='f2,f3,enter' |
- cut -f1)
- case "${choice[0]}" in
- 'f2') filterByArtist ;;
- 'f3') filterPlaylist ;;
- 'enter') printf '%s\n' "${choice[@]:1}" | playSongs ;;
- esac
- }
-
- filterByArtist() {
- local choice
- mapfile -t choice < <(mpc list artist | sort -h | fzf --expect='f1,f3,enter')
- (( "${#choice[@]}" > 0 )) || die
- case "${choice[0]}" in
- 'f1') filterAllSongs ;;
- 'f3') filterPlaylist ;;
- 'enter') filterByAlbumFromArtist "${choice[1]}" ;;
- esac
- }
-
- filterByAlbumFromArtist() {
- local album artist choice
- [[ -z "$1" ]] && filterByArtist
- artist="$1"
- mapfile -t choice < <(mpc search -f '[(%date%)\t][%album%]' artist "${artist}" |
- sort -h | uniq |
- fzf --prompt="$artist > " \
- --expect='f1,f3,enter' \
- --bind='Ctrl-A:select-all' |
- cut -f2)
- case "${choice[0]}" in
- 'f1') filterAllSongs ;;
- 'f3') filterPlaylist ;;
- 'enter') filterSongsFromAlbum "$artist" "${choice[1]}" ;;
- *) filterByArtist ;;
- esac
- }
-
- filterSongsFromAlbum() {
- local album artist choice
- [[ -z "$1" || -z "$2" ]] && die
- artist="$1"
- album="$2"
- mapfile -t choice < <(mpc search -f '%file%\t[[[%track% - ][%title%]]|%file%]' artist "${artist}" album "${album}" |
- fzf --prompt="$artist - $album > " \
- --multi \
- --with-nth='2..' \
- --delimiter='\t' \
- --expect='f1,f3,enter' \
- --bind='Ctrl-A:select-all' |
- cut -f1)
- case "${choice[0]}" in
- 'f1') filterAllSongs ;;
- 'f3') filterPlaylist ;;
- 'enter') printf '%s\n' "${choice[@]:1}" | playSongs ;;
- *) filterByAlbumFromArtist "$artist" ;;
- esac
- }
-
- filterPlaylist() {
- local choice
- current_song=$(mpc current -f "$track_format")
- mapfile -t choice < <(mpc playlist -f "%position%\t$track_format" |
- fzf --prompt='playlist > ' \
- --multi \
- ${current_song:+--header="now playing: ${current_song}"} \
- --delimiter='\t' \
- --with-nth='2..' \
- --expect='f1,f2,>,<,ctrl-d,enter' |
- cut -f1) || die
- case "${choice[0]}" in
- 'f1') filterAllSongs ;;
- 'f2') filterByArtist ;;
- '>') mpc -q next ; filterPlaylist ;;
- '<') mpc -q prev ; filterPlaylist ;;
- 'ctrl-d') [[ -n "${choice[1]}" ]] && mpc -q del "${choice[@]:1}" ; filterPlaylist ;;
- 'enter') [[ -n "${choice[1]}" ]] && mpc -q play "${choice[@]:1}" ; filterPlaylist ;;
- esac
- }
-
- playSongs() {
- mapfile -t songs
- (( "${#songs[@]}" > 0 )) || die
- printf '%s\n' "${songs[@]}" | mpc -q add
- index=$(mpc playlist | wc -l)
- (( ${#songs[@]} > 1 )) &&
- index=$(( index - ${#songs[@]} + 1))
- mpc -q play "$index"
- filterPlaylist
- }
-
- declare filter='filterAllSongs'
- while :; do
- case "$1" in
- -A|--all) filter='filterAllSongs' ; shift ;;
- -a|--artist) filter='filterByArtist' ; shift ;;
- -p|--playlist) filter='filterPlaylist' ; shift ;;
- -h|--help) usage ; exit ;;
- *) break
- esac
- done
-
- has -v fzf mpc || die
- isRunning mpd || [[ -n "$MPD_HOST" ]] || die "can't connect to mpd"
-
- $filter
|