#!/bin/sh set -eu # Load helper methods . "sh/info.sh" # Load helper methods . "sh/helper.sh" # Load configuration . "sh/config.sh" # Load theme . "sh/theme.sh" # Load AWK scripts . "sh/awk.sh" # Load tools . "sh/tools.sh" # Load MusicBrainz and Discogs methods . "sh/api.sh" # Load preview methods . "sh/preview.sh" # Load cache functionality . "sh/cache.sh" # Load MusicBrainz wrappers . "sh/mb.sh" # Load local file handling . "sh/local.sh" # Support of local music files if [ "${MUSICDIR:-}" ]; then 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:-}" = "--load-local" ]; then load_local exit 0 fi if [ "${1:-}" = "--list-releases" ]; then list_releases exit 0 fi if [ "${1:-}" = "--list-releasegroups" ]; then list_releasegroups exit 0 fi if [ "${1:-}" = "--list-artists" ]; then list_artists exit 0 fi fi if [ "${1:-}" = "--internal-preview-artist" ]; then __preview_artist "$2" exit 0 fi if [ "${1:-}" = "--internal-reload" ]; then sleep 1 while [ -f "$LOCKFILE" ]; do sleep 1 done cat "$RESULTS" exit 0 fi if [ "${1:-}" = "--internal-search" ]; then printf "" >"$RESULTS" 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 echo "$$" >"$PIDFILE" touch "$LOCKFILE" sleep 1 if [ "$2" = "artist" ]; then api_mb_search_artist "$3" | $JQ -r '.artists[] | [ .id, .type, .name, .disambiguation, .["life-span"].begin, .["life-span"].end ] | join("\t")' | awk \ -F "\t" \ -v format_person="$AV_PERSON" \ -v format_group="$AV_GROUP" \ -v format_disambiguation="$AV_DISAMBIGUATION" \ "$AWK_ARTISTS" | tee "$RESULTS" || true else api_mb_search_releasegroup "$3" | $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 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" \ "$AWK_RELEASEGROUPS" | cut -d "$(printf '\t')" -f 2- | column -t -s "$(printf '\t')" | sed 's| \+\([0-9a-f-]\+\)$|\t\1|' | tee "$RESULTS" || true fi 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 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" \ "$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 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" \ "$AWK_RELEASES" | 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-recordings" ]; then mb_release "$2" | $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 format="$REC_FORMAT" \ "$AWK_RECORDINGS" | sort -k1,1n -k2,2g | cut -d "$(printf '\t')" -f 2- | column -t -s "$(printf '\t')" -R 1,2,5 | sed 's| \+\([0-9a-f-]\+\)$|\t\1|' exit 0 fi if [ "${1:-}" = "--internal-list-local-artists" ]; then while IFS= read -r aid; do mb_artist "$aid" | $JQ -r '[ .id, .type, .name, .disambiguation, .["life-span"].begin, .["life-span"].end ] | join("\t")' done <"$LOCALDATA_ARTISTS" | awk \ -F "\t" \ -v format_person="$AV_PERSON" \ -v format_group="$AV_GROUP" \ -v format_disambiguation="$AV_DISAMBIGUATION" \ "$AWK_ARTISTS" exit 0 fi if [ "${1:-}" = "--internal-list-local-releasegroups" ]; then while IFS= read -r rgid; do mb_releasegroup "$rgid" | $JQ -r '[ .id, ."primary-type", (."secondary-types" // []|join(";")), ."first-release-date", .title, (."artist-credit" | map(([.name, .joinphrase]|join(""))) | join("")) ] | join("\t")' done <"$LOCALDATA_RELEASEGROUPS" | awk \ -F "\t" \ -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" \ "$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-local-releases" ]; then while IFS= read -r rid; do mb_release "$rid" | $JQ -r '[ .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")' done <"$LOCALDATA_RELEASES" | awk \ -F "\t" \ -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" \ "$AWK_RELEASES" | 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:-}" = "--help" ]; then cat < | --releasegroup | --release ] EOF exit 0 fi # Set window title printf '\033]0;%s\007' "$WINDOW_TITLE" # Generate filenames for temporary files tmpdir=$(mktemp -d) LOCKFILE="$tmpdir/lock" RESULTS="$tmpdir/results" PIDFILE="$tmpdir/pid" trap 'rm -rf "$tmpdir"' EXIT INT export LOCKFILE RESULTS PIDFILE if [ "${1:-}" = "--search" ]; then $0 --internal-search "$2" "$3" exit 0 fi 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="load: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')" artist="$(mb_releasegroup "$2" | $JQ -r '."artist-credit" | map(([.name, .joinphrase]|join(""))) | join("")')" sel=$( $0 --internal-list-releases "$2" | $FZF \ --no-clear \ --ansi \ --reverse \ --cycle \ --no-sort \ --query="$FORMAT_STATUS_OFFICIAL " \ --delimiter="\t" \ --prompt="$(printf "$FULL_PROMPT" "$artist" "$title")" \ --accept-nth="{2}" \ --with-nth="{1}" \ --expect="ctrl-h,ctrl-a" \ --bind="load: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/{r2}' &" \ --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 -- "--release" "$mid" [ "$lns" -eq 2 ] && [ "$key" = "ctrl-h" ] && set -- "--select-artist" "$(mb_releasegroup "$2" | $JQ -r '."artist-credit"')" [ "$lns" -eq 2 ] && [ "$key" = "ctrl-a" ] && set -- "--select-artist" "$(mb_release "$mid" | $JQ -r '."artist-credit"')" ;; "--release") title="$(mb_release "$2" | $JQ -r '.title')" artist="$(mb_release "$2" | $JQ -r '."artist-credit" | map(([.name, .joinphrase]|join(""))) | join("")')" sel=$( $0 --internal-list-recordings "$2" | $FZF \ --no-clear \ --ansi \ --reverse \ --cycle \ --no-sort \ --delimiter="\t" \ --prompt="$(printf "$FULL_PROMPT" "$artist" "$title")" \ --accept-nth="{2}" \ --with-nth="{1}" \ --expect="ctrl-h,ctrl-a" \ --bind="alt-b:execute-silent:xdg-open 'https://musicbrainz.org/track/{r2}' &" \ --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" = "ctrl-h" ] && set -- "--releasegroup" "$(mb_release "$2" | $JQ -r '."release-group".id')" [ "$lns" -eq 2 ] && [ "$key" = "ctrl-a" ] && set -- "--select-artist" "$(mb_release "$2" | $JQ -r ".media[].tracks[] | select(.id==\"$mid\") | .\"artist-credit\"")" ;; "--select-artist") tput rmcup sel=$( echo "$2" | $JQ -r 'map([.artist.id, .artist.type, .name] | join("\t")) | join("\n")' | awk \ -F "\t" \ -v format_person="$AV_PERSON" \ -v format_group="$AV_GROUP" \ -v format_disambiguation="$AV_DISAMBIGUATION" \ "$AWK_ARTISTS" | $FZF \ --no-clear \ -1 \ --ansi \ --cycle \ --no-sort \ --border="bold" \ --border-label="Select artist" \ --delimiter="\t" \ --prompt="$SEARCH_PROMPT" \ --margin="5%,20%" \ --accept-nth="{2}" \ --with-nth="{1}" ) [ "$sel" ] && set -- "--artist" "$sel" ;; "--search-releasegroup") sel=$( printf "" | $FZF \ --no-clear \ --ansi \ --reverse \ --no-sort \ --disabled \ --cycle \ --delimiter="\t" \ --prompt="$SEARCH_PROMPT" \ --info="inline-right" \ --info-command="echo \"Search album\"" \ --accept-nth="{2}" \ --with-nth="{1}" \ --expect="ctrl-c,ctrl-q,tab" \ --bind="load:transform:[ \"\$FZF_TOTAL_COUNT\" -gt 0 ] && echo \"rebind:ctrl-l\" || echo \"unbind:ctrl-l\"" \ --bind="ctrl-l:accept" \ --bind="ctrl-d:half-page-down,ctrl-u:half-page-up" \ --bind="alt-b:execute-silent:xdg-open 'https://musicbrainz.org/release-group/{r2}' &" \ --bind="change:execute-silent($0 --internal-search releasegroup \$FZF_QUERY &)+reload($0 --internal-reload)" || true ) lns=$(echo "$sel" | wc -l) key=$(echo "$sel" | head -1 | tail -1) mid=$(echo "$sel" | head -2 | tail -1) [ "$key" = "ctrl-c" ] && tput rmcup && exit 0 [ "$key" = "ctrl-q" ] && tput rmcup && exit 0 [ "$key" = "tab" ] && set -- "--search-artist" [ "$lns" -eq 2 ] && [ ! "$key" ] && [ "$mid" ] && set -- "--releasegroup" "$mid" ;; "--artists") sel=$( printf "" | $FZF \ --no-clear \ --ansi \ --reverse \ --no-sort \ --disabled \ --cycle \ --delimiter="\t" \ --prompt="$SEARCH_PROMPT" \ --info="inline-right" \ --info-command="echo \"Search music artist\"" \ --accept-nth="{2}" \ --with-nth="{1}" \ --preview-window="right,25%,border-left,wrap,<30(hidden)" \ --preview="$0 --internal-preview-artist {2}" \ --expect="ctrl-c,ctrl-q,tab" \ --bind="load:transform:[ \"\$FZF_TOTAL_COUNT\" -gt 0 ] && echo \"rebind:ctrl-l\" || echo \"unbind:ctrl-l\"" \ --bind="ctrl-l:accept" \ --bind="ctrl-d:half-page-down,ctrl-u:half-page-up" \ --bind="down:preview-half-page-down,up:preview-half-page-up" \ --bind="alt-b:execute-silent:xdg-open 'https://musicbrainz.org/artist/{r2}' &" \ --bind="change:execute-silent($0 --internal-search artist \$FZF_QUERY &)+reload($0 --internal-reload)" || true ) lns=$(echo "$sel" | wc -l) key=$(echo "$sel" | head -1 | tail -1) mid=$(echo "$sel" | head -2 | tail -1) [ "$key" = "ctrl-c" ] && tput rmcup && exit 0 [ "$key" = "ctrl-q" ] && tput rmcup && exit 0 [ "$key" = "tab" ] && set -- "--search-releasegroup" [ "$lns" -eq 2 ] && [ ! "$key" ] && [ "$mid" ] && set -- "--artist" "$mid" ;; *) sel=$( printf "" | $FZF \ --no-clear \ --ansi \ --reverse \ --no-sort \ --disabled \ --cycle \ --delimiter="\t" \ --prompt="$SEARCH_PROMPT" \ --info="inline-right" \ --info-command="echo \"Search music artist\"" \ --accept-nth="{2}" \ --with-nth="{1}" \ --preview-window="right,25%,border-left,wrap,<30(hidden)" \ --preview="$0 --internal-preview-artist {2}" \ --expect="ctrl-c,ctrl-q,tab" \ --bind="load:transform:[ \"\$FZF_TOTAL_COUNT\" -gt 0 ] && echo \"rebind:ctrl-l\" || echo \"unbind:ctrl-l\"" \ --bind="ctrl-l:accept" \ --bind="ctrl-d:half-page-down,ctrl-u:half-page-up" \ --bind="down:preview-half-page-down,up:preview-half-page-up" \ --bind="alt-b:execute-silent:xdg-open 'https://musicbrainz.org/artist/{r2}' &" \ --bind="change:execute-silent($0 --internal-search artist \$FZF_QUERY &)+reload($0 --internal-reload)" || true ) lns=$(echo "$sel" | wc -l) key=$(echo "$sel" | head -1 | tail -1) mid=$(echo "$sel" | head -2 | tail -1) [ "$key" = "ctrl-c" ] && tput rmcup && exit 0 [ "$key" = "ctrl-q" ] && tput rmcup && exit 0 [ "$key" = "tab" ] && set -- "--search-releasegroup" [ "$lns" -eq 2 ] && [ ! "$key" ] && [ "$mid" ] && set -- "--artist" "$mid" ;; esac done