diff --git a/src/main.sh b/src/main.sh index e4d586b..968e2ba 100755 --- a/src/main.sh +++ b/src/main.sh @@ -35,134 +35,140 @@ set -eu # Load local file handling . "sh/local.sh" -# Support of local music files -if [ "${1:-}" = "--decorate" ]; then - [ ! "${2:-}" ] && err "You did not specify a directory." && exit 1 - [ ! -d "$2" ] && err "Path $2 does not point to a directory." && exit 1 - if ! decorate "$2"; then - err "Something went wrong. Are you're files tagged correctly?" - exit 1 - fi +# Load list-generating methods +. "sh/lists.sh" + +if [ "${1:-}" = "--fzf-reload" ]; then + mode=$(cut -d "#" -f 1 "$MODEFILE") + args=$(cut -d "#" -f 2- "$MODEFILE") + case "$mode" in + "$MODE_ARTIST") + list_releasegroups "$args" + ;; + "$MODE_RELEASEGROUP") + list_releases "$args" + ;; + "$MODE_RELEASE") + list_recordings "$args" + ;; + "$MODE_LIST_ARTISTS") + list_local_artists + ;; + "$MODE_LIST_ALBUMS") + list_local_releasegroups + ;; + "$MODE_SELECT_ARTIST") + true + ;; + esac exit 0 fi -if [ "${1:-}" = "--reload" ]; then - [ ! "${2:-}" ] && err "Path to decorated music is missing." && exit 1 - [ ! -d "$2" ] && err "Path does not point to a directory." && exit 1 - info "Reloading information of local music directory $2" - load_local "$2" || err "Failed to load local data" - info "Done" +if [ "${1:-}" = "--fzf-load" ]; then + mode=$(cut -d "#" -f 1 "$MODEFILE") + args=$(cut -d "#" -f 2- "$MODEFILE") + case "$mode" in + "$MODE_ARTIST") + secsymb="$(printf "$FORMAT_TYPE_HAS_SECONDARY" "")" + QUERY="$(printf "!%s " "$secsymb")" + name="$(mb_artist "$args" | $JQ -r '.name')" + PROMPT=$(printf "$ARTIST_PROMPT" "$name") + ;; + "$MODE_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") + ;; + "$MODE_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") + ;; + "$MODE_SEARCH_ARTIST") + ENABLE_CHANGE=1 + DISABLE_SEARCH=1 + SHOW_PREVIEW=1 + ;; + "$MODE_SEARCH_ALBUM") + ENABLE_CHANGE=1 + DISABLE_SEARCH=1 + ;; + "$MODE_LIST_ARTISTS") + SHOW_PREVIEW=1 + ;; + "$MODE_LIST_ALBUMS") ;; + "$MODE_SELECT_ARTIST") ;; + esac + [ "${QUERY:-}" ] && printf "+change-query(%s)" "$QUERY" + printf "+change-prompt(%s)" "${PROMPT:-"$SEARCH_PROMPT"}" + [ "${DISABLE_SEARCH:-}" ] && printf "+disable-search" || printf "+enable-search" + [ "${SHOW_PREVIEW:-}" ] && printf "+show-preview" || printf "+hide-preview" + [ "${ENABLE_CHANGE:-}" ] && printf "+rebind(change)" || printf "+unbind(change)" exit 0 fi -if [ "${1:-}" = "--list-releases" ]; then - list_releases +if [ "${1:-}" = "--fzf-info" ]; then + mode=$(cut -d "#" -f 1 "$MODEFILE") + args=$(cut -d "#" -f 2- "$MODEFILE") + case "$mode" in + "$MODE_SEARCH_ARTIST") + echo "Search music artist on MusicBrainz" + ;; + "$MODE_SEARCH_ALBUM") + echo "Search album on MusicBrainz" + ;; + "$MODE_LIST_ARTISTS") + echo "Search artists" + ;; + "$MODE_LIST_ALBUMS") + echo "Search albums" + ;; + "$MODE_SELECT_ARTIST") + echo "Select artist" + ;; + *) + 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 exit 0 fi -if [ "${1:-}" = "--list-releasegroups" ]; then - list_releasegroups - exit 0 -fi - -if [ "${1:-}" = "--list-artists" ]; then - list_artists - exit 0 -fi - -if [ "${1:-}" = "--play-release" ]; then - mbid=${2} - deco=${3} - base="$(dirname "$deco")" - echo "Playing release ($mbid) [$deco]" >>/tmp/foo - tmplist=$(mktemp) - mb_release "$mbid" | - $JQ -r --slurpfile deco "$deco" --arg base "$base" '$deco[].tracks as $filenames | - .media[] | - .position as $pos | - .tracks | - map({ - $pos, - number: .number, - file: $filenames[.id] - }) | - map( - if(.number | type == "string" and test("^[0-9]+$")) then - .number |= tonumber - else - . - end - ) | - sort_by([.pos, .number]) | - map($base + "/" + .file)[]' >"$tmplist" - if [ "${4:-}" ]; then - mpv_queue_list "$tmplist" - else - mpv_play_list "$tmplist" - fi - rm -f "$tmplist" - exit 0 -fi - -if [ "${1:-}" = "--play-recording" ]; then - echo "Playing recording $2" >>/tmp/foo - if [ "${3:-}" ]; then - mpv_queue_file "$2" - else - mpv_play_file "$2" - fi - exit 0 -fi - -if [ "${1:-}" = "--play-toggle" ]; then - mpv_toggle_pause -fi - -if [ "${1:-}" = "--play-next" ]; then - mpv_next -fi - -if [ "${1:-}" = "--play-previous" ]; then - mpv_prev -fi - -if [ "${1:-}" = "--seek-forward" ]; then - mpv_seek_forward -fi - -if [ "${1:-}" = "--seek-backward" ]; then - mpv_seek_backward -fi - -if [ "${1:-}" = "--internal-preview-artist" ]; then - __preview_artist "$2" - exit 0 -fi - -if [ "${1:-}" = "--internal-reload" ]; then +if [ "${1:-}" = "--fzf-change-reload" ]; then + # 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-]\+\)$|\t\1|' exit 0 fi -if [ "${1:-}" = "--internal-search" ]; then - printf "" >"$RESULTS" +if [ "${1:-}" = "--fzf-change" ]; then + # Kill any running search if [ -f "$PIDFILE" ]; then pid=$(cat "$PIDFILE") rm -f "$PIDFILE" kill -9 "$pid" >/dev/null 2>&1 || true fi - [ ! "${3}" ] && exit 0 - # Save current pid + # Stop, if no search string is given + [ "$FZF_QUERY" ] || exit 0 + # Store PID of current process echo "$$" >"$PIDFILE" touch "$LOCKFILE" sleep 1 - if [ "$2" = "artist" ]; then - api_mb_search_artist "$3" | + mode=$(cut -d "#" -f 1 "$MODEFILE") + if [ "$mode" = "$MODE_SEARCH_ARTIST" ]; then + api_mb_search_artist "$FZF_QUERY" | $JQ -r '.artists[] | [ .id, .type, @@ -178,11 +184,10 @@ if [ "${1:-}" = "--internal-search" ]; then -v format_group="$AV_GROUP" \ -v format_disambiguation="$AV_DISAMBIGUATION" \ -v format_local="$FORMAT_LOCAL" \ - "$AWK_ARTISTS" | - tee "$RESULTS" || + "$AWK_ARTISTS" >"$RESULTS" || true else - api_mb_search_releasegroup "$3" | + api_mb_search_releasegroup "$FZF_QUERY" | $JQ -r '."release-groups"[] | [ .id, ."primary-type", @@ -218,152 +223,195 @@ if [ "${1:-}" = "--internal-search" ]; then -v format_fieldrec="$FORMAT_TYPE_SECONDARY_FIELDREC" \ -v format_local="$FORMAT_LOCAL" \ "$AWK_RELEASEGROUPS" | - cut -d "$(printf '\t')" -f 2- | - column -t -s "$(printf '\t')" | - sed 's| \+\([0-9a-f-]\+\)$|\t\1|' | - tee "$RESULTS" || + cut -d "$(printf '\t')" -f 2- >"$RESULTS" || true fi + # Process ends now: Display and quit rm -f "$LOCKFILE" "$PIDFILE" exit 0 fi -if [ "${1:-}" = "--internal-list-releasegroups" ]; then - name=$(mb_artist "$2" | $JQ -r '.name') - mb_artist_releasegroups "$2" | - $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 artist="$name" \ - -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" | - sort -n -r | - cut -d "$(printf '\t')" -f 2- | - column -t -s "$(printf '\t')" | - sed 's| \+\([0-9a-f-]\+\)$|\t\1|' - exit 0 -fi - -if [ "${1:-}" = "--internal-list-releases" ]; then - title="$(mb_releasegroup "$2" | - $JQ -r '.title')" - artist="$(mb_releasegroup "$2" | - $JQ -r '."artist-credit" | map(([.name, .joinphrase]|join(""))) | join("")')" - mb_releasegroup_releases "$2" | - $JQ -r '."releases"[] | [ - .id, - .status, - .date, - ."cover-art-archive".count, - (."label-info" | map(.label.name) | unique | join(", ")), - (.media | map(."track-count") | add), - (.media | map(.format) | unique | join(", ")), - .country, - .title, - (."artist-credit" | map(([.name, .joinphrase]|join(""))) | join("")) - ] | join("\t")' | - awk \ - -F "\t" \ - -v file_local_releases="${LOCALDATA_RELEASES:-}" \ - -v release_official="$FORMAT_STATUS_OFFICIAL" \ - -v release_promotion="$FORMAT_STATUS_PROMO" \ - -v release_bootleg="$FORMAT_STATUS_BOOTLEG" \ - -v release_pseudo="$FORMAT_STATUS_PSEUDO" \ - -v release_withdrawn="$FORMAT_STATUS_WITHDRAWN" \ - -v release_expunged="$FORMAT_STATUS_EXPUNGED" \ - -v release_cancelled="$FORMAT_STATUS_CANCELLED" \ - -v release_format="$RV_FORMAT" \ - -v release_format_title_artist="$RV_TITLE_ARTIST" \ - -v release_format_title="$RV_TITLE" \ - -v release_format_artist="$RV_ARTIST" \ - -v rg_artist="$artist" \ - -v rg_title="$title" \ - -v format_local="$FORMAT_LOCAL" \ - "$AWK_RELEASES" | - sort -n -r | - cut -d "$(printf '\t')" -f 2- | - column -t -s "$(printf '\t')" | - sed 's| \+\([0-9a-f-]\+\):\(.*$\)$|\t\1\t\2|' - exit 0 -fi - -if [ "${1:-}" = "--internal-list-recordings" ]; then - deco="$(grep "$2" "$LOCALDATA_RELEASES" | cut -d "$(printf '\t')" -f 2)" - if [ "$deco" ]; then - base="$(dirname "$deco")" - rectmp=$(mktemp) - $JQ -r --arg base "$base/" '.tracks | to_entries | map(.key + "\t" + $base + .value) | join("\n")' "$deco" >"$rectmp" - fi - mb_release "$2" | - $JQ -r '.media[] | +generate_playlist() { + dir="$(dirname "$2")" + mb_release "$1" | + $JQ -r --slurpfile deco "$2" --arg base "$dir" '$deco[].tracks as $filenames | + .media[] | .position as $pos | - .tracks[] | [ - .id, + .tracks | + map({ $pos, - .number, - .length, - .recording.title, - (.recording."artist-credit" | map([.name, .joinphrase] | join("")) | join("")) - ] | - join("\t")' | - awk \ - -F "\t" \ - -v file_local_recordings="${rectmp:-}" \ - -v format="$REC_FORMAT" \ - -v format_local="$FORMAT_LOCAL" \ - "$AWK_RECORDINGS" | - sort -k1,1n -k2,2g | - cut -d "$(printf '\t')" -f 2- | - column -t -s "$(printf '\t')" -R 2,3,6 | - sed 's| \+\([0-9a-f-]\+\):\(.*$\)$|\t\1\t\2|' - if [ "${rectmp:-}" ] && [ -f "$rectmp" ]; then - rm -f "$rectmp" + number: .number, + file: $filenames[.id] + }) | + map( + if(.number | type == "string" and test("^[0-9]+$")) then + .number |= tonumber + else + . + end + ) | + sort_by([.pos, .number]) | + map($base + "/" + .file)[]' +} + +if [ "${1:-}" = "--fzf-key" ]; then + mbid="${2:-}" + path="${3:-}" + mode=$(cut -d "#" -f 1 "$MODEFILE") + args=$(cut -d "#" -f 2- "$MODEFILE") + if [ "$FZF_KEY" = "enter" ] && [ "$path" ]; then + case "$mode" in + "$MODE_RELEASEGROUP") + generate_playlist "$mbid" "$path" >"$tmplist" + mpv_play_list "$tmplist" >/dev/null + rm -f "$tmplist" + ;; + "$MODE_RELEASE") + mpv_play_file "$path" >/dev/null + ;; + esac + elif [ "$FZF_KEY" = "alt-enter" ] && [ "$path" ]; then + case "$mode" in + "$MODE_RELEASEGROUP") + generate_playlist "$mbid" "$path" >"$tmplist" + mpv_queue_list "$tmplist" >/dev/null + rm -f "$tmplist" + ;; + "$MODE_RELEASE") + mpv_queue_file "$path" >/dev/null + ;; + esac + elif [ "$FZF_KEY" = "alt-space" ]; then + mpv_toggle_pause >/dev/null + elif [ "$FZF_KEY" = "ctrl-n" ] && [ "$path" ]; then + mpv_next >/dev/null + elif [ "$FZF_KEY" = "ctrl-p" ] && [ "$path" ]; then + mpv_prev >/dev/null + elif [ "$FZF_KEY" = "shift-right" ] && [ "$path" ]; then + mpv_seek_forward >/dev/null + elif [ "$FZF_KEY" = "shift-left" ] && [ "$path" ]; then + mpv_seek_backward >/dev/null + elif [ "$FZF_KEY" = "ctrl-d" ]; then + printf "half-page-down" + elif [ "$FZF_KEY" = "down" ]; then + printf "preview-half-page-down" + elif [ "$FZF_KEY" = "up" ]; then + printf "preview-half-page-up" + elif [ "$FZF_KEY" = "ctrl-u" ]; then + printf "half-page-up" + elif [ "$FZF_KEY" = "alt-l" ]; then + case "$mode" in + "$MODE_SEARCH_ARTIST" | "$MODE_SEARCH_ALBUM") ;; + *) QUERY="$FORMAT_LOCAL " ;; + esac + elif [ "$FZF_KEY" = "tab" ]; then + case "$mode" in + "$MODE_SEARCH_ARTIST") MODE_NEXT="$MODE_SEARCH_ALBUM" ;; + "$MODE_SEARCH_ALBUM") MODE_NEXT="$MODE_SEARCH_ARTIST" ;; + "$MODE_LIST_ARTISTS") MODE_NEXT="$MODE_LIST_ALBUMS" ;; + "$MODE_LIST_ALBUMS") MODE_NEXT="$MODE_LIST_ARTISTS" ;; + esac + elif [ "$FZF_KEY" = "ctrl-/" ]; then + case "$mode" in + "$MODE_SEARCH_ARTIST") MODE_NEXT="$MODE_LIST_ARTISTS" ;; + "$MODE_SEARCH_ALBUM") MODE_NEXT="$MODE_LIST_ALBUMS" ;; + "$MODE_LIST_ARTISTS") MODE_NEXT="$MODE_SEARCH_ARTIST" ;; + "$MODE_LIST_ALBUMS") MODE_NEXT="$MODE_SEARCH_ALBUM" ;; + esac + elif [ "$FZF_KEY" = "alt-b" ] && [ "$mbid" ]; then + case "$mode" in + "$MODE_ARTIST") urltype="release-group" ;; + "$MODE_RELEASEGROUP") urltype="release" ;; + "$MODE_RELEASE") urltype="track" ;; + esac + printf "esecute-silent(xdg-open \"https://musicbrainz.org/%s/%s\" &)" "$urltype" "$mbid" + elif [ "$FZF_KEY" = "ctrl-h" ]; then + case "$mode" in + "$MODE_ARTIST") + MODE_NEXT="$MODE_LIST_ARTISTS" + ;; + "$MODE_RELEASEGROUP") + MODE_NEXT="$MODE_SELECT_ARTIST" + MODE_NEXT_ARGS="$(mb_releasegroup "$args" | $JQ -r --compact-output '."artist-credit"')" + ;; + "$MODE_RELEASE") + MODE_NEXT="$MODE_RELEASEGROUP" + MODE_NEXT_ARGS="$(mb_release "$args" | $JQ -r --compact-output '."release-group".id')" + ;; + esac + elif [ "$FZF_KEY" = "ctrl-l" ] && [ "$mbid" ]; then + MODE_NEXT_ARGS="$mbid" + case "$mode" in + "$MODE_LIST_ARTISTS" | "$MODE_SEARCH_ARTIST") + MODE_NEXT="$MODE_ARTIST" + ;; + "$MODE_ARTIST") + MODE_NEXT="$MODE_RELEASEGROUP" + ;; + "$MODE_RELEASEGROUP" | "$MODE_LIST_ALBUMS" | "$MODE_SEARCH_ALBUM") + MODE_NEXT="$MODE_RELEASE" + ;; + esac + elif [ "$FZF_KEY" = "ctrl-a" ] && [ "$mbid" ]; then + case "$mode" in + "$MODE_ARTIST" | "$MODE_SEARCH_ARTIST" | "$MODE_LIST_ARTISTS") + MODE_NEXT_ARGS="$(mb_releasegroup "$mbid" | $JQ -r --compact-output '."artist-credit"')" + ;; + "$MODE_RELEASEGROUP" | "$MODE_SEARCH_ALBUM" | "$MODE_LIST_ALBUMS") + MODE_NEXT_ARGS="$(mb_release "$mbid" | $JQ -r --compact-output '."artist-credit"')" + ;; + "$MODE_RELEASE") + MODE_NEXT_ARGS="$(mb_release "$args" | $JQ -r --compact-output '."artist-credit"')" + ;; + esac + [ "$MODE_NEXT_ARGS" ] && MODE_NEXT="$MODE_SELECT_ARTIST" + else + # View specific commands + case "$mode" in + "$MODE_ARTIST") + case "$FZF_KEY" in + "alt-1") + secsymb="$(printf "$FORMAT_TYPE_HAS_SECONDARY" "")" + QUERY="!$secsymb " + ;; + "alt-2") + secsymb="$(printf "$FORMAT_TYPE_HAS_SECONDARY" "")" + QUERY="$secsymb " + ;; + esac + ;; + esac + fi + [ "${QUERY:-}" ] && printf "+change-query(%s)" "$QUERY" + if [ "$MODE_NEXT" ]; then + printf "%s#%s" "$MODE_NEXT" "${MODE_NEXT_ARGS:-}" >"$MODEFILE" + printf "+clear-query+reload:%s" "$0 --fzf-reload" fi exit 0 fi -if [ "${1:-}" = "--internal-list-local-artists" ]; then - cat "$LOCALDATA_ARTISTS_VIEW" 2>/dev/null +# Support of local music files +if [ "${1:-}" = "--decorate" ]; then + [ ! "${2:-}" ] && err "You did not specify a directory." && exit 1 + [ ! -d "$2" ] && err "Path $2 does not point to a directory." && exit 1 + if ! decorate "$2"; then + err "Something went wrong. Are you're files tagged correctly?" + exit 1 + fi exit 0 fi -if [ "${1:-}" = "--internal-list-local-releasegroups" ]; then - cat "$LOCALDATA_RELEASEGROUPS_VIEW" 2>/dev/null +if [ "${1:-}" = "--reload" ]; then + [ ! "${2:-}" ] && err "Path to decorated music is missing." && exit 1 + [ ! -d "$2" ] && err "Path does not point to a directory." && exit 1 + info "Reloading information of local music directory $2" + load_local "$2" || err "Failed to load local data" + info "Done" exit 0 fi -if [ "${1:-}" = "--internal-list-local-releases" ]; then - cat "$LOCALDATA_RELEASES_VIEW" 2>/dev/null +if [ "${1:-}" = "--internal-preview-artist" ]; then + __preview_artist "$2" exit 0 fi @@ -398,8 +446,9 @@ tmpdir=$(mktemp -d) LOCKFILE="$tmpdir/lock" RESULTS="$tmpdir/results" PIDFILE="$tmpdir/pid" +MODEFILE="$tmpdir/mode" trap 'rm -rf "$tmpdir"' EXIT INT -export LOCKFILE RESULTS PIDFILE +export LOCKFILE RESULTS PIDFILE MODEFILE if [ "${1:-}" = "--ni-search-artist" ]; then $0 --internal-search "artist" "$2" @@ -411,10 +460,45 @@ if [ "${1:-}" = "--ni-search-album" ]; then exit 0 fi +# Modes +MODE_ARTIST="artist" +MODE_RELEASEGROUP="rg" +MODE_RELEASE="release" +MODE_SEARCH_ARTIST="search-artist" +MODE_SEARCH_ALBUM="search-album" +MODE_LIST_ARTISTS="list-artists" +MODE_LIST_ALBUMS="list-albums" +MODE_SELECT_ARTIST="select-artist" +export MODE_ARTIST MODE_RELEASEGROUP MODE_RELEASE MODE_SEARCH_ARTIST \ + MODE_SEARCH_ALBUM MODE_LIST_ARTISTS MODE_LIST_ALBUMS MODE_SELECT_ARTIST + case "${1:-}" in -"" | "--artist" | "--releasegroup" | "--release" | "--search-artist" | "--search-album" | "--albums" | "--artists") ;; +"--artist") + [ ! "${2:-}" ] && err "MusicBrainz Artist ID not specified (see --help)" && exit 1 + printf "%s#%s" "$MODE_ARTIST" "$2" >"$MODEFILE" + ;; +"--releasegroup") + [ ! "${2:-}" ] && err "MusicBrainz Release-Group ID not specified (see --help)" && exit 1 + printf "%s#%s" "$MODE_RELEASEGROUP" "$2" >"$MODEFILE" + ;; +"--release") + [ ! "${2:-}" ] && err "MusicBrainz Release ID not specified (see --help)" && exit 1 + printf "%s#%s" "$MODE_RELEASE" "$2" >"$MODEFILE" + ;; +"--search-artist") + printf "%s#%s" "$MODE_SEARCH_ARTIST" "${2:-}" >"$MODEFILE" + ;; +"--search-album") + printf "%s#%s" "$MODE_SEARCH_ALBUM" "${2:-}" >"$MODEFILE" + ;; +"--artists" | "") + printf "%s" "$MODE_LIST_ARTISTS" >"$MODEFILE" + ;; +"--albums") + printf "%s" "$MODE_LIST_ALBUMS" >"$MODEFILE" + ;; *) - err "Unknown option $1" + err "Unknown option $1 (see --help)" exit 1 ;; esac @@ -422,39 +506,39 @@ esac # Start mpv mpv_start +$FZF \ + --bind="start:reload:$0 --fzf-reload" \ + --bind="load:transform:$0 --fzf-load" \ + --bind="change:execute-silent($0 --fzf-change &)+reload:$0 --fzf-change-reload" \ + --bind="ctrl-d:transform:$0 --fzf-key" \ + --bind="ctrl-u:transform:$0 --fzf-key" \ + --bind="alt-b:transform:$0 --fzf-key {2}" \ + --bind="ctrl-h:transform:$0 --fzf-key {2}" \ + --bind="ctrl-l:transform:$0 --fzf-key {2}" \ + --bind="ctrl-a:transform:$0 --fzf-key {2}" \ + --bind="alt-l:transform:$0 --fzf-key" \ + --bind="alt-1:transform:$0 --fzf-key" \ + --bind="alt-2:transform:$0 --fzf-key" \ + --bind="tab:transform:$0 --fzf-key" \ + --bind="ctrl-/:transform:$0 --fzf-key" \ + --bind="enter:transform:$0 --fzf-key {2} {3}" \ + --bind="alt-enter:transform:$0 --fzf-key {2} {3}" \ + --bind="alt-space:transform:$0 --fzf-key" \ + --bind="alt-space:transform:$0 --fzf-key" \ + --bind="ctrl-n:transform:$0 --fzf-key" \ + --bind="ctrl-p:transform:$0 --fzf-key" \ + --bind="shift-right:transform:$0 --fzf-key" \ + --bind="shift-left:transform:$0 --fzf-key" \ + --info="inline-right" \ + --info-command="$0 --fzf-info" \ + --preview-window="right,25%,border-left,wrap,<30(hidden)" \ + --preview="$0 --internal-preview-artist {2}" \ + --delimiter="\t" \ + --with-nth="{1}" \ + --accept-nth="{2}" + while true; do case "${1:-}" in - "--artist") - name="$(mb_artist "$2" | $JQ -r '.name')" - secsymb="$(printf "$FORMAT_TYPE_HAS_SECONDARY" "")" - sel=$( - $0 --internal-list-releasegroups "$2" | - $FZF \ - --no-clear \ - --ansi \ - --reverse \ - --cycle \ - --no-sort \ - --query="!$secsymb " \ - --delimiter="\t" \ - --prompt="$(printf "$ARTIST_PROMPT" "$name")" \ - --accept-nth="{2}" \ - --with-nth="{1}" \ - --expect="ctrl-h,ctrl-a" \ - --bind="alt-l:change-query($FORMAT_LOCAL )" \ - --bind="load:unbind(enter)+unbind(alt-enter)+transform:[ \"\$FZF_TOTAL_COUNT\" -gt 0 ] && echo \"rebind:ctrl-l\" || echo \"unbind:ctrl-l)\"" \ - --bind="ctrl-l:accept" \ - --bind="alt-b:execute-silent:xdg-open 'https://musicbrainz.org/release-group/{r2}' &" \ - --bind="alt-1:change-query(!$secsymb ),alt-2:change-query($secsymb )" \ - --bind="ctrl-d:half-page-down,ctrl-u:half-page-up" - ) - lns=$(echo "$sel" | wc -l) - key=$(echo "$sel" | head -1 | tail -1) - mid=$(echo "$sel" | head -2 | tail -1) - [ "$lns" -eq 2 ] && [ ! "$key" ] && [ "$mid" ] && set -- "--releasegroup" "$mid" - [ "$lns" -eq 2 ] && [ "$key" = "ctrl-h" ] && set -- "" - [ "$lns" -eq 2 ] && [ "$key" = "ctrl-a" ] && set -- "--select-artist" "$(mb_releasegroup "$mid" | $JQ -r '."artist-credit"')" - ;; "--releasegroup") title="$(mb_releasegroup "$2" | $JQ -r '.title')" diff --git a/src/sh/helper.sh b/src/sh/helper.sh index 6763a8b..4574730 100644 --- a/src/sh/helper.sh +++ b/src/sh/helper.sh @@ -13,3 +13,7 @@ info() { debug() { echo "${DBG}DEBUG${OFF} ${INFO}$(date)${OFF}: $*" >/dev/stderr } + +foo() { + echo "${DBG}DEBUG${OFF} ${INFO} [$$] $(date)${OFF}: $*" >>/tmp/foo +} diff --git a/src/sh/lists.sh b/src/sh/lists.sh new file mode 100644 index 0000000..8d86194 --- /dev/null +++ b/src/sh/lists.sh @@ -0,0 +1,141 @@ +# List release groups of given artist +# argument $1: MB artist id +list_releasegroups() { + name=$(mb_artist "$1" | $JQ -r '.name') + mb_artist_releasegroups "$1" | + $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 artist="$name" \ + -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" | + sort -n -r | + cut -d "$(printf '\t')" -f 2- | + column -t -s "$(printf '\t')" | + sed 's| \+\([0-9a-f-]\+\)$|\t\1|' +} + +# List releases in given relese group +# argument $1: MB release-group id +list_releases() { + title="$(mb_releasegroup "$1" | + $JQ -r '.title')" + artist="$(mb_releasegroup "$1" | + $JQ -r '."artist-credit" | map(([.name, .joinphrase]|join(""))) | join("")')" + mb_releasegroup_releases "$1" | + $JQ -r '."releases"[] | [ + .id, + .status, + .date, + ."cover-art-archive".count, + (."label-info" | map(.label.name) | unique | join(", ")), + (.media | map(."track-count") | add), + (.media | map(.format) | unique | join(", ")), + .country, + .title, + (."artist-credit" | map(([.name, .joinphrase]|join(""))) | join("")) + ] | join("\t")' | + awk \ + -F "\t" \ + -v file_local_releases="${LOCALDATA_RELEASES:-}" \ + -v release_official="$FORMAT_STATUS_OFFICIAL" \ + -v release_promotion="$FORMAT_STATUS_PROMO" \ + -v release_bootleg="$FORMAT_STATUS_BOOTLEG" \ + -v release_pseudo="$FORMAT_STATUS_PSEUDO" \ + -v release_withdrawn="$FORMAT_STATUS_WITHDRAWN" \ + -v release_expunged="$FORMAT_STATUS_EXPUNGED" \ + -v release_cancelled="$FORMAT_STATUS_CANCELLED" \ + -v release_format="$RV_FORMAT" \ + -v release_format_title_artist="$RV_TITLE_ARTIST" \ + -v release_format_title="$RV_TITLE" \ + -v release_format_artist="$RV_ARTIST" \ + -v rg_artist="$artist" \ + -v rg_title="$title" \ + -v format_local="$FORMAT_LOCAL" \ + "$AWK_RELEASES" | + sort -n -r | + cut -d "$(printf '\t')" -f 2- | + column -t -s "$(printf '\t')" | + sed 's| \+\([0-9a-f-]\+\):\(.*$\)$|\t\1\t\2|' +} + +# List recordings of given release +# argument $1: MB release id +list_recordings() { + deco="$(grep "$1" "$LOCALDATA_RELEASES" | cut -d "$(printf '\t')" -f 2)" + if [ "$deco" ]; then + base="$(dirname "$deco")" + rectmp=$(mktemp) + $JQ -r --arg base "$base/" '.tracks | to_entries | map(.key + "\t" + $base + .value) | join("\n")' "$deco" >"$rectmp" + fi + mb_release "$1" | + $JQ -r '.media[] | + .position as $pos | + .tracks[] | [ + .id, + $pos, + .number, + .length, + .recording.title, + (.recording."artist-credit" | map([.name, .joinphrase] | join("")) | join("")) + ] | + join("\t")' | + awk \ + -F "\t" \ + -v file_local_recordings="${rectmp:-}" \ + -v format="$REC_FORMAT" \ + -v format_local="$FORMAT_LOCAL" \ + "$AWK_RECORDINGS" | + sort -k1,1n -k2,2g | + cut -d "$(printf '\t')" -f 2- | + column -t -s "$(printf '\t')" -R 2,3,6 | + sed 's| \+\([0-9a-f-]\+\):\(.*$\)$|\t\1\t\2|' + if [ "${rectmp:-}" ] && [ -f "$rectmp" ]; then + rm -f "$rectmp" + fi +} + +# List artists (local) +list_local_artists() { + cat "$LOCALDATA_ARTISTS_VIEW" 2>/dev/null +} + +# List release groups (local) +list_local_releasegroups() { + cat "$LOCALDATA_RELEASEGROUPS_VIEW" 2>/dev/null +} + +# List releases (local) +list_local_releases() { + cat "$LOCALDATA_RELEASES_VIEW" 2>/dev/null +} diff --git a/src/sh/local.sh b/src/sh/local.sh index 1180cca..c57403d 100644 --- a/src/sh/local.sh +++ b/src/sh/local.sh @@ -194,7 +194,7 @@ load_local() { column -t -s "$(printf '\t')" | sed 's| \+\([0-9a-f-]\+\)$|\t\1|' >"$LOCALDATA_RELEASEGROUPS_VIEW" info "Precomputing release view" - list_releases | + cut -d "$(printf '\t')" -f 1 "$LOCALDATA_RELEASES" | while IFS= read -r rid; do mb_release "$rid" | $JQ -r '[ .id, @@ -230,18 +230,3 @@ load_local() { column -t -s "$(printf '\t')" | sed 's| \+\([0-9a-f-]\+\):\(.*$\)$|\t\1\t\2|' >"$LOCALDATA_RELEASES_VIEW" } - -# List all releases -list_releases() { - cut -d "$(printf '\t')" -f 1 "$LOCALDATA_RELEASES" -} - -# List all release groups -list_releasegroups() { - cat "$LOCALDATA_RELEASEGROUPS" -} - -# List all album artists -list_artists() { - cat "$LOCALDATA_ARTISTS" -} diff --git a/src/sh/theme.sh b/src/sh/theme.sh index af9cf8b..4d6a016 100644 --- a/src/sh/theme.sh +++ b/src/sh/theme.sh @@ -11,6 +11,7 @@ CLIFE="\033[38;5;251m" OFF="\033[m" FORMAT_LOCAL="${FORMAT_LOCAL:-"🔆"}" +export FORMAT_LOCAL # Prompts SEARCH_PROMPT=${SEARCH_PROMPT:-"🔎 〉"} diff --git a/src/sh/tools.sh b/src/sh/tools.sh index f847526..55b83b8 100644 --- a/src/sh/tools.sh +++ b/src/sh/tools.sh @@ -1,5 +1,5 @@ if command -v "fzf" >/dev/null; then - FZF="fzf --black" + FZF="fzf --black --ansi --reverse --cycle" else err "Did not find the command-line fuzzy finder fzf." exit 1