diff --git a/src/main.sh b/src/main.sh index ef3680e..bd4d109 100755 --- a/src/main.sh +++ b/src/main.sh @@ -55,7 +55,7 @@ if [ "${1:-}" = "--internal-search" ]; then echo "$$" >"$PIDFILE" touch "$LOCKFILE" sleep 1 - __api_mb_search_artists "$2" | + api_mb_search_artists "$2" | $JQ -r '.artists[] | [ .id, .type, @@ -76,15 +76,20 @@ if [ "${1:-}" = "--internal-search" ]; then exit 0 fi -if [ "${1:-}" = "--internal-list-releases-fresh" ]; then +if [ "${1:-}" = "--internal-list-releases" ]; then + print "NOT IMPLEMENTED" + exit 0 +fi + +if [ "${1:-}" = "--internal-list-releasegroups-fresh" ]; then artistid="$2" cache_delete_artist "$artistid" shift 2 - set -- "--internal-list-releases" "$artistid" + set -- "--internal-list-releasegroups" "$artistid" mb_artist "$artistid" >/dev/null fi -if [ "${1:-}" = "--internal-list-releases" ]; then +if [ "${1:-}" = "--internal-list-releasegroups" ]; then name=$(mb_artist "$2" | $JQ -r '.name') mb_artist_releasegroups "$2" | $JQ -r '."release-groups"[] | [ @@ -158,10 +163,10 @@ fi while true; do case "${1:-}" in "--show-artist") - name=$(mb_artist "$2" | $JQ -r '.name') - secsymb=$(printf "$FORMAT_TYPE_HAS_SECONDARY" "") + name="$(mb_artist "$2" | $JQ -r '.name')" + secsymb="$(printf "$FORMAT_TYPE_HAS_SECONDARY" "")" sel=$( - $0 --internal-list-releases "$2" | + $0 --internal-list-releasegroups "$2" | $FZF \ --ansi \ --reverse \ @@ -173,10 +178,20 @@ while true; do --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\"" + --bind="ctrl-r:reload:$0 --internal-list-releasegroups-fresh \"$2\"" ) [ "$sel" ] && set -- "--show-release" "$sel" ;; + "--show-release-group") + title="$(mb_releasegroup "$2" | + $JQ -r '.title')" + artist="$(mb_releasegroup "$2" | + $JQ -r '."artist-credit" | map(([.name, .joinphrase]|join(""))) | join("")')" + echo "$title" + echo "$artist" + exit 0 + set -- "" + ;; *) sel=$( printf "" | diff --git a/src/sh/api.sh b/src/sh/api.sh index a5e6422..d469735 100644 --- a/src/sh/api.sh +++ b/src/sh/api.sh @@ -1,32 +1,58 @@ MB_BROWSE_STEPS=100 export MB_BROWSE_STEPS -# Argument: MB Artist ID -__api_mb_browse_releases() { +api_mb_artist() { $CURL \ --get \ --data fmt=json \ - --data inc=release-groups \ - --data-urlencode artist="$1" \ + --data inc="url-rels+artist-rels+aliases" \ -A "$APP_NAME/$APP_VERSION ($APP_WEBSITE)" \ - "https://musicbrainz.org/ws/2/release" + "https://musicbrainz.org/ws/2/artist/$1" +} +api_mb_releasegroup() { + $CURL \ + --get \ + --data fmt=json \ + --data inc=artist-credits \ + -A "$APP_NAME/$APP_VERSION ($APP_WEBSITE)" \ + "https://musicbrainz.org/ws/2/release-group/$1" } -# Argument: MB Artist ID -__api_mb_browse_release_groups() { +api_mb_release() { + $CURL \ + --get \ + --data fmt=json \ + --data inc="recordings+artist-credits" \ + -A "$APP_NAME/$APP_VERSION ($APP_WEBSITE)" \ + "https://musicbrainz.org/ws/2/release/$1" +} + +api_mb_browse_artist_releasegroups() { $CURL \ --get \ --data fmt=json \ --data inc=artist-credits \ --data limit="$MB_BROWSE_STEPS" \ --data offset="${2:-0}" \ - --data-urlencode artist="$1" \ + --data artist="$1" \ -A "$APP_NAME/$APP_VERSION ($APP_WEBSITE)" \ "https://musicbrainz.org/ws/2/release-group" } +api_mb_browse_releasegroup_releases() { + $CURL \ + --get \ + --data fmt=json \ + --data inc=artist-credits \ + --data limit="$MB_BROWSE_STEPS" \ + --data offset="${2:-0}" \ + --data release-group="$1" \ + -A "$APP_NAME/$APP_VERSION ($APP_WEBSITE)" \ + "https://musicbrainz.org/ws/2/release" +} + # Argument: Search string -__api_mb_search_artists() { +api_mb_search_artists() { $CURL \ --get \ --data fmt=json \ @@ -35,34 +61,21 @@ __api_mb_search_artists() { "https://musicbrainz.org/ws/2/artist" } -# Argument: MB Artist ID -__api_mb_get_artist() { - $CURL \ - --get \ - --data fmt=json \ - --data inc="url-rels+artist-rels+aliases" \ - -A "$APP_NAME/$APP_VERSION ($APP_WEBSITE)" \ - "https://musicbrainz.org/ws/2/artist/$1" -} - -# Argument: Discogs id -__api_discogs_get_artist() { +api_discogs_artist() { $CURL \ --get \ -A "$APP_NAME/$APP_VERSION ($APP_WEBSITE)" \ "https://api.discogs.com/artists/$1" } -# Argument: wikidata id -__api_wikidata_get_sitelinks() { +api_wikidata_sitelinks() { $CURL \ --get \ -A "$APP_NAME/$APP_VERSION ($APP_WEBSITE)" \ "https://www.wikidata.org/w/rest.php/wikibase/v1/entities/items/$1/sitelinks" } -# Argument: Wikipedia name (last part of URL) -__api_wikipedia_en_get_summary() { +api_wikipedia_en_summary() { $CURL \ --get \ -A "$APP_NAME/$APP_VERSION ($APP_WEBSITE)" \ diff --git a/src/sh/cache.sh b/src/sh/cache.sh index f1a2b24..69fe9df 100644 --- a/src/sh/cache.sh +++ b/src/sh/cache.sh @@ -1,103 +1,140 @@ +# Caching structure +# +# ./artist/radix(uuid)/musicbrainz.json # Artist information +# ./artist/radix(uuid)/releasegroups.json # List of all release groups +# ./artist/radix(uuid)/... # Any other artist information +# ./releasegroup/radix(uuid)/musicbrainz.json # Release group information +# ./releasegroup/radix(uuid)/releases.json # List of all releases in release group +# ./release/radix(uuid)/musicbrainz.json # Release information with tracklist etc. CACHEDIR="$HOME/.cache/$APP_NAME" -[ -d "$CACHEDIR" ] || mkdir "$CACHEDIR" +TYPE_ARTIST="artist" +TYPE_RELEASEGROUP="releasegroup" +TYPE_RELEASE="release" -artist_mb_filename="musicbrainz.json" -artist_mb_releasegroups_filename="releasegroups.json" +artist_filename="musicbrainz.json" +artist_releasegroups_filename="releasegroups.json" artist_discogs_filename="discogs.json" artist_wikidata_filename="wikidata.json" artist_enwikipedia_filename="enwikipedia.json" +releasegroup_filename="musicbrainz.json" +releasegroup_releases_filename="releases.json" +release_filename="musicbrainz.json" + +# Radix transform directory name +__radix() { + echo "$1" | awk -F "" '{ print $1$2$3$4"/"$5$6$7$8"/"$0 }' +} # Super wrapper -# argument $1: MusicBrainz Artist ID -# argument $2: Filename of json file -__get_artist_json() { - f="$CACHEDIR/$1/$2" +# argument $1: type +# argument $2: MusicBrainz ID +# argument $3: Filename of json file +__get_json() { + f="$CACHEDIR/$1/$(__radix "$2")/$3" [ -f "$f" ] || return cat "$f" } # Super wrapper -# argument $1: MusicBrainz Artist ID -# argument $2: Filename of json file -__put_artist_json() { - artistdir="$CACHEDIR/$1" - [ -d "$artistdir" ] || mkdir "$artistdir" - f="$artistdir/$2" +# argument $1: type +# argument $2: MusicBrainz ID +# argument $3: Filename of json file +__put_json() { + dir="$CACHEDIR/$1/$(__radix "$2")" + [ -d "$dir" ] || mkdir -p "$dir" + f="$dir/$3" tmpf=$(mktemp) cat >"$tmpf" [ -s "$tmpf" ] && mv "$tmpf" "$f" || printf "{}" >"$f" } -# Delete all cache associated to the given artist -# argument $1: MusicBrainz Artist ID -cache_delete_artist() { - artistdir="$CACHEDIR/$1" - rm -rf "$artistdir" +## Artist +cache_get_artist() { + __get_json "$TYPE_ARTIST" "$1" "$artist_filename" } -# Returns the cached MusicBrainz data for the artist given by the MusicBrainz -# Artist ID in $1 -cache_get_artist_mb() { - __get_artist_json "$1" "$artist_mb_filename" +cache_get_artist_releasegroups() { + __get_json "$TYPE_ARTIST" "$1" "$artist_releasegroups_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() { - __get_artist_json "$1" "$artist_discogs_filename" + __get_json "$TYPE_ARTIST" "$1" "$artist_discogs_filename" } -# Returns the cached Wikipedia (English) data for the artist given by the -# MusicBrainz Artist ID in $1 cache_get_artist_enwikipedia() { - __get_artist_json "$1" "$artist_enwikipedia_filename" + __get_json "$TYPE_ARTIST" "$1" "$artist_enwikipedia_filename" } cache_get_artist_wikidata() { - __get_artist_json "$1" "$artist_wikidata_filename" + __get_json "$TYPE_ARTIST" "$1" "$artist_wikidata_filename" } -# Read from stdin the MusicBrainz data for the artist given by the MusicBrainz -# Artist ID in $1, and cache it. -cache_put_artist_mb() { - cat | __put_artist_json "$1" "$artist_mb_filename" +cache_put_artist() { + cat | __put_json "$TYPE_ARTIST" "$1" "$artist_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" +cache_put_artist_releasegroups() { + cat | __put_json "$TYPE_ARTIST" "$1" "$artist_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() { +cache_append_artist_releasegroups() { tmpf=$(mktemp) cat >"$tmpf" updated=$(mktemp) - f="$CACHEDIR/$1/$artist_mb_releasegroups_filename" + f="$CACHEDIR/$TYPE_ARTIST/$(__radix "$1")/$artist_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() { - cat | __put_artist_json "$1" "$artist_discogs_filename" + cat | __put_json "$TYPE_ARTIST" "$1" "$artist_discogs_filename" } -# Read from stdin the Wikipedia data (English) for the artist given by the -# MusicBrainz Artist ID in $1, and cache it. cache_put_artist_enwikipedia() { - cat | __put_artist_json "$1" "$artist_enwikipedia_filename" + cat | __put_json "$TYPE_ARTIST" "$1" "$artist_enwikipedia_filename" } cache_put_artist_wikidata() { - cat | __put_artist_json "$1" "$artist_wikidata_filename" + cat | __put_json "$TYPE_ARTIST" "$1" "$artist_wikidata_filename" +} + +## Release group +cache_get_releasegroup() { + __get_json "$TYPE_RELEASEGROUP" "$1" "$releasegroup_filename" +} + +cache_get_releasegroup_releases() { + __get_json "$TYPE_RELEASEGROUP" "$1" "$releasegroup_releases_filename" +} + +cache_put_releasegroup() { + cat | __put_json "$TYPE_RELEASEGROUP" "$1" "$releasegroup_filename" +} + +cache_put_releasegroup_releases() { + cat | __put_json "$TYPE_RELEASEGROUP" "$1" "$releasegroup_releases_filename" +} + +cache_append_releasegroup_releases() { + tmpf=$(mktemp) + cat >"$tmpf" + updated=$(mktemp) + f="$CACHEDIR/$TYPE_RELEASEGROUP/$(__radix "$1")/$releasegroup_releases_filename" + $JQ -r --slurpfile n "$tmpf" '."releases" += ($n[0]|."releases")' "$f" >"$updated" && mv "$updated" "$f" + rm -f "$tmpf" +} + +## Release +cache_get_release() { + __get_json "$TYPE_RELEASE" "$1" "$release_filename" +} + +cache_put_release() { + cat | __put_json "$TYPE_RELEASE" "$1" "$release_filename" +} + +## Cache deletion +cache_delete_artist() { + # Get release groups + echo "NOT IMPLEMENTED" >/dev/stderr } diff --git a/src/sh/mb.sh b/src/sh/mb.sh index cac8b1c..f7688fa 100644 --- a/src/sh/mb.sh +++ b/src/sh/mb.sh @@ -3,25 +3,55 @@ # Helper methods to retrieve from cache, if it exists, and otherwise populate # cache and retrieve __mb_artist_cache_or_fetch() { - if ! cache_get_artist_mb "$1"; then - __api_mb_get_artist "$1" | cache_put_artist_mb "$1" - cache_get_artist_mb "$1" + if ! cache_get_artist "$1"; then + api_mb_artist "$1" | cache_put_artist "$1" + cache_get_artist "$1" + fi +} + +__mb_releasegroup_cache_or_fetch() { + if ! cache_get_releasegroup "$1"; then + api_mb_releasegroup "$1" | cache_put_releasegroup "$1" + cache_get_releasegroup "$1" + fi +} + +__mb_release_cache_or_fetch() { + if ! cache_get_release "$1"; then + api_mb_release "$1" | cache_put_release "$1" + cache_get_release "$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")" + if ! cache_get_artist_releasegroups "$1"; then + api_mb_browse_artist_releasegroups "$1" | cache_put_artist_releasegroups "$1" + rg="$(cache_get_artist_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" + api_mb_browse_artist_releasegroups "$1" "$seen" | cache_append_artist_releasegroups "$1" seen=$((seen + MB_BROWSE_STEPS)) done - cache_get_artist_mb_releasegroups "$1" + cache_get_artist_releasegroups "$1" + fi +} + +__mb_releasegroup_cache_or_fetch_releases() { + if ! cache_get_releasegroup_releases "$1"; then + api_mb_browse_releasegroup_releases "$1" | cache_put_releasegroup_releases "$1" + releases="$(cache_get_releasegroup_releases "$1")" + total=$(printf "%s" "$releases" | $JQ -r '."release-count"') + seen=$MB_BROWSE_STEPS + while [ "$total" -gt "$seen" ]; do + # Fetch remaning releases, and append to cache + sleep 1 # Make sure we don't get blocked (we prefer not to handle failed requests...) + api_mb_browse_releasegroup_releases "$1" "$seen" | cache_append_releasegroup_releases "$1" + seen=$((seen + MB_BROWSE_STEPS)) + done + cache_get_releasegroup_releases "$1" fi } @@ -38,10 +68,10 @@ mb_artist_wikidata() { wikidataid=$(mb_artist "$1" | $JQ -r '.relations | map(select(.type=="wikidata")) | - .[0].url.resource' | + .[0].url.resource // ""' | awk -F "/" '{print $NF}') - [ ! "$wikidataid" ] && return || [ "$wikidataid" = "null" ] && return - __api_wikidata_get_sitelinks "$wikidataid" | cache_put_artist_wikidata "$1" + [ ! "$wikidataid" ] && return + api_wikidata_sitelinks "$wikidataid" | cache_put_artist_wikidata "$1" cache_get_artist_wikidata "$1" fi } @@ -59,10 +89,10 @@ mb_artist_enwikipedia() { # take the second route. wikidata=$(mb_artist_wikidata "$1" || true) wikiid=$(printf "%s" "$wikidata" | - $JQ -r '.enwiki.url' | + $JQ -r '.enwiki.url // ""' | awk -F "/" '{print $NF}') - [ ! "$wikiid" ] && return || [ "$wikiid" = "null" ] && return - __api_wikipedia_en_get_summary "$wikiid" | cache_put_artist_enwikipedia "$1" + [ ! "$wikiid" ] && return + api_wikipedia_en_summary "$wikiid" | cache_put_artist_enwikipedia "$1" cache_get_artist_enwikipedia "$1" fi } @@ -74,10 +104,10 @@ mb_artist_discogs() { discogsid=$(mb_artist "$1" | $JQ -r '.relations | map(select(.type=="discogs")) | - .[0].url.resource' | + .[0].url.resource // ""' | awk -F "/" '{print $NF}') - [ ! "$discogsid" ] && return || [ "$discogsid" = "null" ] && return - __api_discogs_get_artist "$discogsid" | cache_put_artist_discogs "$1" + [ ! "$discogsid" ] && return + api_discogs_artist "$discogsid" | cache_put_artist_discogs "$1" cache_get_artist_discogs "$1" fi } @@ -87,3 +117,17 @@ mb_artist_discogs() { mb_artist_releasegroups() { __mb_artist_cache_or_fetch_releasegroups "$1" } + +# Get MusicBrainz json for release group +# @argument $1: MusicBrainz Release-Group ID +mb_releasegroup() { + __mb_releasegroup_cache_or_fetch "$1" +} + +mb_releasegroup_releases() { + __mb_releasegroup_cache_or_fetch_releases "$1" +} + +mb_release() { + __mb_release_cache_or_fetch "$1" +}