From f3c58ca859ebc465b40d71d14677e31f1c521632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=84min=20Baumeler?= Date: Wed, 23 Jul 2025 20:51:22 +0200 Subject: [PATCH] rg caching, improved display --- src/awk/releasegroups.awk | 12 ++++++--- src/main.sh | 11 +++++++-- src/sh/api.sh | 5 +++- src/sh/cache.sh | 24 ++++++++++++++++++ src/sh/mb.sh | 51 ++++++++++++++++++++++++--------------- src/sh/theme.sh | 48 ++++++++++++++++-------------------- 6 files changed, 98 insertions(+), 53 deletions(-) diff --git a/src/awk/releasegroups.awk b/src/awk/releasegroups.awk index 3b90dfc..13389e0 100644 --- a/src/awk/releasegroups.awk +++ b/src/awk/releasegroups.awk @@ -17,12 +17,12 @@ BEGIN { OFS="\t" } case "EP": line_type=format_ep; break case "Broadcast": line_type=format_broadcast; break case "Other": line_type=format_other; break - default: line_type="unknown type" + default: line_type="" } split(sectype, a, ";") for (i in a) { t="" - switch (sectype) { + switch (a[i]) { case "Compilation": t=format_compilation; break case "Soundtrack": t=format_soundtrack; break case "Spokenword": t=format_spokenword; break @@ -37,11 +37,15 @@ BEGIN { OFS="\t" } case "Field recording": t=fieldrec; break } if (t) - line_sectype=line_sectype ? line_sectype " / " t : t + line_sectype=line_sectype ? line_sectype ", " t : t + } + if (sectype) { + line_type = sprintf(format_has_secondary, line_type) + line_sectype = sprintf(format_secondary, line_sectype) } sub("<>", title, line_release) line_year = year ? format_year : "" sub("<<year>>", year, line_year) sort = year ? year : 0 - print line_type, line_sectype, line_release, line_year, sort, id + print line_type, line_release, line_year, line_sectype, sort, id } diff --git a/src/main.sh b/src/main.sh index 3c85a6f..43979d0 100755 --- a/src/main.sh +++ b/src/main.sh @@ -84,7 +84,7 @@ if [ "${1:-}" = "--internal-list-releases-fresh" ]; then fi if [ "${1:-}" = "--internal-list-releases" ]; then - __api_mb_browse_release_groups "$2" | + mb_artist_releasegroups "$2" | $JQ -r '."release-groups"[] | [ .id, ."primary-type", @@ -101,6 +101,8 @@ if [ "${1:-}" = "--internal-list-releases" ]; then -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" \ @@ -115,7 +117,7 @@ if [ "${1:-}" = "--internal-list-releases" ]; then -v format_fieldrec="$FORMAT_TYPE_SECONDARY_FIELDREC" \ "$AWK_RELEASEGROUPS" | sort | - sort -t "$(printf '\t')" -k 5 -n -r | + sort -t "$(printf '\t')" -k 4 -n -r | column -t -s "$(printf '\t')" | sed 's| \+[0-9]\+ \+\([0-9a-f-]\+\)$|\t\1|' exit 0 @@ -152,16 +154,20 @@ while true; do case "${1:-}" in "--show-artist") name=$(mb_artist "$2" | $JQ -r '.name') + secsymb=$(printf "$FORMAT_TYPE_HAS_SECONDARY" "") sel=$( $0 --internal-list-releases "$2" | $FZF \ --ansi \ --reverse \ --cycle \ + --query="!$secsymb " \ --delimiter="\t" \ --prompt="$(printf "$ARTIST_PROMPT" "$name")" \ --accept-nth="{2}" \ --with-nth="{1}" \ + --bind="alt-1:change-query(!$secsymb ),alt-2:change-query($secsymb )" \ + --bind="ctrl-d:half-page-down,ctrl-u:half-page-up" \ --bind="ctrl-r:reload:$0 --internal-list-releases-fresh \"$2\"" ) [ "$sel" ] && set -- "--show-release" "$sel" @@ -183,6 +189,7 @@ while true; do --with-nth="{2}" \ --preview-window="wrap" \ --preview="$0 --internal-preview-artist {1}" \ + --bind="ctrl-d:half-page-down,ctrl-u:half-page-up" \ --bind="change:execute-silent($0 --internal-search \$FZF_QUERY &)+reload($0 --internal-reload)" ) [ "$sel" ] && set -- "--show-artist" "$sel" diff --git a/src/sh/api.sh b/src/sh/api.sh index a73d3e5..c06b732 100644 --- a/src/sh/api.sh +++ b/src/sh/api.sh @@ -1,3 +1,6 @@ +MB_BROWSE_STEPS=100 +export MB_BROWSE_STEPS + # Argument: MB Artist ID __api_mb_browse_releases() { $CURL \ @@ -14,7 +17,7 @@ __api_mb_browse_release_groups() { $CURL \ --get \ --data fmt=json \ - --data limit=100 \ + --data limit="$MB_BROWSE_STEPS" \ --data offset="${2:-0}" \ --data-urlencode artist="$1" \ -A "$APP_NAME/$APP_VERSION ($APP_WEBSITE)" \ diff --git a/src/sh/cache.sh b/src/sh/cache.sh index 9192aea..f1a2b24 100644 --- a/src/sh/cache.sh +++ b/src/sh/cache.sh @@ -2,6 +2,7 @@ CACHEDIR="$HOME/.cache/$APP_NAME" [ -d "$CACHEDIR" ] || mkdir "$CACHEDIR" artist_mb_filename="musicbrainz.json" +artist_mb_releasegroups_filename="releasegroups.json" artist_discogs_filename="discogs.json" artist_wikidata_filename="wikidata.json" artist_enwikipedia_filename="enwikipedia.json" @@ -40,6 +41,12 @@ cache_get_artist_mb() { __get_artist_json "$1" "$artist_mb_filename" } +# Returns the cached MusicBrainz release-group data for the artist given by the +# MusicBrainz Artist ID in $1 +cache_get_artist_mb_releasegroups() { + __get_artist_json "$1" "$artist_mb_releasegroups_filename" +} + # Returns the cached Discogs data for the artist given by the MusicBrainz # Artist ID in $1 cache_get_artist_discogs() { @@ -62,6 +69,23 @@ cache_put_artist_mb() { cat | __put_artist_json "$1" "$artist_mb_filename" } +# Read from stdin the MusicBrainz release-group data for the artist given by +# the MusicBrainz Artist ID in $1, and cache it. +cache_put_artist_mb_releasegroups() { + cat | __put_artist_json "$1" "$artist_mb_releasegroups_filename" +} + +# Read from stdin the MusicBrainz release-group data for the artist given by +# the MusicBrainz Artist ID in $1, and append it to the current cache. +cache_append_artist_mb_releasegroups() { + tmpf=$(mktemp) + cat >"$tmpf" + updated=$(mktemp) + f="$CACHEDIR/$1/$artist_mb_releasegroups_filename" + $JQ -r --slurpfile n "$tmpf" '."release-groups" += ($n[0]|."release-groups")' "$f" >"$updated" && mv "$updated" "$f" + rm -f "$tmpf" +} + # Read from stdin the Discogs data for the artist given by the MusicBrainz # Artist ID in $1, and cache it. cache_put_artist_discogs() { diff --git a/src/sh/mb.sh b/src/sh/mb.sh index 82055ed..3756245 100644 --- a/src/sh/mb.sh +++ b/src/sh/mb.sh @@ -1,12 +1,28 @@ # The only IDs uses here are MusicBrainz IDs +# Helper methods to retrieve from cache, if it exists, and otherwise populate +# cache and retrieve __mb_artist_cache_or_fetch() { - mbartist="$(cache_get_artist_mb "$1" || true)" - if [ ! "$mbartist" ]; then + if ! cache_get_artist_mb "$1"; then __api_mb_get_artist "$1" | cache_put_artist_mb "$1" - mbartist="$(cache_get_artist_mb "$1")" + cache_get_artist_mb "$1" + fi +} + +__mb_artist_cache_or_fetch_releasegroups() { + if ! cache_get_artist_mb_releasegroups "$1"; then + __api_mb_browse_release_groups "$1" | cache_put_artist_mb_releasegroups "$1" + rg="$(cache_get_artist_mb_releasegroups "$1")" + total=$(printf "%s" "$rg" | $JQ -r '."release-group-count"') + seen=$MB_BROWSE_STEPS + while [ "$total" -gt "$seen" ]; do + # Fetch remaning release groups, and append to cache + sleep 1 # Make sure we don't get blocked (we prefer not to handle failed requests...) + __api_mb_browse_release_groups "$1" "$seen" | cache_append_artist_mb_releasegroups "$1" + seen=$((seen + MB_BROWSE_STEPS)) + done + cache_get_artist_mb_releasegroups "$1" fi - printf "%s" "$mbartist" } # Get MusicBrainz json for artist @@ -18,8 +34,7 @@ mb_artist() { # Get Wikidata json for artist # @argument $1: MusicBrainz Artist ID mb_artist_wikidata() { - wikidata=$(cache_get_artist_wikidata "$1" || true) - if [ ! "$wikidata" ] || [ "$wikidata" = "null" ]; then + if ! cache_get_artist_wikidata "$1"; then wikidataid=$(mb_artist "$1" | $JQ -r '.relations | map(select(.type=="wikidata")) | @@ -27,17 +42,14 @@ mb_artist_wikidata() { awk -F "/" '{print $NF}') [ ! "$wikidataid" ] || [ "$wikidataid" != "null" ] || return __api_wikidata_get_sitelinks "$wikidataid" | cache_put_artist_wikidata "$1" - wikidata=$(cache_get_artist_wikidata "$1") + cache_get_artist_wikidata "$1" fi - [ ! "$wikidata" ] || [ "$wikidata" != "null" ] || return - printf "%s" "$wikidata" } # Get Wikipedia (English) summary json for artist # @argument $1: MusicBrainz Artist ID mb_artist_enwikipedia() { - enwiki="$(cache_get_artist_enwikipedia "$1" || true)" - if [ ! "$enwiki" ] || [ "$enwiki" = "null" ]; then + if ! cache_get_artist_enwikipedia "$1"; then # To fetch the wikipedia data, we need the wikipedia URL # There are two possibly ways to get the wikipedia URL # 1. From the website relations in MB (MB artists donw have wiki rels) @@ -51,17 +63,14 @@ mb_artist_enwikipedia() { awk -F "/" '{print $NF}') [ ! "$wikiid" ] && return || [ "$wikiid" = "null" ] && return __api_wikipedia_en_get_summary "$wikiid" | cache_put_artist_enwikipedia "$1" - enwiki="$(cache_get_artist_enwikipedia "$1")" + cache_get_artist_enwikipedia "$1" fi - [ ! "$enwiki" ] && return || [ "$enwiki" = "null" ] && return - printf "%s" "$enwiki" } # Get Discogs json for artist # @argument $1: MusicBrainz Artist ID mb_artist_discogs() { - discogs="$(cache_get_artist_discogs "$1" || true)" - if [ ! "$discogs" ] || [ "$discogs" = "null" ]; then + if ! cache_get_artist_discogs "$1"; then discogsid=$(mb_artist "$1" | $JQ -r '.relations | map(select(.type=="discogs")) | @@ -69,8 +78,12 @@ mb_artist_discogs() { awk -F "/" '{print $NF}') [ ! "$discogsid" ] && return || [ "$discogsid" = "null" ] && return __api_discogs_get_artist "$discogsid" | cache_put_artist_discogs "$1" - discogs="$(cache_get_artist_discogs "$1" || true)" + cache_get_artist_discogs "$1" fi - [ ! "$discogs" ] && return || [ "$discogs" = "null" ] && return - printf "%s" "$discogs" +} + +# Get release-groups json for artist +# @argument $1: MusicBrainz Artist ID +mb_artist_releasegroups() { + __mb_artist_cache_or_fetch_releasegroups "$1" } diff --git a/src/sh/theme.sh b/src/sh/theme.sh index 1a589e8..66c624e 100644 --- a/src/sh/theme.sh +++ b/src/sh/theme.sh @@ -4,40 +4,34 @@ COLOR_RESET="\033[m" FORMAT_PERSON="${FORMAT_PERSON:-๐Ÿ‘ค $COLOR_ARTIST<<name>>$COLOR_RESET}" FORMAT_GROUP="${FORMAT_GROUP:-๐Ÿ‘ฅ $COLOR_ARTIST<<name>>$COLOR_RESET}" FORMAT_DISAMBIGUATION="${FORMAT_DISAMBIGUATION:-$COLOR_DISAMBIGUATION(<<disambiguation>>)$COLOR_RESET}" -COLOR_TYPE="\033[38;5;208m" -COLOR_TYPE_SECONDARY="\033[38;5;210m" +COLOR_TYPE="\033[38;5;177m" +COLOR_TYPE_SECONDARY="\033[38;5;242m" COLOR_RELEASE_TITLE="\033[38;5;229m" COLOR_RELEASE_YEAR="\033[38;5;179m" FORMAT_RELEASE="${FORMAT_RELEASE:-"${COLOR_RELEASE_TITLE}<<title>>$COLOR_RESET"}" FORMAT_YEAR="${FORMAT_YEAR:-"${COLOR_RELEASE_YEAR}(<<year>>)${COLOR_RESET}"}" -FORMAT_TYPE_ALBUM="${FORMAT_TYPE_ALBUM:-"๐Ÿ’ฝ ${COLOR_TYPE}LP$COLOR_RESET"}" -FORMAT_TYPE_EP="${FORMAT_TYPE_EP:-"๐Ÿ“€ ${COLOR_TYPE}EP$COLOR_RESET"}" -FORMAT_TYPE_SINGLE="${FORMAT_TYPE_SINGLE:-"๐ŸŽถ ${COLOR_TYPE}single$COLOR_RESET"}" -FORMAT_TYPE_BROADCAST="${FORMAT_TYPE_BROADCAST:-"๐Ÿ“ป ${COLOR_TYPE}broadcast$COLOR_RESET"}" -FORMAT_TYPE_OTHER="${FORMAT_TYPE_OTHER:-"โ” ${COLOR_TYPE}other$COLOR_RESET"}" -FORMAT_TYPE_SECONDARY_COMPILATION="${FORMAT_TYPE_SECONDARY_COMPILATION:-"๐Ÿงฉ ${COLOR_TYPE_SECONDARY}compilation$COLOR_RESET"}" -FORMAT_TYPE_SECONDARY_SOUNDTRACK="${FORMAT_TYPE_SECONDARY_SOUNDTRACK:-"๐ŸŽฌ ${COLOR_TYPE_SECONDARY}soundtrack$COLOR_RESET"}" -FORMAT_TYPE_SECONDARY_SPOKENWORD="${FORMAT_TYPE_SECONDARY_SPOKENWORD:-"๐Ÿ“– ${COLOR_TYPE_SECONDARY}spokenword$COLOR_RESET"}" -FORMAT_TYPE_SECONDARY_INTERVIEW="${FORMAT_TYPE_SECONDARY_INTERVIEW:-"๐Ÿ’ฌ ${COLOR_TYPE_SECONDARY}interview$COLOR_RESET"}" -FORMAT_TYPE_SECONDARY_AUDIOBOOK="${FORMAT_TYPE_SECONDARY_AUDIOBOOK:-"๐ŸŽง ${COLOR_TYPE_SECONDARY}audiobook$COLOR_RESET"}" -FORMAT_TYPE_SECONDARY_AUDIODRAMA="${FORMAT_TYPE_SECONDARY_AUDIODRAMA:-"๐ŸŽญ ${COLOR_TYPE_SECONDARY}audio drama$COLOR_RESET"}" -FORMAT_TYPE_SECONDARY_LIVE="${FORMAT_TYPE_SECONDARY_LIVE:-"๐ŸŽค ${COLOR_TYPE_SECONDARY}live$COLOR_RESET"}" -FORMAT_TYPE_SECONDARY_REMIX="${FORMAT_TYPE_SECONDARY_REMIX:-"๐Ÿ” ${COLOR_TYPE_SECONDARY}remix$COLOR_RESET"}" -FORMAT_TYPE_SECONDARY_DJMIX="${FORMAT_TYPE_SECONDARY_DJMIX:-"๐Ÿชฉ ${COLOR_TYPE_SECONDARY}DJ-mix$COLOR_RESET"}" -FORMAT_TYPE_SECONDARY_MIXTAPE="${FORMAT_TYPE_SECONDARY_MIXTAPE:-"๐Ÿ“ผ ${COLOR_TYPE_SECONDARY}mixtape$COLOR_RESET"}" -FORMAT_TYPE_SECONDARY_DEMO="${FORMAT_TYPE_SECONDARY_DEMO:-"๐Ÿงช ${COLOR_TYPE_SECONDARY}demo$COLOR_RESET"}" -FORMAT_TYPE_SECONDARY_FIELDREC="${FORMAT_TYPE_SECONDARY_FIELDREC:-"๐ŸŒฟ ${COLOR_TYPE_SECONDARY}field recording$COLOR_RESET"}" -export FORMAT_PERSON FORMAT_GROUP FORMAT_DISAMBIGUATION \ - FORMAT_RELEASE FORMAT_YEAR \ - FORMAT_TYPE_ALBUM FORMAT_TYPE_SINGLE FORMAT_TYPE_EP FORMAT_TYPE_BROADCAST FORMAT_TYPE_OTHER \ - FORMAT_TYPE_SECONDARY_COMPILATION FORMAT_TYPE_SECONDARY_SOUNDTRACK FORMAT_TYPE_SECONDARY_SPOKENWORD \ - FORMAT_TYPE_SECONDARY_INTERVIEW FORMAT_TYPE_SECONDARY_AUDIOBOOK FORMAT_TYPE_SECONDARY_AUDIODRAMA \ - FORMAT_TYPE_SECONDARY_LIVE FORMAT_TYPE_SECONDARY_REMIX FORMAT_TYPE_SECONDARY_DJMIX FORMAT_TYPE_SECONDARY_MIXTAPE \ - FORMAT_TYPE_SECONDARY_DEMO FORMAT_TYPE_SECONDARY_FIELDREC +FORMAT_TYPE_ALBUM="${FORMAT_TYPE_ALBUM:-"LP ๐Ÿ’ฝ"}" +FORMAT_TYPE_EP="${FORMAT_TYPE_EP:-"EP ๐Ÿ“€"}" +FORMAT_TYPE_SINGLE="${FORMAT_TYPE_SINGLE:-"SI ๐ŸŽถ"}" +FORMAT_TYPE_BROADCAST="${FORMAT_TYPE_BROADCAST:-"BR ๐Ÿ“ป"}" +FORMAT_TYPE_OTHER="${FORMAT_TYPE_OTHER:-"OT โ”"}" +FORMAT_TYPE_HAS_SECONDARY="${FORMAT_TYPE_HAS_SECONDARY:-"%sโ˜ผ"}" +FORMAT_TYPE_SECONDARY="${FORMAT_TYPE_SECONDARY:-"${COLOR_TYPE_SECONDARY}[โ˜ผ: %s]$COLOR_RESET"}" +FORMAT_TYPE_SECONDARY_COMPILATION="${FORMAT_TYPE_SECONDARY_COMPILATION:-"๐Ÿงฉ compilation"}" +FORMAT_TYPE_SECONDARY_SOUNDTRACK="${FORMAT_TYPE_SECONDARY_SOUNDTRACK:-"๐ŸŽฌ soundtrack"}" +FORMAT_TYPE_SECONDARY_SPOKENWORD="${FORMAT_TYPE_SECONDARY_SPOKENWORD:-"๐Ÿ“– spokenword"}" +FORMAT_TYPE_SECONDARY_INTERVIEW="${FORMAT_TYPE_SECONDARY_INTERVIEW:-"๐Ÿ’ฌ interview"}" +FORMAT_TYPE_SECONDARY_AUDIOBOOK="${FORMAT_TYPE_SECONDARY_AUDIOBOOK:-"๐ŸŽง audiobook"}" +FORMAT_TYPE_SECONDARY_AUDIODRAMA="${FORMAT_TYPE_SECONDARY_AUDIODRAMA:-"๐ŸŽญ audio drama"}" +FORMAT_TYPE_SECONDARY_LIVE="${FORMAT_TYPE_SECONDARY_LIVE:-"๐ŸŽค live"}" +FORMAT_TYPE_SECONDARY_REMIX="${FORMAT_TYPE_SECONDARY_REMIX:-"๐Ÿ” remix"}" +FORMAT_TYPE_SECONDARY_DJMIX="${FORMAT_TYPE_SECONDARY_DJMIX:-"๐Ÿชฉ DJ-mix"}" +FORMAT_TYPE_SECONDARY_MIXTAPE="${FORMAT_TYPE_SECONDARY_MIXTAPE:-"๐Ÿ“ผ mixtape"}" +FORMAT_TYPE_SECONDARY_DEMO="${FORMAT_TYPE_SECONDARY_DEMO:-"๐Ÿงช demo"}" +FORMAT_TYPE_SECONDARY_FIELDREC="${FORMAT_TYPE_SECONDARY_FIELDREC:-"๐ŸŒฟ field recording"}" SEARCH_PROMPT=${SEARCH_PROMPT:-"๐Ÿ”Ž โŒช"} ARTIST_PROMPT="${ARTIST_PROMPT:-"๐ŸŽค ${COLOR_ARTIST}%s$COLOR_RESET โŒช"}" -export SEARCH_PROMPT ARTIST_PROMPT #BROWSE_PROMPT_ROOT="${BROWSE_PROMPT_ROOT:-"$SEARCH_PROMPT"}" #BROWSE_PROMPT_ARTIST="${BROWSE_PROMPT_ARTIST:-"$AFMT โŒช"}" #BROWSE_PROMPT_RELEASE="${BROWSE_PROMPT_RELEASE:-"$AFMT ใ€‹ $RFMT โŒช"}"