Add iTunes and AcoustID as additional free music enrichment sources

- itunes.py: zero-auth fallback for album artwork when MusicBrainz/Cover Art
  Archive has no match — kicks in automatically during music enrichment,
  toggleable in Settings (on by default, no key required).
- acoustid.py: audio fingerprint identification (Chromaprint fpcalc + the
  AcoustID API) for tracks with missing/unknown artist or album — nothing
  to text-search on, so this identifies from the actual audio content
  instead. Requires a free user-supplied API key from acoustid.org/api-key,
  off by default. New /music/identify endpoint + admin trigger button.
- Dockerfile: added libchromaprint-tools for fpcalc.
- Settings page: new Music Metadata & Artwork section with both toggles.
This commit is contained in:
Myron Blair
2026-07-27 21:03:59 -05:00
parent 628a729afd
commit 671074764e
6 changed files with 299 additions and 7 deletions
+32
View File
@@ -0,0 +1,32 @@
"""iTunes Search API client — free, no API key, no auth, no rate-limit registration.
Used as a fallback when MusicBrainz + Cover Art Archive has no match/art for a release.
"""
import requests
from typing import Optional, Dict
ITUNES_BASE = "https://itunes.apple.com/search"
def lookup_album(artist: str, album: str) -> Optional[Dict]:
"""Best-effort match for an artist+album against the iTunes Store catalog."""
try:
r = requests.get(ITUNES_BASE, params={
"term": f"{artist} {album}", "media": "music", "entity": "album", "limit": 1,
}, timeout=15)
r.raise_for_status()
results = (r.json() or {}).get("results") or []
except Exception:
return None
if not results:
return None
res = results[0]
art = res.get("artworkUrl100")
if art:
# iTunes serves a small default; the same CDN path accepts arbitrary sizes.
art = art.replace("100x100bb", "1200x1200bb")
return {
"title": res.get("collectionName") or album,
"artist": res.get("artistName") or artist,
"year": (res.get("releaseDate") or "")[:4] or None,
"art_url": art,
}