v2 post-migration bug fixes, lidarr_missing_art port, and Partnership SSH/FolderView3 enhancements
Bug fixes across the ecosystem after v1→v2 architecture migration and Unraid 7.2.5 upgrade:
- common.sh: fix _alias_array() phantom empty element (removed [@]:-} pattern), fix
resolve_remote_ip() with Tailscale FQDN lowercase + awk fallback, add FANART/LASTFM
key aliases in detect_hosts(), global [@]:-} sweep across 10+ scripts
- webgui_restart.sh: fix emhttp detection (pgrep emhttpd) and restart command for 7.2.5
(/usr/local/sbin/emhttp stop && start — rc.emhttp removed in 7.2.5)
- bandwidth_monitor.sh, continuous_scripts_status.sh: fix 'local' keyword outside function
- backup_verify.sh: fix resolve_remote_ip() called before detect_hosts()
- Orchestrators: fix script display duplication bug in status output (${entry##*/})
- rsync_stop.sh, git_pull_execute.sh, partnership_manager.sh, coffee_report: lowercase all
tailscale ip -4 call sites to match Tailscale's lowercase device names
- master_host1.conf: fix SSH key path (gmer4lfe_rsync_automation), add FANART/LASTFM keys
- master_host2.conf: add FANART/LASTFM API keys
New: Media/lidarr_missing_art.sh
- Full ecosystem port of standalone Lidarr artwork fetcher
- Fetches missing album art via fanart.tv + Last.fm APIs
- @tsv batch extraction: 1 jq call per API response vs N*albums (8050 albums in 24s)
- HOST guard (HOST1 only), --status, --dry-run, acquire_lock
New: Initial_run/ssh_setup.sh
- Generates {hostname}_rsync_automation ed25519 keypair (skip if exists, --force to regen)
- ssh-copy-id to remote via Tailscale IP, auto-updates master_host*.conf
- --validate mode: strike tracking (SSH_MAX_STRIKES, SSH_STRIKE_RESET_HRS),
notify at limit — Tailscale-unreachable remote does NOT count as SSH strike
New: Initial_run/partnership_onboard.sh
- Orchestrator: ssh_setup.sh then partnership_manager.sh --onboard in one command
Partnership/partnership_manager.sh: FolderView3 integration
- Derive partner folder name at runtime (strip unraid- prefix case-insensitively)
- --onboard: create {Mirror}-Failover folder with failover tier containers
- --offboard (both paths): stop + rm containers in folder, remove JSON entry
- --check: calls ssh_setup.sh --validate when IP resolves but SSH state empty
- --status: shows FolderView3 folder state and containers inline
master.conf: SSH_MAX_STRIKES, SSH_STRIKE_RESET_HRS, PARTNERSHIP_FOLDERVIEW3,
PARTNERSHIP_FOLDERVIEW3_URL added to Partnership section
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
7cecda6b90
commit
5526bc1eca
+236
-230
@@ -1,78 +1,126 @@
|
||||
#!/bin/bash
|
||||
# ==============================================================================================
|
||||
# ================================= Lidarr Missing Art =========================================
|
||||
# ==============================================================================================
|
||||
# Fetches missing album and artist artwork for the Lidarr music library.
|
||||
# Reads from Lidarr API to discover album/artist paths, then downloads only
|
||||
# what is missing — never overwrites existing files.
|
||||
#
|
||||
# ── SAFE DESIGN ───────────────────────────────────────────────────────────────────────────────
|
||||
# READS from Lidarr only — no writes back to Lidarr
|
||||
# NEVER modifies audio tags or renames media files
|
||||
# NEVER overwrites existing artwork
|
||||
# ONLY writes missing artwork files to existing album/artist directories
|
||||
#
|
||||
# ── ARTWORK TARGETS ───────────────────────────────────────────────────────────────────────────
|
||||
# Album folder: cover.jpg cdart.png back.jpg
|
||||
# Artist folder: folder.jpg fanart.jpg logo.png banner.jpg
|
||||
#
|
||||
# ── SOURCES ───────────────────────────────────────────────────────────────────────────────────
|
||||
# Album covers: fanart.tv → iTunes fallback
|
||||
# Artist art: fanart.tv → Deezer fallback → Last.fm fallback
|
||||
#
|
||||
# ── HOST AWARENESS ────────────────────────────────────────────────────────────────────────────
|
||||
# Lidarr runs on HOST1 only. detect_hosts() sets LIDARR_URL — if empty (HOST2) the
|
||||
# script exits cleanly with no action rather than failing.
|
||||
#
|
||||
# ── SAFEGUARDS ────────────────────────────────────────────────────────────────────────────────
|
||||
# acquire_lock — prevents concurrent runs during large library scans
|
||||
# curl + jq check — fail fast if tools missing
|
||||
# API reachability — verified before processing begins
|
||||
# Skip existing — never overwrites, idempotent re-runs are safe
|
||||
# Min file size — rejects corrupt/placeholder downloads (LIDARR_ART_MIN_SIZE)
|
||||
# Parallel jobs — capped at LIDARR_ART_MAX_PARALLEL to avoid hammering APIs
|
||||
# Download retries — LIDARR_ART_RETRIES attempts per image before giving up
|
||||
# Dry-run mode — logs what would be downloaded without writing anything
|
||||
#
|
||||
# ── CONFIGURATION (master.conf) ───────────────────────────────────────────────────────────────
|
||||
# FANART_API_KEY — fanart.tv API key
|
||||
# LASTFM_API_KEY — last.fm API key
|
||||
# LIDARR_ART_MIN_SIZE — minimum valid download size in bytes
|
||||
# LIDARR_ART_MAX_PARALLEL — concurrent background download jobs
|
||||
# LIDARR_ART_RETRIES — download retry attempts per image
|
||||
# LIDARR_ART_SLEEP_BETWEEN — seconds between fanart.tv API calls
|
||||
#
|
||||
# ── CONFIGURATION (master_host*.conf) ─────────────────────────────────────────────────────────
|
||||
# HOST1_LIDARR_URL — Lidarr base URL
|
||||
# HOST1_LIDARR_API_KEY — Lidarr API key
|
||||
# All aliased by detect_hosts() — script uses unprefixed LIDARR_URL / LIDARR_API_KEY
|
||||
#
|
||||
# ── USAGE ─────────────────────────────────────────────────────────────────────────────────────
|
||||
# lidarr_missing_art.sh — fetch all missing artwork
|
||||
# lidarr_missing_art.sh --dry-run — preview without downloading
|
||||
# lidarr_missing_art.sh --log — verbose output
|
||||
# lidarr_missing_art.sh --status — show config and exit
|
||||
# ==============================================================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
source "$SCRIPT_DIR/../load_config.sh"
|
||||
|
||||
parse_args "$@"
|
||||
|
||||
# ==============================================================================================
|
||||
# ================================= Music Artwork Fetcher ======================================
|
||||
# ━━━ Setup ━━━
|
||||
# ==============================================================================================
|
||||
#
|
||||
# SAFE DESIGN
|
||||
# - READS from Lidarr only
|
||||
# - NEVER modifies tags
|
||||
# - NEVER renames media
|
||||
# - NEVER writes to Lidarr
|
||||
# - ONLY writes missing artwork files
|
||||
#
|
||||
# ARTWORK
|
||||
#
|
||||
# Album Folder:
|
||||
# cover.jpg
|
||||
# cdart.png
|
||||
# back.jpg
|
||||
#
|
||||
# Artist Folder:
|
||||
# folder.jpg
|
||||
# fanart.jpg
|
||||
# logo.png
|
||||
# banner.jpg
|
||||
#
|
||||
# SOURCES
|
||||
#
|
||||
# Album Covers:
|
||||
# fanart.tv
|
||||
# iTunes fallback
|
||||
#
|
||||
# Artist Art:
|
||||
# fanart.tv
|
||||
# Deezer fallback
|
||||
# Last.fm fallback
|
||||
echo ""
|
||||
echo "━━━ $ICON_GEAR Setup ━━━"
|
||||
|
||||
# ================================= CONFIG =====================================================
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
error "Must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
success "Running as root"
|
||||
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
error "curl not found — required for API calls"
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
error "jq not found — required for JSON parsing"
|
||||
exit 1
|
||||
fi
|
||||
success "curl and jq found"
|
||||
|
||||
LIDARR_URL="http://localhost:8686"
|
||||
LIDARR_API_KEY="b2977e71ef074bc0a0529d9fcce3b2dc"
|
||||
acquire_lock
|
||||
|
||||
FANART_API_KEY="Yd7147a43b692df0b364b94dc47efb81"
|
||||
LASTFM_API_KEY="be6dc169c33ae263e690c30d18b7491d"
|
||||
detect_hosts
|
||||
|
||||
LOG="/tmp/artfetch.log"
|
||||
# HOST guard — Lidarr runs on HOST1 only
|
||||
if [[ -z "$LIDARR_URL" ]]; then
|
||||
log "Lidarr not configured for $MY_ID — nothing to do"
|
||||
exit 0
|
||||
fi
|
||||
success "Identity: $MY_ID ($LOCAL_SERVER_NAME)"
|
||||
|
||||
MIN_SIZE=10000
|
||||
MAX_PARALLEL=4
|
||||
RETRIES=2
|
||||
SLEEP_BETWEEN=0.2
|
||||
|
||||
# ================================= FLAGS ======================================================
|
||||
|
||||
DRY_RUN=0
|
||||
|
||||
if [[ "$1" == "--dry-run" ]]; then
|
||||
DRY_RUN=1
|
||||
echo "Running in DRY-RUN mode"
|
||||
# ==============================================================================================
|
||||
# ━━━ Status ━━━
|
||||
# ==============================================================================================
|
||||
if [[ "$SHOW_STATUS" == true ]]; then
|
||||
echo ""
|
||||
echo "━━━━━ $ICON_SUMMARY STATUS ━━━━━"
|
||||
echo "$ICON_HOST Identity: $MY_ID ($LOCAL_SERVER_NAME)"
|
||||
echo "$ICON_GEAR Lidarr URL: $LIDARR_URL"
|
||||
echo "$ICON_NET Fanart key: $([[ -n "${FANART_API_KEY:-}" ]] && echo "set" || echo "not set")"
|
||||
echo "$ICON_NET LastFM key: $([[ -n "${LASTFM_API_KEY:-}" ]] && echo "set" || echo "not set")"
|
||||
echo "$ICON_GEAR Min size: ${LIDARR_ART_MIN_SIZE} bytes"
|
||||
echo "$ICON_GEAR Parallel: $LIDARR_ART_MAX_PARALLEL jobs"
|
||||
echo "$ICON_RETRY Retries: $LIDARR_ART_RETRIES"
|
||||
echo "$ICON_TIME API sleep: ${LIDARR_ART_SLEEP_BETWEEN}s"
|
||||
echo "$ICON_NOTIFY Notify: unRAID=${NOTIFY_UNRAID:-false} Discord=$([[ -n "${MY_DISCORD_WEBHOOK:-}" ]] && echo enabled || echo disabled)"
|
||||
echo "$ICON_GEAR Dry Run: $DRY_RUN"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ================================= LOGGING ====================================================
|
||||
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no files will be written"
|
||||
|
||||
log() {
|
||||
echo "$(date '+%F %T') | $1" >> "$LOG"
|
||||
}
|
||||
|
||||
# ================================= HELPERS ====================================================
|
||||
# ==============================================================================================
|
||||
# ── FUNCTIONS ─────────────────────────────────────────────────────────────────────────────────
|
||||
# ==============================================================================================
|
||||
|
||||
curl_json() {
|
||||
curl -s \
|
||||
--connect-timeout 5 \
|
||||
--max-time 20 \
|
||||
"$1"
|
||||
curl -s --connect-timeout 5 --max-time 20 "$1"
|
||||
}
|
||||
|
||||
job_count() {
|
||||
@@ -80,285 +128,243 @@ job_count() {
|
||||
}
|
||||
|
||||
wait_for_slot() {
|
||||
while (( $(job_count) >= MAX_PARALLEL )); do
|
||||
while (( $(job_count) >= LIDARR_ART_MAX_PARALLEL )); do
|
||||
sleep 0.2
|
||||
done
|
||||
}
|
||||
|
||||
# ================================= DOWNLOAD ===================================================
|
||||
|
||||
# Downloads URL to dest only if dest doesn't exist and downloaded size >= MIN_SIZE.
|
||||
# Returns 0 on success or skip (file already exists), 1 on failure.
|
||||
download_if_valid() {
|
||||
|
||||
local url="$1"
|
||||
local dest="$2"
|
||||
|
||||
[[ -z "$url" || "$url" == "null" ]] && return 1
|
||||
|
||||
# never overwrite existing
|
||||
[[ -f "$dest" ]] && return 0
|
||||
|
||||
if [[ "$DRY_RUN" -eq 1 ]]; then
|
||||
log "[DRY] $dest"
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
info "DRY RUN — would fetch: $(basename "$dest")"
|
||||
return 0
|
||||
fi
|
||||
|
||||
for ((i=0; i<=RETRIES; i++)); do
|
||||
|
||||
tmp="${dest}.tmp"
|
||||
|
||||
curl -s \
|
||||
--connect-timeout 5 \
|
||||
--max-time 20 \
|
||||
-L \
|
||||
-o "$tmp" \
|
||||
"$url"
|
||||
|
||||
size=$(stat -c%s "$tmp" 2>/dev/null)
|
||||
|
||||
if [[ "$size" -gt "$MIN_SIZE" ]]; then
|
||||
local tmp="${dest}.tmp"
|
||||
local i
|
||||
for (( i=0; i<=LIDARR_ART_RETRIES; i++ )); do
|
||||
curl -s --connect-timeout 5 --max-time 20 -L -o "$tmp" "$url"
|
||||
local size
|
||||
size=$(stat -c%s "$tmp" 2>/dev/null || echo 0)
|
||||
if (( size > LIDARR_ART_MIN_SIZE )); then
|
||||
mv "$tmp" "$dest"
|
||||
log "[OK] $dest"
|
||||
log "Fetched: $dest"
|
||||
return 0
|
||||
fi
|
||||
|
||||
rm -f "$tmp"
|
||||
sleep 1
|
||||
done
|
||||
|
||||
log "[FAIL] $dest"
|
||||
warn "Failed to fetch valid image: $(basename "$dest")"
|
||||
return 1
|
||||
}
|
||||
|
||||
# ================================= DEEZER =====================================================
|
||||
|
||||
deezer_artist_image() {
|
||||
|
||||
local artist="$1"
|
||||
|
||||
local query
|
||||
query=$(printf "%s" "$artist" | sed 's/ /+/g')
|
||||
|
||||
curl_json \
|
||||
"https://api.deezer.com/search/artist?q=$query" |
|
||||
curl_json "https://api.deezer.com/search/artist?q=$query" |
|
||||
jq -r '.data[0].picture_xl // empty'
|
||||
}
|
||||
|
||||
# ================================= LASTFM =====================================================
|
||||
|
||||
lastfm_artist_image() {
|
||||
|
||||
local artist="$1"
|
||||
|
||||
local encoded
|
||||
encoded=$(printf "%s" "$artist" | sed 's/ /%20/g')
|
||||
|
||||
curl_json \
|
||||
"https://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist=$encoded&api_key=$LASTFM_API_KEY&format=json" |
|
||||
curl_json "https://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist=$encoded&api_key=$LASTFM_API_KEY&format=json" |
|
||||
jq -r '.artist.image[-1]["#text"] // empty'
|
||||
}
|
||||
|
||||
# ==============================================================================================
|
||||
# ====================================== ALBUMS =================================================
|
||||
# ━━━ Verify Lidarr reachable ━━━
|
||||
# ==============================================================================================
|
||||
echo ""
|
||||
echo "━━━ $ICON_NET Lidarr API ━━━"
|
||||
|
||||
echo "===== PROCESSING ALBUMS ====="
|
||||
|
||||
albums=$(curl_json \
|
||||
"$LIDARR_URL/api/v1/album?apikey=$LIDARR_API_KEY")
|
||||
|
||||
[[ -z "$albums" || "$albums" == "null" ]] && {
|
||||
echo "ERROR: Lidarr album API failed"
|
||||
if ! curl_json "$LIDARR_URL/api/v1/system/status?apikey=$LIDARR_API_KEY" | jq -e '.version' >/dev/null 2>&1; then
|
||||
error "Lidarr API unreachable at $LIDARR_URL — aborting"
|
||||
notify "lidarr_missing_art failed — Lidarr API unreachable on $(hostname)" "Lidarr Missing Art" "warning"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
success "Lidarr API reachable"
|
||||
|
||||
START=$(date +%s)
|
||||
|
||||
ALBUMS_CHECKED=0
|
||||
ALBUMS_COMPLETE=0
|
||||
ALBUM_FETCHES=0
|
||||
ALBUM_FAILS=0
|
||||
|
||||
ARTISTS_CHECKED=0
|
||||
ARTISTS_COMPLETE=0
|
||||
ARTIST_FETCHES=0
|
||||
ARTIST_FAILS=0
|
||||
|
||||
# ==============================================================================================
|
||||
# ━━━ Albums ━━━
|
||||
# ==============================================================================================
|
||||
echo ""
|
||||
echo "━━━ $ICON_EMBY Albums ━━━"
|
||||
|
||||
albums=$(curl_json "$LIDARR_URL/api/v1/album?apikey=$LIDARR_API_KEY")
|
||||
|
||||
if [[ -z "$albums" || "$albums" == "null" ]]; then
|
||||
error "Lidarr album API returned empty — aborting"
|
||||
notify "lidarr_missing_art failed — album API empty on $(hostname)" "Lidarr Missing Art" "warning"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
total_albums=$(echo "$albums" | jq '. | length')
|
||||
album_count=0
|
||||
info "$total_albums albums to process"
|
||||
|
||||
echo "$albums" | jq -c '.[]?' | while read -r album; do
|
||||
while IFS=$'\t' read -r local_path mbid artist_name album_name; do
|
||||
(( ALBUMS_CHECKED++ ))
|
||||
|
||||
((album_count++))
|
||||
[[ ! -d "$local_path" ]] && continue
|
||||
|
||||
path=$(echo "$album" | jq -r '.path')
|
||||
mbid=$(echo "$album" | jq -r '.foreignAlbumId')
|
||||
artist=$(echo "$album" | jq -r '.artist.artistName')
|
||||
name=$(echo "$album" | jq -r '.title')
|
||||
log "[$ALBUMS_CHECKED/$total_albums] $artist_name — $album_name"
|
||||
|
||||
[[ ! -d "$path" ]] && continue
|
||||
|
||||
printf '[ALBUM %s/%s] %s - %s\n' \
|
||||
"$album_count" "$total_albums" "$artist" "$name"
|
||||
|
||||
# skip complete albums
|
||||
if [[ -f "$path/cover.jpg" &&
|
||||
-f "$path/cdart.png" &&
|
||||
-f "$path/back.jpg" ]]; then
|
||||
echo " -> complete"
|
||||
if [[ -f "$local_path/cover.jpg" &&
|
||||
-f "$local_path/cdart.png" &&
|
||||
-f "$local_path/back.jpg" ]]; then
|
||||
(( ALBUMS_COMPLETE++ ))
|
||||
log " complete — skipping"
|
||||
continue
|
||||
fi
|
||||
|
||||
wait_for_slot
|
||||
|
||||
(
|
||||
|
||||
JSON=""
|
||||
|
||||
if [[ -n "$mbid" && "$mbid" != "null" ]]; then
|
||||
|
||||
JSON=$(curl_json \
|
||||
"http://webservice.fanart.tv/v3/music/albums/$mbid?api_key=$FANART_API_KEY")
|
||||
|
||||
sleep "$SLEEP_BETWEEN"
|
||||
JSON=$(curl_json "http://webservice.fanart.tv/v3/music/albums/$mbid?api_key=$FANART_API_KEY")
|
||||
sleep "$LIDARR_ART_SLEEP_BETWEEN"
|
||||
fi
|
||||
|
||||
# ================= COVER =================
|
||||
|
||||
if [[ ! -f "$path/cover.jpg" ]]; then
|
||||
|
||||
if [[ ! -f "$local_path/cover.jpg" ]]; then
|
||||
IMG=$(echo "$JSON" | jq -r '.[].albumcover[0].url // empty')
|
||||
|
||||
if ! download_if_valid "$IMG" "$path/cover.jpg"; then
|
||||
|
||||
query=$(printf "%s %s" "$artist" "$name" | sed 's/ /+/g')
|
||||
|
||||
itunes=$(curl_json \
|
||||
"https://itunes.apple.com/search?term=$query&entity=album&limit=1" |
|
||||
jq -r '.results[0].artworkUrl100 // empty' |
|
||||
sed 's/100x100/600x600/')
|
||||
|
||||
download_if_valid "$itunes" "$path/cover.jpg"
|
||||
if ! download_if_valid "$IMG" "$local_path/cover.jpg"; then
|
||||
query=$(printf "%s %s" "$artist_name" "$album_name" | sed 's/ /+/g')
|
||||
itunes=$(curl_json "https://itunes.apple.com/search?term=$query&entity=album&limit=1" |
|
||||
jq -r '.results[0].artworkUrl100 // empty' | sed 's/100x100/600x600/')
|
||||
download_if_valid "$itunes" "$local_path/cover.jpg"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ================= CDART =================
|
||||
|
||||
if [[ ! -f "$path/cdart.png" ]]; then
|
||||
|
||||
if [[ ! -f "$local_path/cdart.png" ]]; then
|
||||
IMG=$(echo "$JSON" | jq -r '.[].cdart[0].url // empty')
|
||||
|
||||
download_if_valid "$IMG" "$path/cdart.png"
|
||||
download_if_valid "$IMG" "$local_path/cdart.png"
|
||||
fi
|
||||
|
||||
# ================= BACK =================
|
||||
|
||||
if [[ ! -f "$path/back.jpg" ]]; then
|
||||
|
||||
if [[ ! -f "$local_path/back.jpg" ]]; then
|
||||
IMG=$(echo "$JSON" | jq -r '.[].albumback[0].url // empty')
|
||||
|
||||
download_if_valid "$IMG" "$path/back.jpg"
|
||||
download_if_valid "$IMG" "$local_path/back.jpg"
|
||||
fi
|
||||
|
||||
) &
|
||||
|
||||
done
|
||||
done < <(echo "$albums" | jq -r '.[] | [.path, .foreignAlbumId, .artist.artistName, .title] | @tsv')
|
||||
|
||||
wait
|
||||
|
||||
# ==============================================================================================
|
||||
# ====================================== ARTISTS ================================================
|
||||
# ━━━ Artists ━━━
|
||||
# ==============================================================================================
|
||||
echo ""
|
||||
echo "━━━ $ICON_EMBY Artists ━━━"
|
||||
|
||||
echo
|
||||
echo "===== PROCESSING ARTISTS ====="
|
||||
artists=$(curl_json "$LIDARR_URL/api/v1/artist?apikey=$LIDARR_API_KEY")
|
||||
|
||||
artists=$(curl_json \
|
||||
"$LIDARR_URL/api/v1/artist?apikey=$LIDARR_API_KEY")
|
||||
|
||||
[[ -z "$artists" || "$artists" == "null" ]] && {
|
||||
echo "ERROR: Lidarr artist API failed"
|
||||
if [[ -z "$artists" || "$artists" == "null" ]]; then
|
||||
error "Lidarr artist API returned empty — aborting"
|
||||
notify "lidarr_missing_art failed — artist API empty on $(hostname)" "Lidarr Missing Art" "warning"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
total_artists=$(echo "$artists" | jq '. | length')
|
||||
artist_count=0
|
||||
info "$total_artists artists to process"
|
||||
|
||||
echo "$artists" | jq -c '.[]?' | while read -r artist; do
|
||||
while IFS=$'\t' read -r local_path mbid name; do
|
||||
(( ARTISTS_CHECKED++ ))
|
||||
|
||||
((artist_count++))
|
||||
|
||||
path=$(echo "$artist" | jq -r '.path')
|
||||
mbid=$(echo "$artist" | jq -r '.foreignArtistId')
|
||||
name=$(echo "$artist" | jq -r '.artistName')
|
||||
|
||||
[[ ! -d "$path" ]] && continue
|
||||
[[ ! -d "$local_path" ]] && continue
|
||||
[[ -z "$mbid" || "$mbid" == "null" ]] && continue
|
||||
|
||||
printf '[ARTIST %s/%s] %s\n' \
|
||||
"$artist_count" "$total_artists" "$name"
|
||||
log "[$ARTISTS_CHECKED/$total_artists] $name"
|
||||
|
||||
# skip complete artists
|
||||
if [[ -f "$path/folder.jpg" &&
|
||||
-f "$path/fanart.jpg" &&
|
||||
-f "$path/logo.png" &&
|
||||
-f "$path/banner.jpg" ]]; then
|
||||
echo " -> complete"
|
||||
if [[ -f "$local_path/folder.jpg" &&
|
||||
-f "$local_path/fanart.jpg" &&
|
||||
-f "$local_path/logo.png" &&
|
||||
-f "$local_path/banner.jpg" ]]; then
|
||||
(( ARTISTS_COMPLETE++ ))
|
||||
log " complete — skipping"
|
||||
continue
|
||||
fi
|
||||
|
||||
wait_for_slot
|
||||
|
||||
(
|
||||
JSON=$(curl_json "http://webservice.fanart.tv/v3/music/$mbid?api_key=$FANART_API_KEY")
|
||||
sleep "$LIDARR_ART_SLEEP_BETWEEN"
|
||||
|
||||
JSON=$(curl_json \
|
||||
"http://webservice.fanart.tv/v3/music/$mbid?api_key=$FANART_API_KEY")
|
||||
|
||||
sleep "$SLEEP_BETWEEN"
|
||||
|
||||
# ================= folder.jpg =================
|
||||
|
||||
if [[ ! -f "$path/folder.jpg" ]]; then
|
||||
|
||||
if [[ ! -f "$local_path/folder.jpg" ]]; then
|
||||
IMG=$(echo "$JSON" | jq -r '.artistthumb[0].url // empty')
|
||||
|
||||
if ! download_if_valid "$IMG" "$path/folder.jpg"; then
|
||||
|
||||
if ! download_if_valid "$IMG" "$local_path/folder.jpg"; then
|
||||
IMG=$(deezer_artist_image "$name")
|
||||
|
||||
if ! download_if_valid "$IMG" "$path/folder.jpg"; then
|
||||
|
||||
if ! download_if_valid "$IMG" "$local_path/folder.jpg"; then
|
||||
IMG=$(lastfm_artist_image "$name")
|
||||
|
||||
download_if_valid "$IMG" "$path/folder.jpg"
|
||||
download_if_valid "$IMG" "$local_path/folder.jpg"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# ================= fanart.jpg =================
|
||||
|
||||
if [[ ! -f "$path/fanart.jpg" ]]; then
|
||||
|
||||
if [[ ! -f "$local_path/fanart.jpg" ]]; then
|
||||
IMG=$(echo "$JSON" | jq -r '.artistbackground[0].url // empty')
|
||||
|
||||
if ! download_if_valid "$IMG" "$path/fanart.jpg"; then
|
||||
|
||||
if ! download_if_valid "$IMG" "$local_path/fanart.jpg"; then
|
||||
IMG=$(deezer_artist_image "$name")
|
||||
|
||||
download_if_valid "$IMG" "$path/fanart.jpg"
|
||||
download_if_valid "$IMG" "$local_path/fanart.jpg"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ================= logo.png =================
|
||||
|
||||
if [[ ! -f "$path/logo.png" ]]; then
|
||||
|
||||
if [[ ! -f "$local_path/logo.png" ]]; then
|
||||
IMG=$(echo "$JSON" | jq -r '.hdmusiclogo[0].url // empty')
|
||||
|
||||
download_if_valid "$IMG" "$path/logo.png"
|
||||
download_if_valid "$IMG" "$local_path/logo.png"
|
||||
fi
|
||||
|
||||
# ================= banner.jpg =================
|
||||
|
||||
if [[ ! -f "$path/banner.jpg" ]]; then
|
||||
|
||||
if [[ ! -f "$local_path/banner.jpg" ]]; then
|
||||
IMG=$(echo "$JSON" | jq -r '.musicbanner[0].url // empty')
|
||||
|
||||
download_if_valid "$IMG" "$path/banner.jpg"
|
||||
download_if_valid "$IMG" "$local_path/banner.jpg"
|
||||
fi
|
||||
|
||||
) &
|
||||
|
||||
done
|
||||
done < <(echo "$artists" | jq -r '.[] | [.path, .foreignArtistId, .artistName] | @tsv')
|
||||
|
||||
wait
|
||||
|
||||
echo
|
||||
echo "===== COMPLETE ====="
|
||||
END=$(date +%s)
|
||||
|
||||
log "===== COMPLETE ====="
|
||||
# ==============================================================================================
|
||||
# ━━━ Summary ━━━
|
||||
# ==============================================================================================
|
||||
echo ""
|
||||
echo "━━━━━ $ICON_SUMMARY LIDARR MISSING ART SUMMARY ━━━━━"
|
||||
echo "$ICON_HOST Identity: $MY_ID ($LOCAL_SERVER_NAME)"
|
||||
echo "$ICON_TIME Duration: $(format_duration $((END - START)))"
|
||||
echo "$ICON_EMBY Albums: $ALBUMS_CHECKED checked, $ALBUMS_COMPLETE already complete"
|
||||
echo "$ICON_EMBY Artists: $ARTISTS_CHECKED checked, $ARTISTS_COMPLETE already complete"
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
echo "$ICON_WARN Status: DRY RUN — no files written"
|
||||
else
|
||||
echo "$ICON_DONE Status: $ICON_SUCCESS ALL DONE"
|
||||
notify "Lidarr art fetch complete on $(hostname) — ${ALBUMS_CHECKED} albums, ${ARTISTS_CHECKED} artists processed" "Lidarr Missing Art" "normal"
|
||||
fi
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
|
||||
exit 0
|
||||
|
||||
Reference in New Issue
Block a user