# Print the command that sets the header. # @argument $1: view # @argument $2: mbid fzf_command_set_header() { view=$1 mbid=$2 case "$view" in "$VIEW_SEARCH_ARTIST") header="Search artist on MusicBrainz" ;; "$VIEW_SEARCH_ALBUM") header="Search album on MusicBrainz" ;; "$VIEW_LIST_ARTISTS") header="Search locally available artist" ;; "$VIEW_LIST_ALBUMS") header="Search locally available album" ;; "$VIEW_ARTIST") name="$(mb_artist "$mbid" | $JQ -r '.name')" header=$(printf "$ARTIST_PROMPT" "$name") ;; "$VIEW_RELEASEGROUP") title="$(mb_releasegroup "$mbid" | $JQ -r '.title')" artist="$(mb_releasegroup "$mbid" | $JQ -r '."artist-credit" | map(([.name, .joinphrase]|join(""))) | join("")')" header=$(printf "$FULL_PROMPT" "$artist" "$title") ;; "$VIEW_RELEASE") title="$(mb_release "$mbid" | $JQ -r '.title')" artist="$(mb_release "$mbid" | $JQ -r '."artist-credit" | map(([.name, .joinphrase]|join(""))) | join("")')" header=$(printf "$FULL_PROMPT" "$artist" "$title") ;; esac printf "+change-header(%s)" "${header:-"???"}" } # Print the command that tells fzf to load the data # @argument $1: view # @argument $2: mbid fzf_command_load_data() { view=$1 mbid=${2:-} case "$view" in "$VIEW_SEARCH_ARTIST") ;; "$VIEW_SEARCH_ALBUM") ;; "$VIEW_LIST_ARTISTS") ;; "$VIEW_LIST_ALBUMS") ;; "$VIEW_ARTIST") ;; "$VIEW_RELEASEGROUP") ;; "$VIEW_RELEASE") ;; esac printf "+reload($0 --lines %s %s)" "$VIEW_LIST_ARTISTS" "" } # Set prompt of input field # @argument $1: view # @argument $2: mode __set_prompt() { view=$1 mode=$2 case "$view" in "$VIEW_ARTIST") name="$(mb_artist "$args" | $JQ -r '.name')" PROMPT=$(printf "$ARTIST_PROMPT" "$name") ;; "$VIEW_RELEASEGROUP") title="$(mb_releasegroup "$args" | $JQ -r '.title')" artist="$(mb_releasegroup "$args" | $JQ -r '."artist-credit" | map(([.name, .joinphrase]|join(""))) | join("")')" PROMPT=$(printf "$FULL_PROMPT" "$artist" "$title") ;; "$VIEW_RELEASE") title="$(mb_release "$args" | $JQ -r '.title')" artist="$(mb_release "$args" | $JQ -r '."artist-credit" | map(([.name, .joinphrase]|join(""))) | join("")')" PROMPT=$(printf "$FULL_PROMPT" "$artist" "$title") ;; esac [ "$mode" = "$MODE_INSERT" ] && PT="$PROMPT_INSERT" || PT="$PROMPT_NORMAL" printf "+change-header(%s %s)" "$PT" "${PROMPT:-"$SEARCH_PROMPT"}" } # Reload data for FZF fzf_handle_reload() { view=$(state_get_view) mode=$(state_get_mode) args=$(state_get_args) case "$view" in "$VIEW_ARTIST") list_releasegroups "$args" ;; "$VIEW_RELEASEGROUP") list_releases "$args" ;; "$VIEW_RELEASE") list_recordings "$args" ;; "$VIEW_LIST_ARTISTS") list_local_artists ;; "$VIEW_LIST_ALBUMS") list_local_releasegroups ;; esac } # Handle for after loading data into FZF fzf_handle_load() { view=$(state_get_view) mode=$(state_get_mode) args=$(state_get_args) case "$view" in "$VIEW_ARTIST") QUERY="!'$QUERY_HAS_SECONDARY' " ;; "$VIEW_RELEASEGROUP") [ "$QUERY_RV" ] && QUERY="'$QUERY_RV' " || QUERY="" ;; "$VIEW_SEARCH_ARTIST") ENABLE_CHANGE=1 DISABLE_SEARCH=1 SHOW_PREVIEW=1 ;; "$VIEW_SEARCH_ALBUM") ENABLE_CHANGE=1 DISABLE_SEARCH=1 ;; "$VIEW_LIST_ARTISTS") SHOW_PREVIEW=1 ;; "$VIEW_LIST_ALBUMS") ;; esac [ "${DISABLE_SEARCH:-}" ] && printf "+disable-search+change-query(%s)+disable-search" "${QUERY:-"$FZF_QUERY"}" || printf "+enable-search+change-query(%s)+enable-search" "${QUERY:-}" [ "${SHOW_PREVIEW:-}" ] && printf "+show-preview" || printf "+hide-preview" [ "${ENABLE_CHANGE:-}" ] && printf "+rebind(change)" || printf "+unbind(change)" __set_prompt "$view" "$mode" } # Print info string for FZF fzf_info() { view=$(state_get_view) mode=$(state_get_mode) args=$(state_get_args) case "$view" in "$VIEW_SEARCH_ARTIST") echo "Search music artist on MusicBrainz" ;; "$VIEW_SEARCH_ALBUM") echo "Search album on MusicBrainz" ;; "$VIEW_LIST_ARTISTS") echo "Search artists" ;; "$VIEW_LIST_ALBUMS") echo "Search albums" ;; "$VIEW_SELECT_ARTIST") debug "Select artist (WE SHOULDNT SEE THIS; THIS IS A BUG!)" ;; *) if [ "$FZF_KEY" ]; then printf "[last key: %s] %s/%s" "$FZF_KEY" "$FZF_MATCH_COUNT" "$FZF_TOTAL_COUNT" else printf "%s/%s" "$FZF_MATCH_COUNT" "$FZF_TOTAL_COUNT" fi ;; esac } # Reload hook that is used after change in query fzf_reload_after_change() { # Wait for async. process to terminate sleep 1 while [ -f "$LOCKFILE" ]; do sleep 1 done # Show results column -t -s "$(printf '\t')" "$RESULTS" | sed 's| \+\([0-9a-f-]\+\) \+\([0-9a-f-]\+\)$|\t\1\t\2|' } # Handle change in query fzf_handle_change() { view="$1" # Kill any running search if [ -f "$PIDFILE" ]; then pid=$(cat "$PIDFILE") rm -f "$PIDFILE" kill -9 "$pid" >/dev/null 2>&1 || true fi # Stop, if no search string is given [ "$FZF_QUERY" ] || exit 0 # Store PID of current process echo "$$" >"$PIDFILE" touch "$LOCKFILE" sleep 1 if [ "$view" = "$VIEW_SEARCH_ARTIST" ]; then api_mb_search_artist "$FZF_QUERY" | $JQ -r '.artists[] | [ .id, .type, .name, .disambiguation, .["life-span"].begin, .["life-span"].end ] | join("\t")' | awk \ -F "\t" \ -v file_local_artists="${LOCALDATA_ARTISTS:-}" \ -v format_person="$AV_PERSON" \ -v format_group="$AV_GROUP" \ -v format_disambiguation="$AV_DISAMBIGUATION" \ -v format_local="$FORMAT_LOCAL" \ "$AWK_ARTISTS" >"$RESULTS" || true else api_mb_search_releasegroup "$FZF_QUERY" | $JQ -r '."release-groups"[] | [ .id, ."primary-type", (."secondary-types" // []|join(";")), ."first-release-date", .title, (."artist-credit" | map(([.name, .joinphrase]|join(""))) | join("")) ] | join("\t")' | awk \ -F "\t" \ -v file_local_releasegroups="${LOCALDATA_RELEASEGROUPS:-}" \ -v format_release="$RGV_RELEASE" \ -v format_release_w_artist="$RGV_RELEASE_W_ARTIST" \ -v format_year="$RGV_YEAR" \ -v format_album="$FORMAT_TYPE_ALBUM" \ -v format_single="$FORMAT_TYPE_SINGLE" \ -v format_ep="$FORMAT_TYPE_EP" \ -v format_broadcast="$FORMAT_TYPE_BROADCAST" \ -v format_other="$FORMAT_TYPE_OTHER" \ -v format_has_secondary="$FORMAT_TYPE_HAS_SECONDARY" \ -v format_secondary="$FORMAT_TYPE_SECONDARY" \ -v format_compilation="$FORMAT_TYPE_SECONDARY_COMPILATION" \ -v format_soundtrack="$FORMAT_TYPE_SECONDARY_SOUNDTRACK" \ -v format_spokenword="$FORMAT_TYPE_SECONDARY_SPOKENWORD" \ -v format_interview="$FORMAT_TYPE_SECONDARY_INTERVIEW" \ -v format_audiobook="$FORMAT_TYPE_SECONDARY_AUDIOBOOK" \ -v format_audiodrama="$FORMAT_TYPE_SECONDARY_AUDIODRAMA" \ -v format_live="$FORMAT_TYPE_SECONDARY_LIVE" \ -v format_remix="$FORMAT_TYPE_SECONDARY_REMIX" \ -v format_djmix="$FORMAT_TYPE_SECONDARY_DJMIX" \ -v format_mixtape="$FORMAT_TYPE_SECONDARY_MIXTAPE" \ -v format_demo="$FORMAT_TYPE_SECONDARY_DEMO" \ -v format_fieldrec="$FORMAT_TYPE_SECONDARY_FIELDREC" \ -v format_local="$FORMAT_LOCAL" \ "$AWK_RELEASEGROUPS" | cut -d "$(printf '\t')" -f 2- >"$RESULTS" || true fi # Process ends now: Display and quit rm -f "$LOCKFILE" "$PIDFILE" } # Handle FZF keypress # @argument $1: MusicBrainz ID of parent object # @argument $2: MusicBrainz ID of selected object # @argument $3: Path to decoration file (optional) fzf_handle_key() { parentmbid="${1:-}" mbid="${2:-}" path="${3:-}" view=$(state_get_view) mode=$(state_get_mode) args=$(state_get_args) # If we are in the insert mode, and the key pressed is an "input" key, then # put it and quit. if [ "$mode" = "$MODE_INSERT" ]; then case ",$KEYS_INPUT_SINGLE," in *",$FZF_KEY,"*) printf "put(%s)" "$FZF_KEY" return 0 ;; esac case ",$KEYS_INPUT_SPECIAL," in *",$FZF_KEY,"*) case "$FZF_KEY" in "space") printf "put( )" ;; "backspace") printf "backward-delete-char" ;; "delete") printf "delete-char" ;; "left") printf "backward-char" ;; "right") printf "forward-char" ;; esac return 0 ;; esac # Keys in insert mode only case ",$KEYS_I_NORMAL," in *",$FZF_KEY,"*) case "$view" in "$VIEW_PLAYLIST") ;; *) state_update_keep_args "$view" "$MODE_NORMAL" __set_prompt "$view" "$MODE_NORMAL" ;; esac ;; esac fi # Keys exclusive to playlist view if [ "$view" = "$VIEW_PLAYLIST" ]; then case ",$KEYS_PLAYLIST_RELOAD," in *",$FZF_KEY,"*) debug "hit playlist reload key" debug "going to call $(printf "reload:%s" "$0 --fzf-reload")" printf "reload:%s" "$0 --fzf-reload" ;; esac fi # Handle key press case ",$KEYS_HALFPAGE_DOWN," in *",$FZF_KEY,"*) printf "half-page-down" ;; esac case ",$KEYS_HALFPAGE_UP," in *",$FZF_KEY,"*) printf "half-page-up" ;; esac case ",$KEYS_OPEN," in *",$FZF_KEY,"*) [ "$path" ] || return 0 open "$(dirname "$path")" return 0 ;; esac case ",$KEYS_BROWSE," in *",$FZF_KEY,"*) [ "$mbid" ] || return 0 case "$view" in "$VIEW_SEARCH_ARTIST" | "$VIEW_LIST_ARTISTS" | "$VIEW_SELECT_ARTIST") urltype="artist" ;; "$VIEW_ARTIST" | "$VIEW_SEARCH_ALBUM" | "$VIEW_LIST_ALBUMS") urltype="release-group" ;; "$VIEW_RELEASEGROUP") urltype="release" ;; "$VIEW_RELEASE" | "$VIEW_PLAYLIST") urltype="track" ;; esac [ "${urltype:-}" ] && printf "execute-silent(xdg-open \"https://musicbrainz.org/%s/%s\" &)" "$urltype" "$mbid" ;; esac case ",$KEYS_OUT," in *",$FZF_KEY,"*) case "$view" in "$VIEW_ARTIST") VIEW_NEXT="$VIEW_LIST_ARTISTS" ;; "$VIEW_RELEASEGROUP") VIEW_NEXT="$VIEW_SELECT_ARTIST" VIEW_NEXT_ARGS="$(mb_releasegroup "$args" | $JQ -r --compact-output '."artist-credit"')" ACCEPT=1 ;; "$VIEW_RELEASE") VIEW_NEXT="$VIEW_RELEASEGROUP" VIEW_NEXT_ARGS="$(mb_release "$args" | $JQ -r --compact-output '."release-group".id')" ;; "$VIEW_PLAYLIST") VIEW_NEXT="$VIEW_RELEASE" VIEW_NEXT_ARGS="$parentmbid" ACCEPT=1 ;; esac ;; esac case ",$KEYS_IN," in *",$FZF_KEY,"*) [ "$mbid" ] || return 0 VIEW_NEXT_ARGS="$mbid" case "$view" in "$VIEW_LIST_ARTISTS" | "$VIEW_SEARCH_ARTIST") VIEW_NEXT="$VIEW_ARTIST" ;; "$VIEW_ARTIST" | "$VIEW_SEARCH_ALBUM" | "$VIEW_LIST_ALBUMS") VIEW_NEXT="$VIEW_RELEASEGROUP" ;; "$VIEW_RELEASEGROUP") VIEW_NEXT="$VIEW_RELEASE" ;; esac ;; esac case ",$KEYS_SELECT_ARTIST," in *",$FZF_KEY,"*) [ "$mbid" ] || return 0 case "$view" in "$VIEW_ARTIST" | "$VIEW_SEARCH_ARTIST" | "$VIEW_LIST_ARTISTS") VIEW_NEXT_ARGS="$(mb_releasegroup "$mbid" | $JQ -r --compact-output '."artist-credit"')" ACCEPT=1 ;; "$VIEW_RELEASEGROUP" | "$VIEW_SEARCH_ALBUM" | "$VIEW_LIST_ALBUMS") VIEW_NEXT_ARGS="$(mb_release "$mbid" | $JQ -r --compact-output '."artist-credit"')" ACCEPT=1 ;; "$VIEW_RELEASE") VIEW_NEXT_ARGS="$(mb_release "$args" | $JQ -r --compact-output '."artist-credit"')" ACCEPT=1 ;; "$VIEW_PLAYLIST") debug "NOT IMPLEMENTED" ;; esac [ "$VIEW_NEXT_ARGS" ] && VIEW_NEXT="$VIEW_SELECT_ARTIST" ;; esac case ",$KEYS_FILTER_LOCAL," in *",$FZF_KEY,"*) case "$view" in "$VIEW_SEARCH_ARTIST" | "$VIEW_SEARCH_ALBUM" | "$VIEW_PLAYLIST") ;; *) QUERY="'$QUERY_LOCAL' " ;; esac ;; esac # VIEW_RELEASEGROUP="rg" # VIEW_RELEASE="release" # VIEW_LIST_ARTISTS="list-artists" # VIEW_SELECT_ARTIST="select-artist" # VIEW_PLAYLIST="playlist" case ",$KEYS_FILTER_1," in *",$FZF_KEY,"*) case "$view" in "$VIEW_ARTIST" | "$VIEW_LIST_ALBUMS") QUERY="!'$QUERY_HAS_SECONDARY' " ;; esac ;; esac case ",$KEYS_FILTER_2," in *",$FZF_KEY,"*) case "$view" in "$VIEW_ARTIST" | "$VIEW_LIST_ALBUMS") QUERY="!'$QUERY_HAS_SECONDARY' '$QUERY_ALBUM' " ;; esac ;; esac case ",$KEYS_FILTER_3," in *",$FZF_KEY,"*) case "$view" in "$VIEW_ARTIST" | "$VIEW_LIST_ALBUMS") QUERY="!'$QUERY_HAS_SECONDARY' '$QUERY_EP' " ;; esac ;; esac case ",$KEYS_FILTER_4," in *",$FZF_KEY,"*) case "$view" in "$VIEW_ARTIST" | "$VIEW_LIST_ALBUMS") QUERY="!'$QUERY_HAS_SECONDARY' '$QUERY_SINGLE' " ;; esac ;; esac case ",$KEYS_SWITCH_ARTIST_ALBUM," in *",$FZF_KEY,"*) case "$view" in "$VIEW_SEARCH_ARTIST") VIEW_NEXT="$VIEW_SEARCH_ALBUM" ;; "$VIEW_SEARCH_ALBUM") VIEW_NEXT="$VIEW_SEARCH_ARTIST" ;; "$VIEW_LIST_ARTISTS") VIEW_NEXT="$VIEW_LIST_ALBUMS" ;; "$VIEW_LIST_ALBUMS") VIEW_NEXT="$VIEW_LIST_ARTISTS" ;; esac ;; esac case ",$KEYS_SWITCH_LOCAL_REMOTE," in *",$FZF_KEY,"*) case "$view" in "$VIEW_SEARCH_ARTIST") VIEW_NEXT="$VIEW_LIST_ARTISTS" ;; "$VIEW_SEARCH_ALBUM") VIEW_NEXT="$VIEW_LIST_ALBUMS" ;; "$VIEW_LIST_ARTISTS") VIEW_NEXT="$VIEW_SEARCH_ARTIST" MODE_NEXT="$MODE_INSERT" ;; "$VIEW_LIST_ALBUMS") VIEW_NEXT="$VIEW_SEARCH_ALBUM" MODE_NEXT="$MODE_INSERT" ;; esac ;; esac case ",$KEYS_SHOW_PLAYLIST," in *",$FZF_KEY,"*) VIEW_NEXT="$VIEW_PLAYLIST" ACCEPT=1 ;; esac case ",$KEYS_PLAY," in *",$FZF_KEY,"*) [ "$path" ] || return 0 case "$view" in "$VIEW_ARTIST" | "$VIEW_SEARCH_ARTIST" | "$VIEW_SEARCH_ALBUM" | "$VIEW_LIST_ARTISTS" | "$VIEW_LIST_ALBUMS") debug "not implemented" ;; "$VIEW_RELEASEGROUP") generate_playlist "$mbid" "$path" | mpv_play_list >/dev/null ;; "$VIEW_RELEASE") generate_playlist "$parentmbid" "$path" "$mbid" | mpv_play_list >/dev/null ;; "$VIEW_PLAYLIST") generate_playlist "$parentmbid" "$path" "$mbid" | mpv_play_list >/dev/null VIEW_NEXT="$VIEW_PLAYLIST" ACCEPT=1 ;; esac ;; esac case ",$KEYS_QUEUE," in *",$FZF_KEY,"*) [ "$path" ] || return 0 case "$view" in "$VIEW_ARTIST" | "$VIEW_SEARCH_ARTIST" | "$VIEW_SEARCH_ALBUM" | "$VIEW_LIST_ARTISTS" | "$VIEW_LIST_ALBUMS") debug "not implemented" ;; "$VIEW_RELEASEGROUP") generate_playlist "$mbid" "$path" | mpv_queue_list >/dev/null ;; "$VIEW_RELEASE") generate_playlist "$parentmbid" "$path" "$mbid" | mpv_queue_list >/dev/null ;; "$VIEW_PLAYLIST") generate_playlist "$parentmbid" "$path" "$mbid" | mpv_queue_list >/dev/null VIEW_NEXT="$VIEW_PLAYLIST" ACCEPT=1 ;; esac ;; esac # Keys in normal mode only if [ "$mode" = "$MODE_NORMAL" ]; then case ",$KEYS_N_DOWN," in *",$FZF_KEY,"*) printf "down" ;; esac case ",$KEYS_N_UP," in *",$FZF_KEY,"*) printf "up" ;; esac case ",$KEYS_N_OUT," in *",$FZF_KEY,"*) case "$view" in "$VIEW_ARTIST") VIEW_NEXT="$VIEW_LIST_ARTISTS" ;; "$VIEW_RELEASEGROUP") VIEW_NEXT="$VIEW_SELECT_ARTIST" VIEW_NEXT_ARGS="$(mb_releasegroup "$args" | $JQ -r --compact-output '."artist-credit"')" ACCEPT=1 ;; "$VIEW_RELEASE") VIEW_NEXT="$VIEW_RELEASEGROUP" VIEW_NEXT_ARGS="$(mb_release "$args" | $JQ -r --compact-output '."release-group".id')" ;; "$VIEW_PLAYLIST") VIEW_NEXT="$VIEW_RELEASE" VIEW_NEXT_ARGS="$parentmbid" ACCEPT=1 ;; esac ;; esac case ",$KEYS_N_IN," in *",$FZF_KEY,"*) [ "$mbid" ] || return 0 VIEW_NEXT_ARGS="$mbid" case "$view" in "$VIEW_LIST_ARTISTS" | "$VIEW_SEARCH_ARTIST") VIEW_NEXT="$VIEW_ARTIST" ;; "$VIEW_ARTIST" | "$VIEW_SEARCH_ALBUM" | "$VIEW_LIST_ALBUMS") VIEW_NEXT="$VIEW_RELEASEGROUP" ;; "$VIEW_RELEASEGROUP") VIEW_NEXT="$VIEW_RELEASE" ;; esac ;; esac case ",$KEYS_N_TOP," in *",$FZF_KEY,"*) printf "first" ;; esac case ",$KEYS_N_BOT," in *",$FZF_KEY,"*) printf "last" ;; esac case ",$KEYS_N_QUIT," in *",$FZF_KEY,"*) case "$view" in "$VIEW_SELECT_ARTIST" | "$VIEW_PLAYLIST") printf "accept" ;; *) printf "print(Q)+abort" ;; esac ;; esac case ",$KEYS_N_INSERT," in *",$FZF_KEY,"*) case "$view" in "$VIEW_PLAYLIST") ;; *) state_update_keep_args "$view" "$MODE_INSERT" __set_prompt "$view" "$MODE_INSERT" ;; esac ;; esac case ",$KEYS_N_TOGGLE_PLAY_PAUSE," in *",$FZF_KEY,"*) mpv_toggle_pause >/dev/null ;; esac case ",$KEYS_N_PLAY_NEXT," in *",$FZF_KEY,"*) mpv_next >/dev/null [ "$view" = "$VIEW_PLAYLIST" ] && VIEW_NEXT="$VIEW_PLAYLIST" && ACCEPT=1 ;; esac case ",$KEYS_N_PLAY_PREV," in *",$FZF_KEY,"*) mpv_prev >/dev/null [ "$view" = "$VIEW_PLAYLIST" ] && VIEW_NEXT="$VIEW_PLAYLIST" && ACCEPT=1 ;; esac case ",$KEYS_N_SEEK_FORWARD," in *",$FZF_KEY,"*) mpv_seek_forward >/dev/null ;; esac case ",$KEYS_N_SEEK_BACKWARD," in *",$FZF_KEY,"*) mpv_seek_backward >/dev/null ;; esac fi # Post processing [ "${QUERY:-}" ] && printf "+change-query(%s)" "$QUERY" if [ "${VIEW_NEXT:-}" ]; then [ "$VIEW_NEXT" = "$VIEW_PLAYLIST" ] && MODE_NEXT="$MODE_NORMAL" state_update "$VIEW_NEXT" "${MODE_NEXT:-"$mode"}" "${VIEW_NEXT_ARGS:-}" [ "$MODE_NEXT" = "$MODE_INSERT" ] && printf "+enable-search" || printf "+disable-search" [ "${ACCEPT:-}" ] && printf "+accept" || printf "+reload:%s" "$0 --fzf-reload" fi }