Add Discogs as cover source fallback after MusicBrainz
- _discogs_cover_url(): searches Discogs database/search API by artist+album, returns primary image URL; uses DISCOGS_TOKEN if set, else anonymous - download_discogs_cover(): downloads and saves as folder.jpg (PNG→JPEG via PIL) - resolve_cover() priority: local → MusicBrainz → Discogs - music_enricher: pass artist/album to resolve_cover() for Discogs lookup Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8212a918dd
commit
031e595ff7
2 changed files with 64 additions and 0 deletions
|
|
@ -221,10 +221,67 @@ def embed_cover(audio_path: Path, cover_path: Path) -> bool:
|
|||
return False
|
||||
|
||||
|
||||
def _discogs_cover_url(artist: Optional[str], album: Optional[str]) -> Optional[str]:
|
||||
"""Sucht auf Discogs nach artist+album und gibt die primäre Image-URL zurück."""
|
||||
if not HAS_REQUESTS or not artist or not album:
|
||||
return None
|
||||
import os
|
||||
token = os.getenv("DISCOGS_TOKEN", "")
|
||||
headers = {"User-Agent": "MusicMetadataEnricher/1.0"}
|
||||
if token:
|
||||
headers["Authorization"] = f"Discogs token={token}"
|
||||
try:
|
||||
r = requests.get(
|
||||
"https://api.discogs.com/database/search",
|
||||
params={"artist": artist, "release_title": album, "type": "release", "per_page": 3},
|
||||
headers=headers,
|
||||
timeout=10,
|
||||
)
|
||||
if r.status_code != 200:
|
||||
return None
|
||||
results = r.json().get("results", [])
|
||||
for result in results:
|
||||
cover = result.get("cover_image") or result.get("thumb")
|
||||
if cover and "spacer" not in cover:
|
||||
return cover
|
||||
except Exception as e:
|
||||
print(f" ⚠️ Discogs-Suchfehler: {e}", file=sys.stderr)
|
||||
return None
|
||||
|
||||
|
||||
def download_discogs_cover(artist: Optional[str], album: Optional[str], dest_dir: Path) -> Optional[Path]:
|
||||
url = _discogs_cover_url(artist, album)
|
||||
if not url:
|
||||
return None
|
||||
dest = dest_dir / "folder.jpg"
|
||||
try:
|
||||
r = requests.get(url, timeout=15, headers={"User-Agent": "MusicMetadataEnricher/1.0"})
|
||||
if r.status_code != 200:
|
||||
return None
|
||||
ct = r.headers.get("content-type", "")
|
||||
if ("png" in ct or url.lower().endswith(".png")) and HAS_PIL:
|
||||
import io
|
||||
with Image.open(io.BytesIO(r.content)) as img:
|
||||
buf = io.BytesIO()
|
||||
img.convert("RGB").save(buf, format="JPEG", quality=92)
|
||||
dest.write_bytes(buf.getvalue())
|
||||
else:
|
||||
dest.write_bytes(r.content)
|
||||
if _image_ok(dest):
|
||||
return dest
|
||||
dest.unlink(missing_ok=True)
|
||||
except Exception as e:
|
||||
print(f" ⚠️ Discogs-Cover-Fehler: {e}", file=sys.stderr)
|
||||
dest.unlink(missing_ok=True)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_cover(
|
||||
image_files: List[Path],
|
||||
release_mbid: Optional[str],
|
||||
album_dir: Path,
|
||||
artist: Optional[str] = None,
|
||||
album: Optional[str] = None,
|
||||
) -> tuple[Optional[Path], Optional[str]]:
|
||||
"""Returns (cover_path, source_label)."""
|
||||
local = find_local_cover(image_files)
|
||||
|
|
@ -237,4 +294,9 @@ def resolve_cover(
|
|||
if downloaded:
|
||||
return downloaded, "musicbrainz"
|
||||
|
||||
if artist or album:
|
||||
downloaded = download_discogs_cover(artist, album, album_dir)
|
||||
if downloaded:
|
||||
return downloaded, "discogs"
|
||||
|
||||
return None, None
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue