#!/usr/bin/env bash shopt -s globstar # check for config files if [[ ! -f $HOME/.config/clerk/config ]] && [[ ! -f /etc/clerk ]]; then echo "Error: could not find configuration file \"$HOME/.config/clerk/config\"" echo "You can use the provided example configuration file (config.clerk), copy it to the above location and edit it to your needs." exit fi # read global config, if present if [[ -f /etc/clerk.conf ]]; then source /etc/clerk.conf fi # read local config file if [[ -f $HOME/.config/clerk/config ]]; then source $HOME/.config/clerk/config fi # check for scrobbler if [[ $scrobbler == mpdas ]]; then export scrobbler="mpdas -d" export scrobbler_kill="mpdas" elif [[ $scrobbler == mpdscribble ]]; then export scrobbler_kill="mpdscribble" fi fix_date_format() { # provided by Thorsten Wißmann: # https://github.com/t-wissmann/dotfiles/blob/master/menu/rofi-mpd.sh # reformats the date given in column $1 from format %c of locale LC_TIME=C # (see man strftime) to the format specified in argument $2 column indices # start with 1 column_index="$1" gawk -F $'\t' ' # parse a date which was formated using %c to unix time BEGIN { # generated by the following bash one-liner: # for i in {1..12} ; do LC_TIME=C date -d "1972-$i-01" +month2num[\"%b\"]\ =\ %_m ; done month2num["Jan"] = 1 month2num["Feb"] = 2 month2num["Mar"] = 3 month2num["Apr"] = 4 month2num["May"] = 5 month2num["Jun"] = 6 month2num["Jul"] = 7 month2num["Aug"] = 8 month2num["Sep"] = 9 month2num["Oct"] = 10 month2num["Nov"] = 11 month2num["Dec"] = 12 } function reformat_c_date(str) { monthname = gensub(/^([^ ]*)[ ]+([^ ]*)[ ]+([^ ]*)[ ]+([^ ]*)[ ]+([^ ]*)$/, "\\2", "g", str) monthnum = month2num[monthname] nicedate = gensub(/^([^ ]*)[ ]+([^ ]*)[ ]+([^ ]*)[ ]+([^ ]*)[ ]+([^ ]*)$/, "\\5 " monthnum " \\3 \\4", "g", str) nicedate = gensub(/:/, " ", "g", nicedate) return nicedate } { # modify the $column_index-th field $'"$1"' = strftime("'"$2"'", mktime(reformat_c_date($'"$1"'))) print $0 } ' } updateCache () { notify-send "clerk" "updating cache files" cd $HOME/.config/clerk rm -f *.cache mpc --format '[%mtime%\t%albumartist%|%artist%] — (%date%) — %album%' \ search filename '' \ | grep -v '^ — ' \ | grep -v ' — $' \ | uniq \ | fix_date_format 1 '%Y-%m-%d-%H:%M:%S' \ | sort -u \ | sort -nr \ | awk '{for (i=2; i $HOME/.config/clerk/latest.cache # | sed 's,^\([^\t]*\t[^\t]\{40\}\)[^\t]*,\1,' | column -o $'\t' -s $'\t' -t | uniq > $HOME/.config/clerk/latest.cache mpc --format '[%albumartist%|%artist%]\t(%date%) — %album%' \ search filename '' \ | grep -v '^ — ' \ | grep -v ' — $' \ | sort \ | uniq \ | column -o $'\t' -s $'\t' -t > $HOME/.config/clerk/albums.cache mpc --format '[[%title%\t[(by %artist%[ on %album%])]]|[%file%]]\t%file%' \ search filename '' \ | grep -v '^ — ' \ | grep -v ' — $' \ | uniq \ | sed 's,^\([^\t]\{40\}\)[^\t]*,\1…,' | column -o $'\t' -s $'\t' -t \ > $HOME/.config/clerk/tracks.cache notify-send "clerk" "finished updating cache files" } date=$(mpc stats | grep 'DB Updated: ') file="$HOME/.config/clerk/.lastupdate" if [ "$(< $file)" = "$date" ] && [ -f "$file" ] ; then : else updateCache echo "${date}" > "${file}" fi # Use GNU coreutils on OSX sed=$([[ "$OSTYPE" == "darwin"* ]] && echo 'gsed' || echo 'sed') shuf=$([[ "$OSTYPE" == "darwin"* ]] && echo 'gshuf' || echo 'shuf') tac=$([[ "$OSTYPE" == "darwin"* ]] && echo 'gtac' || echo 'tac') # main Menu dplayPrompt () { if [[ -z $(mpc status | grep "/") ]]; then song="No Song is playing" else song=$(mpc current) fi menu=("< Exit" "---" "1 [ Browse Library ]>" "2 [ Current Artist ]>" "3 [ Current Queue ]>" "---" "4 [ Options ]>" "5 [ Ratings ]>") menu=$(printf "%s\n" "${menu[@]}" | dmenu_t -dmenu -lines 17 -mesg "${toggle}: Toggle Playback, ${prev}: Prev, ${next}: Next, ${stop}: Stop" -auto-select -p "Now Playing: ${song} > ") val=$? if [[ $val -eq 10 ]]; then mpc toggle dplayPrompt elif [[ $val -eq 11 ]]; then mpc prev dplayPrompt elif [[ $val -eq 12 ]]; then mpc next dplayPrompt elif [[ $val -eq 13 ]]; then mpc stop dplayPrompt fi if [[ "$menu" == "< Exit" ]]; then exit elif [[ "$menu" == "2 "* ]]; then currentMenu elif [[ "$menu" == "3 "* ]]; then dplayQueue elif [[ "$menu" == "1 "* ]]; then browseLibPrompt elif [[ "$menu" == "4 "* ]]; then dplayOptionsPrompt elif [[ "$menu" == "5 "* ]]; then ratingPrompt elif [[ -z "$menu" ]]; then exit fi } # start/stop scrobbler. locally or remote lastFM () { # Some Variables to clean up the code if [[ $ssh_lastfm == 1 ]]; then mpds_check="$(ssh $ssh_host -q -t "pgrep $scrobbler_kill")" if [ -n "$mpds_check" ]; then ssh $ssh_host -q -t "killall $scrobbler_kill" && notify-send "MPD" "LastFM Scrobbling Disabled" else ssh $ssh_host -q "$scrobbler" && notify-send "MPD" "LastFM Scrobbling Enabled" fi else if pgrep $scrobbler_kill then killall $scrobbler_kill && notify-send "MPD" "LastFM Scrobbling Disabled" else $scrobbler && notify-send "MPD" "LastFM Scrobbling Enabled" fi fi } lastFMCheck () { # Some Variables to clean up the code if ((ssh_lastfm)); then mpds_check="$(ssh $ssh_host -q -t "pgrep $scrobbler_kill")" if [ -n "$mpds_check" ]; then echo "lastfm: off" else echo "lastfm: on" fi else if pgrep $scrobbler_kill then echo "lastfm: on" else echo "lastfm: off" fi fi } currentMenu () { getAlbums() { mpc search -f '(%date%)\t%album%' artist "$(mpc current -f '%artist%')" | uniq | sed 's,^\([^\t\t]\{40\}\)[^\t]*,\1…,' | column -o $'\t' -s $'\t' -t } getTracks() { mpc search -f '%track%\t%title%' artist "$(mpc current -f '%artist%')" | sed 's,^\([^\t\t]\{40\}\)[^\t]*,\1…,' | column -o $'\t' -s $'\t' -t } if [[ -z $(mpc current) ]]; then menu_temp=$(echo -e "< Return" | dmenu_t -dmenu -p "No Music is playing") else menu_temp=$((echo -e "< Return\n---"; getAlbums; echo -e "---"; getTracks) | dmenu_t -custom-kb-1 "${add}" -custom-kb-2 "${insert}" -custom-kb-3 "${replace}" -dmenu -format "f¬s" -filter "$filter" -select "$entry" -mesg "${add}: Add, ${insert}: Insert, ${replace}: Replace" -p "Other Music by $(mpc current -f '%artist%') > ") # for some reason directly defining $val wasnt working. Using a # temporary variable instead. tempval=$? val=$tempval menu="${menu_temp#*¬}" albumartist=$(mpc current -f '%albumartist%') artist=$(mpc current -f '%artist%') unset filter export filter="${menu_temp%¬*}" if [[ $menu == "< Return" ]]; then dplayPrompt fi if [[ $(echo "${menu}" | awk -F '\t' '{ print $1 }') == "("* ]]; then item="Album" elif [[ $(echo "${menu}" | awk -F '\t' '{ print $1 }') != *"(" ]]; then item="Song" fi # checking for exit codes. if [[ $item == "Album" ]]; then if [[ $val -eq 11 ]]; then mpc find album "$(echo -n "${menu}" | awk -F '\t' '{ print $2 }' | sed -e 's/[[:space:]]*$//')" artist "${artist}" | mpc insert entry="$menu" elif [[ $val -eq 0 || $val -eq 12 ]]; then mpc clear mpc find album "$(echo -n "${menu}" | awk -F '\t' '{ print $2 }' | sed -e 's/[[:space:]]*$//')" artist "${artist}" | mpc add mpc play entry="$menu" elif [[ $val -eq 10 ]]; then mpc find album "$(echo -n "${menu}" | awk -F '\t' '{ print $2 }' | sed -e 's/[[:space:]]*$//')" artist "${artist}" | mpc add entry="$menu" elif [[ $val -eq 1 ]]; then exit fi currentMenu elif [[ $item == "Song" ]]; then if [[ $val -eq 11 ]]; then mpc find track "$(echo -n "${menu}" | awk -F '\t' '{ print $1 }' | sed -e 's/[[:space:]]*$//')" title "$(echo -n "$menu" | awk -F '\t' '{ print $2 }' | sed -e 's/[[:space:]]*$//')" artist "${artist}" | mpc insert title="$(echo "$menu" | awk -F '\t' '{ print $2 }')" entry="$menu" elif [[ $val -eq 12 ]]; then mpc clear mpc find track "$(echo -n "${menu}" | awk -F '\t' '{ print $1 }' | sed -e 's/[[:space:]]*$//')" title "$(echo -n "$menu" | awk -F '\t' '{ print $2 }' | sed -e 's/[[:space:]]*$//')" artist "${artist}" | mpc add mpc play entry="$menu" elif [[ $val -eq 0 || $val -eq 10 ]]; then mpc find track "$(echo -n "${menu}" | awk -F '\t' '{ print $1 }' | sed -e 's/[[:space:]]*$//')" title "$(echo -n "$menu" | awk -F '\t' '{ print $2 }' | sed -e 's/[[:space:]]*$//')" artist "${artist}" | mpc add entry="$menu" elif [[ $val -eq 1 ]]; then exit fi currentMenu elif [[ -z "$menu" ]]; then exit fi fi } # rating menu ratingPrompt () { menu=("< Return" "---" "1 Rate current Album" "2 Load Rated Albums" "3 Load Random Rated Album" "---" "4 Rate current Track" "5 Load Rated Tracks" "6 Load Random Rated Tracks" "---" "7 Love current Song on LastFM" "---" "0 Backup/Restore") prompt() { printf "%s\n" "$@" | dmenu_t -p "Ratings > " } case "$(prompt "${menu[@]}")" in 1*) rateAlbum ;; 2*) loadRatedAlbums ;; 3*) loadRandomRating ;; 4*) rateTrack ;; 5*) loadRatedTracks ;; 6*) loadRandomRatedTracks ;; 7*) loveLast ;; 0*) backupPrompt ;; \<*) dplayPrompt ;; *) exit esac } # create rating json files from mpd sticker database and vice versa backupPrompt () { menu=("< Return" "---" "1 Backup Album Ratings to File" "2 Backup Track Ratings to File" "---" "3 Restore Ratings from File") prompt() { printf "%s\n" "$@" | dmenu_t -p "Backup/Restore > " } case "$(prompt "${menu[@]}")" in 1*) clerk_helper importalbumratings & ;; 2*) clerk_helper importtrackratings & ;; 3*) clerk_helper sendstickers & ;; \<*) ratingPrompt ;; *) exit esac } # if mpdas is used use mpc to love track on last.fm. otherwise try # lastfm-mpd-cli loveLast () { if [[ "$scrobbler" == "mpdscribble" ]]; then lastfm-mpd-cli love > /dev/null && notify-send "MPD" "Loved $(mpc current -f '%title%') on LastFM" && exit elif [[ "$scrobbler" == "mpdas" ]]; then mpc sendmessage mpdas love fi } infoPrompt () { menu=("0 Return to Main Menu" "---" "1 Artist Info" "2 Album Info" "3 Current Track Lyrics" "4 Current Track Tags") prompt() { printf "%s\n" "$@" | dmenu_t -p "MPD Menu > " } case "$(prompt "${menu[@]}")" in # 1*) surfraw yubnub allmusic $(mpc current -f %artist%) ;; 1*) artistinfo ;; 2*) surfraw yubnub allmusic $(mpc current -f %album%) && exit;; # 3*) surfraw yubnub google $(mpc current -f %title%) $(mpc current -f %artist%) lyrics ;; 3*) lyrics ;; 4*) currentTag ;; \<*) dplayPrompt ;; *) exit esac } currentTag () { declare -i seen=0 while read line do seen=1 if [[ "$line" == "0 Return to Main Menu" ]]; then dplayPrompt elif [[ "$line" == "Show all Tags" ]]; then readComments elif [[ "$line" == "" ]]; then return fi done < <(echo -e "0 Return to Main Menu\n---\nShow all Tags\n---\n$(mpc current --format "Artist: %artist%\nAlbum: %album%\nDate: %date%\nTrack: %track%\nTitle: %title%")" | dmenu_t -p 'Current Song > ') if [[ $seen = 0 ]] then exit fi } # read all tags from file. Note that mpd can only read vorbiscomment properly readComments () { declare -i seen=0 while read line do seen=1 if [[ "$line" == "0 Return to Main Menu" ]]; then dplayPrompt elif [[ "$line" == "Show Tags" ]]; then currentTag elif [[ "$line" == "" ]]; then return fi done < <(echo -e "0 Return to Main Menu\n---\nShow Tags\n---\n$(mpc current --format '%file%' | clerk_helper readcomments)" | dmenu_t -p 'Current Song > ') if [[ $seen = 0 ]] then exit fi } # Messy options menu. dplayOptionsPrompt () { # define variables to be used in menu export status="$(mpc status)" single=$(echo "$status" | tail -1 | awk -F ':' '{ print $5 }' | cut -d ' ' -f 2) random=$(echo "$status" | tail -1 | awk -F ':' '{ print $4 }' | cut -d ' ' -f 2) consume=$(echo "$status" | tail -1 | awk -F ':' '{ print $6 }' | cut -d ' ' -f 2) repeat=$(echo "$status" | tail -1 | awk -F ':' '{ print $3 }' | cut -d ' ' -f 2) if [[ -a /tmp/mpd-sima.pid ]]; then export sima=on else export sima=off fi if [[ "$ssh_lastfm" == "1" ]]; then mpds_check="$(ssh $ssh_host -q -t "pgrep $scrobbler_kill")" if [ -n "$mpds_check" ]; then export scrobble=on else export scrobble=off fi else if pgrep $scrobbler_kill then export scrobble=on else export scrobble=off fi fi export rgain="$(mpc replaygain | cut -d ' ' -f 2)" replayGain () { if [[ $(mpc replaygain | cut -d ' ' -f 2) == album ]]; then mpc replaygain track > /dev/null && export rgain="track" elif [[ $(mpc replaygain | cut -d ' ' -f 2) == track ]]; then mpc replaygain off > /dev/null && export rgain="off" elif [[ $(mpc replaygain | cut -d ' ' -f 2) == off ]]; then mpc replaygain album > /dev/null && export rgain="album" fi } menu=("< Return" "---" "1 Random: $(echo $random)" "2 Repeat: $(echo $repeat)" "3 Single Mode: $(echo $single)" "4 Consume Mode: $(echo $consume)" "5 Replaygain: $(echo $rgain)" "6 Scrobbling: $(echo $scrobble)" "7 Similar Artists Mode: $(echo $sima)" "---" "8 Set Crossfade $(mpc crossfade | cut -d ':' -f2)" "9 Manage Outputs" "0 Number of Random Songs: $(echo $value)") prompt() { printf "%s\n" "$@" | dmenu_t -auto-select -p "MPD Options > " } case "$(prompt "${menu[@]}")" in 1*) mpc random && dplayOptionsPrompt ;; 2*) mpc repeat && dplayOptionsPrompt ;; 3*) mpc single && dplayOptionsPrompt ;; 4*) mpc consume && dplayOptionsPrompt ;; 5*) replayGain && dplayOptionsPrompt ;; 6*) lastFM && dplayOptionsPrompt ;; 7*) mpdSima && dplayOptionsPrompt ;; 8*) crossfadePrompt ;; 9*) outputPrompt ;; 0*) optionRandomPrompt ;; \<*) dplayPrompt ;; *) exit esac } # toggle similar artist playback mpdSima () { if [[ -a /tmp/mpd-sima.pid ]]; then kill $(cat /tmp/mpd-sima.pid) sleep 1 else mpd-sima -d -p /tmp/mpd-sima.pid sleep 1 fi } # function to change number of random songs in config file optionRandomPrompt() { number="$(echo -e " " | dmenu_t -p 'Set No. of Songs for random Songs > ')" $sed -i "s/value=.*/value="$number"/" $HOME/.config/clerk/config export value="$number" dplayOptionsPrompt } crossfadePrompt () { menu=$(echo -e "< Return\n---\n0\n1\n2\n3\n4\n5" | dmenu_t -p "Crossfade") if [[ $menu == "< Return" ]]; then dplayOptionsPrompt else mpc crossfade ${menu}; dplayOptionsPrompt fi } # read list of available podcasts. Not using mpd playlists, because mpd does # not support custom names for urls. format of podcast in file is "Name \ URL" loadRSS () { podcast=$(echo -e "< Return\n---\n$(cat $HOME/.config/clerk/podcasts | cut -d '\' -f1)" | dmenu_t -p "Choose Podcast > ") if [[ $podcast == "< Return" ]]; then dplayQueue else mpc clear mpc load $(grep "$podcast" $HOME/.config/clerk/podcasts | cut -d '\' -f2) episode=$(mpc playlist --format "%position% — %artist% — %title%" | dmenu_t -p "Choose Episode > ") POS=$(echo "$episode" | awk -F " — " '{ print $1 }') mpc play "$POS" fi } # suspend current playlist. playlist, song id and play-position are saved to # $HOME/.config/clerk/suspend suspendPlaylist () { playing=$(! mpc status | grep 'playing\|paused') time=$(mpc status | $sed '2!d;s;/.:.*;;;s;.* ;;') position=$(mpc current --format '%position%') if [[ -z "$playing" ]]; then notify-send "clerk" "mpd is not playing, no state to suspend" else mpc rm suspended mpc save suspended rm -f $HOME/.config/clerk/suspend echo "pos="$position"" >> $HOME/.config/clerk/suspend echo "time="$time"" >> $HOME/.config/clerk/suspend if [[ "$stop_after_suspend" == yes ]]; then mpc stop else echo " " fi notify-send "Clerk" "Playlist suspended" dplayQueue fi } # read $HOME/.config/clerk/suspend and restore playlist. Then start playing # from same position that was saved in suspend file resumePlaylist () { http=$(! mpc current --format %file% | grep 'http://') source $HOME/.config/clerk/suspend mpc clear mpc load suspended mpc play $pos mpc toggle sleep 2 mpc seek "$time" mpc toggle notify-send "Clerk" "Resumed last-suspended Playlist" dplayQueue } # Play or delete items from current Queue dplayQueue () { while true; do re='^[0-9]+$' if [[ "$POS" =~ $re ]]; then POS=$(( $POS + 6 )) else POS=0 fi select="-selected-row $POS" help_text=$(echo -e "${delete}: Delete - ${crop}: Crop - ${clear}: Clear - ${rate}: Rate\n${moveup}: Move Up - ${movedown}: Move Down - ${suspend}: Suspend - ${resume}: Resume" | column -s '-' -t) line1=$(echo "${help_text}" | head -1) line2=$(echo "${help_text}" | tail -1) HELP="${line1} ${line2}" songs () { mpc --format '%position%\t\t%track%\t%title%\t(by %artist% on %album% (%date%))' playlist \ | sed 's,^\([^\t]\{40\}\)[^\t]*,\1…,' \ | column -o ' ' -s $'\t' -t } position () { current=$(mpc current -f '%position%') echo $(( $current +5 )) } TRACKDISPLAY=$(echo -e "< Return\n---\nLoad Playlist\nLoad RSS\nSave Playlist\n---\n$(songs)" | dmenu_t -kb-custom-1 "${delete}" -kb-custom-2 "${rate}" -kb-custom-4 "${crop}" -kb-custom-5 "${clear}" -kb-custom-6 "${moveup}" -kb-custom-7 "${movedown}" -kb-custom-8 "${suspend}" -kb-custom-9 "${resume}" -dmenu $(echo "${select}") -u $(position) -mesg "${HELP}" -p "Current Queue > ") tempval=$? val=$tempval POS=$(echo "${TRACKDISPLAY}" | awk '{ print $1 }') if [[ $val -eq 10 ]]; then mpc del $POS; POS=$(( $POS - 1)); dplayQueue elif [[ $val -eq 1 ]]; then exit elif [[ $val -eq 13 ]]; then mpc play $POS; mpc crop elif [[ $val -eq 16 ]]; then mpc mv $POS $(echo $(( $POS + 1 ))) POS=$POS; elif [[ $val -eq 15 ]]; then mpc mv $POS $(echo $(( $POS - 1 ))) POS=$(( $POS - 2)); elif [[ $val -eq 17 ]]; then suspendPlaylist elif [[ $val -eq 18 ]]; then resumePlaylist elif [[ $val -eq 12 ]]; then dplayQueueSave elif [[ $val -eq 14 ]]; then if [[ $TRACKDISPLAY == *""* ]]; then mpc clear fi elif [[ $val -eq 0 ]]; then if [[ $TRACKDISPLAY == "< Return" ]]; then dplayPrompt elif [[ $TRACKDISPLAY == "Load RSS" ]]; then loadRSS elif [[ $TRACKDISPLAY == "Load Playlist" ]]; then dplayQueueLoad; elif [[ $TRACKDISPLAY == "Save Playlist" ]]; then dplayQueueSave; else mpc play $POS; fi elif [[ $val -eq 11 ]]; then filename=$(mpc playlist --format '%position%\t%file%' | grep "^${POS}" | awk -F '\t' '{ print $2 }') info=$(mpc --format '%artist%\t%album%\t%date%\t%track%\t%title%' search filename "${filename}") echo "${info}" ARTIST=$(echo "${info}" \ | awk -F '\t' '{ print $1 }') ALBUM=$(echo "${info}" \ | awk -F '\t' '{ print $2 }') DATE=$(echo "${info}" \ | awk -F '\t' '{ print $3 }') TRACK=$(echo "${info}" \ | awk -F '\t' '{ print $4 }') TITLE=$(echo "${info}" \ | awk -F '\t' '{ print $5 }') rateartist="${ARTIST}" ratealbum="${ALBUM}" ratetrack="${TRACK}" ratetitle="${TITLE}" rateTrack elif [[ $TRACKDISPLAY == "< Return" ]]; then dplayQueue fi done } # show all mpd playlists and load them to queue dplayQueueLoad () { playlist=$(echo -e "< Return\n---\n$(mpc lsplaylists)" | dmenu_t -p "Load Playlist > ") if [[ "$playlist" == "< Return" ]]; then dplayQueue else mpc clear mpc load "$playlist" && dplayQueue fi } # save current playlist to playlist file. dplayQueueSave () { while read playlists do if [[ "$playlists" == "< Return" ]]; then dplayQueue elif [[ "$playlists" == "Save new Playlist" ]]; then playlist=$(echo "" | dmenu_t -p "Type Name for Playlist > ") if [[ "$playlist" == "" ]]; then dplayQueueSave else mpc save "$playlist" dplayQueue fi else playlist=$(echo -e "0 Return to Playlist Menu\n---\nYes\nNo" | dmenu_t -p "Overwrite Playlist? > ") if [[ "$playlist" == "Yes" ]]; then mpc rm "$playlists" mpc save "$playlists" elif [[ "$playlist" == "No" ]]; then playlist=$(echo "" | dmenu_t -p "Type Name for Playlist > ") if [[ "$playlist" == "" ]]; then dplayQueue else mpc save "$playlist" dplayQueue fi fi fi done < <(echo -e "< Return\n---\nSave new Playlist\n---\n$(mpc lsplaylists)" | dmenu_t -p "Choose Playlist > ") exit } # enable/disable outputs outputPrompt () { menu="$(echo -e "0 Return to Options Menu\n---\n$(mpc outputs)" \ | dmenu_t -p "Outputs > ")"; if [[ "$menu" == "0 Return to Options Menu" ]] then dplayOptionsPrompt; elif [[ "$menu" == "" ]]; then exit else mpc toggleoutput $(echo "$menu" \ | awk '{print $2}'); notify-send "MPD" "$(echo "$menu" \ | $sed -e 's/enabled$/disabled/;ta;s/disabled$/enabled/;:a;')"; outputPrompt fi } # rate any album rateAlbum () { rating="$(seq 10 | dmenu_t -p "Select Album Rating: > ")" if [[ $rating == "" ]]; then exit else # check if rateartist was defined, if it wasn't use currently playing # track for rating, otherwise use what was delivered in the rate* # variables. if [[ -z "$rateartist" ]]; then artist=$(mpc current -f '%artist%') album=$(mpc current -f '%album%') date=$(mpc current -f '%date%') if [[ -n $(mpc find track "1" albumartist "${artist}" album "${album}" date "${date}") ]]; then track="1" else track="01" fi disc=$(mpc current -f '%disc%') export disc=${disc} export track=${track} clerk_helper ratealbum "${artist}" "${album}" "${date}" "${rating}" notify-send "clerk" "rated ${artist} - ${album} with ${rating}" else export disc=${disc} export track=${track} clerk_helper ratealbum "${rateartist}" "${ratealbum}" "${ratedate}" "${rating}" notify-send "clerk" "rated ${rateartist} - ${ratealbum} with ${rating}" fi fi } rateTrack () { rating="$(echo -e "< Return\n---\n$(seq 10)" | dmenu_t -p "Select Track Rating: > ")" if [[ $rating == "" ]]; then exit elif [[ $rating == "< Return" ]]; then dplayQueue else if [[ -z "$rateartist" ]]; then export rating=${rating} rateartist=$(mpc current -f '%artist%') ratetitle=$(mpc current -f '%title%') ratetrack=$(mpc current -f '%track%') ratealbum=$(mpc current -f '%album%') clerk_helper ratetrack "${rateartist}" "${ratealbum}" "${ratetrack}" "${ratetitle}" "${rating}" notify-send "clerk" "rated $(mpc current) with $(echo ${rating})" else clerk_helper ratetrack "${rateartist}" "${ratealbum}" "${ratetrack}" "${ratetitle}" "${rating}" notify-send "clerk" "rated ${rateartist} - ${ratetitle} with $(echo ${rating})" fi fi } # function to instantly rate a track without a submenu. rating is defined on # commandline instantRateTrack () { rateartist=$(mpc current -f '%artist%') ratetitle=$(mpc current -f '%title%') ratetrack=$(mpc current -f '%track%') ratealbum=$(mpc current -f '%album%') export rating=$1 clerk_helper ratetrack "${rateartist}" "${ratealbum}" "${ratetrack}" "${ratetitle}" "${rating}" notify-send "clerk" "rated ${rateartist} - ${ratetitle} with $(echo ${rating})" } # load rated albums with minimum rating of xx loadRatedAlbums () { rating="$(seq 10 | dmenu_t -p "Minimum Rating > ")" if [[ $rating == "" ]]; then exit else albums="$(while read -a line; do dirname "${line[*]}"; done <<< "$(mpc sticker "" find albumrating \ | grep -E "albumrating=$rating")" \ | $sed 's/\/\CD.*//g' \ | sort \ | uniq \ | dmenu_t -p "Choose Album > ")" if [[ $albums == "" ]]; then exit else mpc clear; mpc add "$albums"; mpc play fi fi } loadRatedTracks () { rating="$(seq 10 | dmenu_t -p "Rating > ")" if [ rating = "" ]; then exit else cd $HOME/.config/clerk mpc clear songs="$(mpc sticker "" find rating | awk -F 'rating=' '{ print $2 }')" echo "$songs" | mpc add mpc play fi } loadRandomRatedTracks () { number="$(echo " " | dmenu_t -p "Number of Songs > " | xargs echo)" rating="$(seq 10 | dmenu_t -p "Minimum Rating > ")" if [ rating = "" ]; then exit else cd $HOME/.config/clerk mpc clear songs="$(mpc sticker "" find rating \ | grep -E "rating=$rating|rating=$(echo $(( $rating + 1 )))|rating=$(echo $(( $rating + 2 )))|rating=$(echo $(( $rating + 3 )))|rating=$(echo $(( $rating + 4 )))" \ | awk -F ':' '{ print $1 }')" echo "$songs" \ | $shuf -n $number \ | mpc add mpc play rm -f /tmp/clerk_tracklist fi } loadRandomRating () { rating="$(seq 10 | dmenu_t -p "Minimum Rating > ")" if [ rating = "" ]; then exit else album="$(while read -a line; do dirname "${line[*]}"; done <<< "$(mpc sticker "" find albumrating \ | grep -E "albumrating=$rating|albumrating=$(echo $(( $rating+1 )))|albumrating=$(echo $(( $rating+2 )))|albumrating=$(echo $(( $rating+3 )))|albumrating=$(echo $(( $rating+4 )))|albumrating=$(echo $(( $rating+5 )))|albumrating=$(echo $(( $rating+6 )))")" \ | $sed 's/\/\CD.*//g' \ | $shuf -n1)" mpc clear; mpc add "$album"; mpc play fi } # load random album. Make sure to make each sub item random. this way each # artist has equal chances of being played, no matter how many albums it has. playRandomAlbum () { mpc clear > /dev/null artist="$(mpc list "albumartist" | $shuf -n 1)" album="$(mpc list album "albumartist" "$artist" | $shuf -n 1)" mpc findadd album "$album" "albumartist" "$artist"; mpc play > /dev/null } # same for tracks, no artist should be preferred because it has more tracks. playRandomTracks () { mpc clear > /dev/null artist="$(mpc list "$random_artist" | $shuf -n 1)" album="$(mpc list album "$random_artist" "$artist" | $shuf -n 1)" title="$(mpc list title album "$album" "$random_artist" "$artist" | $shuf -n 1)" mpc findadd album "$album" "$random_artist" "$artist" title "$title"; mpc play > /dev/null n=0; while (( n++ < $value -1 )); do artist="$(mpc list "$random_artist" | $shuf -n 1)" album="$(mpc list album "$random_artist" "$artist" | $shuf -n 1)" title="$(mpc list title album "$album" "$random_artist" "$artist" | $shuf -n 1)" mpc findadd album "$album" "$random_artist" "$artist" title "$title" done mpc play > /dev/null exit } addLastMod() { help_text=$(echo -e "${add}: Add - ${insert}: Insert - ${replace}: Replace (Default)\n${rate}: Rate - ${addplay}: Add + Play - ${insertplay}: Insert + Play" | column -s '-' -t) line1=$(echo "${help_text}" | head -1) line2=$(echo "${help_text}" | tail -1) HELP="${line1} ${line2}" #HELP="${add}: Add, ${insert}: Insert, ${replace}: Replace (Default), ${rate}: Rate #${addplay}: Add & Play, ${insertplay}: Insert & Play" TRACK_TEMP=$((echo -e "0 Return to Browse Menu\n---"; cat $HOME/.config/clerk/latest.cache) \ | dmenu_t -custom-kb-1 "${add}" -custom-kb-2 "${insert}" -custom-kb-3 "${replace}" -custom-kb-8 "${rate}" -custom-kb-4 "${addplay}" -custom-kb-5 "${insertplay}" -dmenu -select "$entry" -filter "$filter" -format "f¬s" -mesg "${HELP}" -p "Choose Album > ") val=$? TRACK="${TRACK_TEMP#*¬}" unset filter export filter="${TRACK_TEMP%¬*}" if [[ "$TRACK" == "0 Return to Browse Menu" ]]; then browseLibPrompt elif [[ -z "$TRACK" ]]; then exit elif [[ "$TRACK" == "${add}: Add, ${insert}: Insert, ${replace}: Replace (Default)" ]]; then addLastMod else artist=$(echo -en "$TRACK" \ | awk -F '\t' '{ print $1 }' \ | sed -e 's/[[:space:]]*$//') group2=$(echo -en "$TRACK" \ | awk -F '\t' '{ print $2 }' \ | sed -e 's/[[:space:]]*$//') album=$(echo "$group2" \ | awk -F " — " '{print $2}') date=$(echo "$group2" \ | awk -F " — " '{print $1}' \ | awk '{print substr($0, 2, length($0) - 2)}') echo -e "${TRACK}\nartist: ${artist}\nalbum: ${album}\ndate: ${date}" if [[ $val -eq 11 ]]; then mpc search date "$date" album "$album" albumartist "$artist" | mpc insert entry="$TRACK" elif [[ $val -eq 0 || $val -eq 12 ]]; then echo "return code is 13" mpc clear; mpc searchadd date "$date" album "$album" albumartist "$artist"; mpc play entry="$TRACK" elif [[ $val -eq 10 ]]; then mpc searchadd date "$date" album "$album" albumartist "$artist"; elif [[ $val -eq 13 ]]; then mpc findadd date "$date" album "$album" albumartist "$artist" mpc searchplay "${album}" elif [[ $val -eq 17 ]]; then if [[ -n $(mpc find -f '%disc%' albumartist "${artist}" album "${album}" date "${date}") ]]; then disc=$(mpc find -f '%disc%' albumartist "${artist}" album "${album}" date "${date}" | head -1) else disc="" fi if [[ -n $(mpc find track "1" albumartist "${artist}" album "${album}" date "${date}") ]]; then track="1" else track="01" fi disc=${disc} track=${track} rateartist="${artist}" ratealbum="${album}" ratedate="${date}" rateAlbum entry="$TRACK" elif [[ $val -eq 14 ]]; then mpc clear; mpc findadd date "$date" album "$album" albumartist "$artist"; mpc searchplay "${album}" entry="$TRACK" elif [[ $val -eq 1 ]]; then exit fi addLastMod fi } AddAlbumTags() { help_text=$(echo -e "${add}: Add - ${insert}: Insert - ${replace}: Replace (Default)\n${rate}: Rate - ${addplay}: Add + Play - ${insertplay}: Insert + Play" | column -s '-' -t) line1=$(echo "${help_text}" | head -1) line2=$(echo "${help_text}" | tail -1) HELP="${line1} ${line2}" TRACK_TEMP=$((echo -e "0 Return to Browse Menu\n---"; cat $HOME/.config/clerk/albums.cache) \ | dmenu_t -custom-kb-1 "${add}" -custom-kb-2 "${insert}" -custom-kb-3 "${replace}" -custom-kb-8 "${rate}" -custom-kb-4 "${addplay}" -custom-kb-5 "${insertplay}" -dmenu -filter "$filter" -select "$entry" -format "f¬s" -mesg "${HELP}" -p "Choose Album > ") val=$? TRACK="${TRACK_TEMP#*¬}" unset filter export filter="${TRACK_TEMP%¬*}" if [[ "$TRACK" == "0 Return to Browse Menu" ]]; then browseLibPrompt elif [[ -z "$TRACK" ]]; then exit elif [[ "$TRACK" == "${add}: Add, ${insert}: Insert, ${replace}: Replace (Default), ${rate}: Rate" ]]; then unset line AddAlbumTags else artist=$(echo -en "$TRACK" \ | awk -F '\t' '{print $1}' \ | sed -e 's/[[:space:]]*$//') group2=$(echo -en "$TRACK" \ | awk -F '\t' '{print $2}' \ | sed -e 's/[[:space:]]*$//') album=$(echo "$group2" \ | awk -F " — " '{print $2}') date=$(echo "$group2" \ | awk -F " — " '{print $1}' \ | awk '{print substr($0, 2, length($0) - 2)}') echo -e "artist: ${artist}\ndate: ${date}\nalbum: ${album}" if [[ $val -eq 11 ]]; then mpc find date "$date" album "$album" albumartist "$artist" | mpc insert entry="$TRACK" elif [[ $val -eq 0 || $val -eq 12 ]]; then mpc clear; mpc findadd date "$date" album "$album" albumartist "$artist"; mpc play entry="$TRACK" elif [[ $val -eq 17 ]]; then if [[ -n $(mpc find -f '%disc%' albumartist "${artist}" album "${album}" date "${date}") ]]; then disc=$(mpc find -f '%disc%' albumartist "${artist}" album "${album}" date "${date}" | head -1) else disc="" fi if [[ -n $(mpc find track "1" albumartist "${artist}" album "${album}" date "${date}") ]]; then track="1" else track="01" fi disc=${disc} track=${track} rateartist="${artist}" ratealbum="${album}" ratedate="${date}" rateAlbum entry="$TRACK" elif [[ $val -eq 10 ]]; then mpc searchadd date "$date" album "$album" albumartist "$artist"; entry="$TRACK" elif [[ $val -eq 14 ]]; then mpc findadd date "$date" album "$album" albumartist "$artist"; mpc searchplay "${album}" elif [[ $val -eq 15 ]]; then mpc clear; mpc findadd date "$date" album "$album" albumartist "$artist"; mpc searchplay "${album}" elif [[ $val -eq 1 ]]; then exit fi AddAlbumTags fi } AddTrackTags() { help_text=$(echo -e "${add}: Add (Default) - ${insert}: Insert - ${replace}: Replace \ \n${rate}: Rate - ${addplay}: Add + Play - ${insertplay}: Insert + Play" \ | column -s '-' -t) line1=$(echo "${help_text}" | head -1) line2=$(echo "${help_text}" | tail -1) HELP="${line1} ${line2}" TRACK_TEMP=$((echo -e "0 Return to Browse Menu\n---"; cat $HOME/.config/clerk/tracks.cache) \ | dmenu_t -custom-kb-1 "${add}" -custom-kb-2 "${insert}" -custom-kb-3 "${replace}" -custom-kb-8 "${rate}" -custom-kb-4 "${addplay}" -custom-kb-5 "${insertplay}" -dmenu -filter "$filter" -select "$entry" -format "f¬s" -mesg "${HELP}" -p "Choose Track > ") val=$? TRACK="${TRACK_TEMP#*¬}" unset filter export filter="$(echo ${TRACK_TEMP} | awk -F '¬' '{ print $1 }')" if [[ "$TRACK" == "0 Return to Browse Menu" ]] then browseLibPrompt elif [[ -z "$TRACK" ]]; then exit elif [[ "$TRACK" == "${add}: Add | ${insert}: Insert | ${replace}: Replace | ${rate}: Rate" ]]; then AddTrackTags else filename=$(echo "$TRACK" | awk -F "\t" '{print $3}') echo -e "artist: ${artist}\nalbum: ${album}\ntitle: ${title}\ntrack: ${track}\ndate: ${date}\ngroup1: ${group1}\ngroup2: ${group2}" if [[ $val -eq 11 ]]; then mpc insert "${filename}" entry="$TRACK" elif [[ $val -eq 12 ]]; then mpc clear; mpc add "${filename}"; mpc play entry="$TRACK" elif [[ $val -eq 0 || $val -eq 10 ]]; then mpc add "${filename}" entry="$TRACK" elif [[ $val -eq 13 ]]; then mpc add "${filename}" mpc searchplay "${title}" entry="$TRACK" elif [[ $val -eq 14 ]]; then mpc insert "${filename}" mpc searchplay "${title}" entry="$TRACK" elif [[ $val -eq 17 ]]; then info=$(mpc search --format '%artist%\t%album%\t%date%\t%track%\t%title%' filename "${filename}") artist="$(echo "$info" \ | awk -F '\t' '{ print $1 }')" album="$(echo "$info" \ | awk -F '\t' '{ print $2 }')" date="$(echo "$info" \ | awk -F '\t' '{ print $3 }')" track="$(echo "$info" \ | awk -F '\t' '{ print $4 }')" title="$(echo "$info" \ | awk -F '\t' '{ print $5 }')" echo "${artist} ${album} ${date} ${track} ${title}" rateartist="${artist}" ratealbum="${album}" ratetrack="${track}" ratetitle="${title}" rateTrack entry="$TRACK" elif [[ $val -eq 1 ]]; then exit fi AddTrackTags fi } browseLibPrompt() { menu=("< Return" "---" "1 Choose Albums" "2 Choose Track" "3 Browse latest additions" "---" "4 Play Random Album" "5 Play Random Tracks" "---" "6 Update Album/Track Cache") prompt() { printf "%s\n" "$@" | dmenu_t -auto-select -p "Library Menu > " } case "$(prompt "${menu[@]}")" in 1*) AddAlbumTags ;; 2*) AddTrackTags ;; 6*) updateCache && browseLibPrompt ;; \<*) dplayPrompt ;; 3*) addLastMod ;; 4*) playRandomAlbum ;; 5*) playRandomTracks ;; *) exit esac } saveAlbumToPlaylist() { declare -i seen=0 while read TRACK do seen=1 if [[ "$TRACK" == "0 Return to Main Menu" ]] then dplayPrompt else artist=$(echo -en "$TRACK" \ | awk -F '\t' '{ print $1 }' \ | sed -e 's/[[:space:]]*$//') group2=$(echo -en "$TRACK" \ | awk -F '\t' '{ print $2 }' \ | sed -e 's/[[:space:]]*$//') album=$(echo "$group2" \ | awk -F " — " '{print $2}') date=$(echo "$group2" \ | awk -F " — " '{print $1}' \ | awk '{print substr($0, 2, length($0) - 2)}') mpc search date "$date" album "$album" albumartist "$artist" | clerk_helper saveto fi done < <(echo -e "0 Return to Main Menu\n---\n$(cat $HOME/.config/clerk/albums.cache)" | dmenu_t -dmenu -p "Save Album to Playlist > ") if [[ $seen = 0 ]] then exit fi } saveLatestToPlaylist() { declare -i seen=0 while read TRACK do seen=1 if [[ "$TRACK" == "0 Return to Main Menu" ]] then dplayPrompt else artist=$(echo -en "$TRACK" \ | awk -F '\t' '{ print $1 }' \ | sed -e 's/[[:space:]]*$//') group2=$(echo -en "$TRACK" \ | awk -F '\t' '{ print $2 }' \ | sed -e 's/[[:space:]]*$//') album=$(echo "$group2" \ | awk -F " — " '{print $2}') date=$(echo "$group2" \ | awk -F " — " '{print $1}' \ | awk '{print substr($0, 2, length($0) - 2)}') mpc search date "$date" album "$album" albumartist "$artist" | clerk_helper saveto fi done < <(echo -e "0 Return to Main Menu\n---\n$(cat $HOME/.config/clerk/latest.cache)" | dmenu_t -dmenu -p "Save Album to Playlist > ") if [[ $seen = 0 ]] then exit fi } saveTrackToPlaylist() { TRACK_TEMP=$((echo -e "0 Return to Main Menu\n---"; cat $HOME/.config/clerk/tracks.cache) | dmenu_t -filter "$filter" -select "$entry" -format "f¬s" -dmenu -p "Save Track to Playlist > ") TRACK="${TRACK_TEMP#*¬}" unset filter export filter="$(echo ${TRACK_TEMP} | awk -F '¬' '{ print $1 }')" if [[ "$TRACK" == "0 Return to Main Menu" ]] then dplayPrompt elif [[ -z "$TRACK" ]]; then exit else filename=$(echo "$TRACK" | awk -F "\t" '{print $3}') info=$(mpc search --format '%artist%\t%album%\t%date%\t%track%\t%title%' filename "${filename}") artist="$(echo "$info" \ | awk -F '\t' '{ print $1 }')" album="$(echo "$info" \ | awk -F '\t' '{ print $2 }')" date="$(echo "$info" \ | awk -F '\t' '{ print $3 }')" track="$(echo "$info" \ | awk -F '\t' '{ print $4 }')" title="$(echo "$info" \ | awk -F '\t' '{ print $5 }')" mpc search track "$track" album "$album" title "$title" albumartist "$artist" | clerk_helper saveto entry="$TRACK" saveTrackToPlaylist fi } ################################################################################ function dmenu_t () { rofi -dmenu -z $(echo "$rofiopts") "$@" } while :; do case $1 in --add) if [[ ! $2 ]]; then echo "Missing argument for --add" echo "Possible values: track, album, latest" elif [[ $2 == track ]]; then AddTrackTags elif [[ $2 == album ]]; then AddAlbumTags elif [[ $2 == latest ]]; then addLastMod fi break ;; --rate) if [[ ! $2 ]]; then echo "Missing arguemtn for --rate" echo "Possible values: track, album, instant" echo "Launching rating menu" ratingPrompt elif [[ $2 == track ]]; then rateTrack elif [[ $2 == album ]]; then rateAlbum elif [[ $2 == instant ]]; then if [[ ! $3 ]]; then echo "Missing argument for --rate instant" echo "Please define rating between 1-10" else instantRateTrack $3 fi elif [[ $2 == load ]]; then mpc clear && mpc sticker "" find rating | grep -E "rating=6|rating=7|rating=8|rating=9|rating=10" | awk -F ':' '{print $1}' | $shuf -n $value | mpc add && mpc play fi break ;; --random) if [[ ! $2 ]]; then echo "Missing argument for --random" echo "Possible values: track, album" elif [[ $2 == track ]]; then playRandomTracks elif [[ $2 == album ]]; then playRandomAlbum fi break ;; --current) currentTag break ;; --browse) if [[ ! $2 ]]; then echo "Missing argument for --browse" echo "Possible values: artist, date, genre, folder, system" elif [[ $2 == artist ]]; then browseArtist elif [[ $2 == albumartist ]]; then browseAlbumArtist elif [[ $2 == date ]]; then browseDate elif [[ $2 == genre ]]; then browseGenre elif [[ $2 == system ]]; then browseFilesystem elif [[ $2 == folder ]]; then browseFolders fi break ;; --backup) if [[ ! $2 ]]; then echo "Missing argument for --backup" echo "Possible values: track, album" elif [[ $2 == track ]]; then backupTrackRatings elif [[ $2 == album ]]; then backupAlbumRatings fi break ;; --restore) if [[ ! $2 ]]; then echo "Missing argument for --restore" echo "Possible values: track, album" elif [[ $2 == track ]]; then restoreTrackRatings elif [[ $2 == album ]]; then restoreAlbumRatings fi break ;; --update) updateCache break ;; --queue) if [[ ! $2 ]]; then echo "Missing argument for --queue" echo "Possible values: show, delete, suspend, resume" elif [[ $2 == show ]]; then dplayQueue elif [[ $2 == delete ]]; then dplayQueueDelete elif [[ $2 == suspend ]]; then suspendPlaylist elif [[ $2 == resume ]]; then resumePlaylist fi break ;; --rss) loadRSS break ;; --playlist) if [[ $2 == savealbum ]]; then saveAlbumToPlaylist elif [[ $2 == savelast ]]; then saveLatestToPlaylist elif [[ $2 == savetrack ]]; then saveTrackToPlaylist fi break ;; --lastfm) if [[ ! $2 ]]; then echo "Missing argument for --lastfm" echo "Possible values: toggle, check, love" elif [[ $2 == toggle ]]; then lastFM elif [[ $2 == check ]]; then lastFMCheck elif [[ $2 == love ]]; then if [[ scrobbler=mpdscribble ]]; then lastfm-mpd-cli love > /dev/null && notify-send "MPD" "Loved $(mpc current -f '%title%') on LastFM" elif [[ scrobbler=mpdas ]]; then mpc sendmessage mpdas love fi fi break ;; --help|-h) echo "---" echo "clerk: rofi/dmenu based MPD Interface" echo "Copyright © 2013 - 2015 Rasmus Steinke" echo "---" echo "General" echo " --help, -h this help message" echo " --current show currently playing track" echo " --update update album/track caches" echo "" echo "Library" echo " --add adds selection at the end of the queue" echo " --random play random track or album" echo "" echo "Playlist" echo " --queue manage current queue" echo " --playlist save selection to playlist \"clerk\"" echo " --rss load podcast" echo " (podcast should be placed in ~/.config/clerk/podcasts" echo " with format NAME \ URL)" echo "" echo "Ratings" echo " --rate rate albums or tracks" echo " "load" adds random rated tracks to queue" echo "" echo " --backup backup ratings from mpd sticker database to json file." echo " --restore restore ratings back to mpd sticker database" echo "" echo "LastFM" echo " --lastfm toggle or check last.fm status, love current track" break ;; *) dplayPrompt ;; esac shift done