added lidar missing art checker
This commit is contained in:
@@ -0,0 +1,364 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==============================================================================================
|
||||
# ================================= Music Artwork Fetcher ======================================
|
||||
# ==============================================================================================
|
||||
#
|
||||
# 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
|
||||
|
||||
# ================================= CONFIG =====================================================
|
||||
|
||||
|
||||
LIDARR_URL="http://localhost:8686"
|
||||
LIDARR_API_KEY="b2977e71ef074bc0a0529d9fcce3b2dc"
|
||||
|
||||
FANART_API_KEY="Yd7147a43b692df0b364b94dc47efb81"
|
||||
LASTFM_API_KEY="be6dc169c33ae263e690c30d18b7491d"
|
||||
|
||||
LOG="/tmp/artfetch.log"
|
||||
|
||||
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"
|
||||
fi
|
||||
|
||||
# ================================= LOGGING ====================================================
|
||||
|
||||
log() {
|
||||
echo "$(date '+%F %T') | $1" >> "$LOG"
|
||||
}
|
||||
|
||||
# ================================= HELPERS ====================================================
|
||||
|
||||
curl_json() {
|
||||
curl -s \
|
||||
--connect-timeout 5 \
|
||||
--max-time 20 \
|
||||
"$1"
|
||||
}
|
||||
|
||||
job_count() {
|
||||
jobs -rp | wc -l
|
||||
}
|
||||
|
||||
wait_for_slot() {
|
||||
while (( $(job_count) >= MAX_PARALLEL )); do
|
||||
sleep 0.2
|
||||
done
|
||||
}
|
||||
|
||||
# ================================= DOWNLOAD ===================================================
|
||||
|
||||
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"
|
||||
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
|
||||
mv "$tmp" "$dest"
|
||||
log "[OK] $dest"
|
||||
return 0
|
||||
fi
|
||||
|
||||
rm -f "$tmp"
|
||||
sleep 1
|
||||
done
|
||||
|
||||
log "[FAIL] $dest"
|
||||
return 1
|
||||
}
|
||||
|
||||
# ================================= DEEZER =====================================================
|
||||
|
||||
deezer_artist_image() {
|
||||
|
||||
local artist="$1"
|
||||
|
||||
query=$(printf "%s" "$artist" | sed 's/ /+/g')
|
||||
|
||||
curl_json \
|
||||
"https://api.deezer.com/search/artist?q=$query" |
|
||||
jq -r '.data[0].picture_xl // empty'
|
||||
}
|
||||
|
||||
# ================================= LASTFM =====================================================
|
||||
|
||||
lastfm_artist_image() {
|
||||
|
||||
local artist="$1"
|
||||
|
||||
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" |
|
||||
jq -r '.artist.image[-1]["#text"] // empty'
|
||||
}
|
||||
|
||||
# ==============================================================================================
|
||||
# ====================================== ALBUMS =================================================
|
||||
# ==============================================================================================
|
||||
|
||||
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"
|
||||
exit 1
|
||||
}
|
||||
|
||||
total_albums=$(echo "$albums" | jq '. | length')
|
||||
album_count=0
|
||||
|
||||
echo "$albums" | jq -c '.[]?' | while read -r album; do
|
||||
|
||||
((album_count++))
|
||||
|
||||
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')
|
||||
|
||||
[[ ! -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"
|
||||
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"
|
||||
fi
|
||||
|
||||
# ================= COVER =================
|
||||
|
||||
if [[ ! -f "$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"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ================= CDART =================
|
||||
|
||||
if [[ ! -f "$path/cdart.png" ]]; then
|
||||
|
||||
IMG=$(echo "$JSON" | jq -r '.[].cdart[0].url // empty')
|
||||
|
||||
download_if_valid "$IMG" "$path/cdart.png"
|
||||
fi
|
||||
|
||||
# ================= BACK =================
|
||||
|
||||
if [[ ! -f "$path/back.jpg" ]]; then
|
||||
|
||||
IMG=$(echo "$JSON" | jq -r '.[].albumback[0].url // empty')
|
||||
|
||||
download_if_valid "$IMG" "$path/back.jpg"
|
||||
fi
|
||||
|
||||
) &
|
||||
|
||||
done
|
||||
|
||||
wait
|
||||
|
||||
# ==============================================================================================
|
||||
# ====================================== ARTISTS ================================================
|
||||
# ==============================================================================================
|
||||
|
||||
echo
|
||||
echo "===== PROCESSING ARTISTS ====="
|
||||
|
||||
artists=$(curl_json \
|
||||
"$LIDARR_URL/api/v1/artist?apikey=$LIDARR_API_KEY")
|
||||
|
||||
[[ -z "$artists" || "$artists" == "null" ]] && {
|
||||
echo "ERROR: Lidarr artist API failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
total_artists=$(echo "$artists" | jq '. | length')
|
||||
artist_count=0
|
||||
|
||||
echo "$artists" | jq -c '.[]?' | while read -r artist; do
|
||||
|
||||
((artist_count++))
|
||||
|
||||
path=$(echo "$artist" | jq -r '.path')
|
||||
mbid=$(echo "$artist" | jq -r '.foreignArtistId')
|
||||
name=$(echo "$artist" | jq -r '.artistName')
|
||||
|
||||
[[ ! -d "$path" ]] && continue
|
||||
[[ -z "$mbid" || "$mbid" == "null" ]] && continue
|
||||
|
||||
printf '[ARTIST %s/%s] %s\n' \
|
||||
"$artist_count" "$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"
|
||||
continue
|
||||
fi
|
||||
|
||||
wait_for_slot
|
||||
|
||||
(
|
||||
|
||||
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
|
||||
|
||||
IMG=$(echo "$JSON" | jq -r '.artistthumb[0].url // empty')
|
||||
|
||||
if ! download_if_valid "$IMG" "$path/folder.jpg"; then
|
||||
|
||||
IMG=$(deezer_artist_image "$name")
|
||||
|
||||
if ! download_if_valid "$IMG" "$path/folder.jpg"; then
|
||||
|
||||
IMG=$(lastfm_artist_image "$name")
|
||||
|
||||
download_if_valid "$IMG" "$path/folder.jpg"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# ================= fanart.jpg =================
|
||||
|
||||
if [[ ! -f "$path/fanart.jpg" ]]; then
|
||||
|
||||
IMG=$(echo "$JSON" | jq -r '.artistbackground[0].url // empty')
|
||||
|
||||
if ! download_if_valid "$IMG" "$path/fanart.jpg"; then
|
||||
|
||||
IMG=$(deezer_artist_image "$name")
|
||||
|
||||
download_if_valid "$IMG" "$path/fanart.jpg"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ================= logo.png =================
|
||||
|
||||
if [[ ! -f "$path/logo.png" ]]; then
|
||||
|
||||
IMG=$(echo "$JSON" | jq -r '.hdmusiclogo[0].url // empty')
|
||||
|
||||
download_if_valid "$IMG" "$path/logo.png"
|
||||
fi
|
||||
|
||||
# ================= banner.jpg =================
|
||||
|
||||
if [[ ! -f "$path/banner.jpg" ]]; then
|
||||
|
||||
IMG=$(echo "$JSON" | jq -r '.musicbanner[0].url // empty')
|
||||
|
||||
download_if_valid "$IMG" "$path/banner.jpg"
|
||||
fi
|
||||
|
||||
) &
|
||||
|
||||
done
|
||||
|
||||
wait
|
||||
|
||||
echo
|
||||
echo "===== COMPLETE ====="
|
||||
|
||||
log "===== COMPLETE ====="
|
||||
Reference in New Issue
Block a user