Follow-up to the preferred-art feature. Real test runs showed a source could win on priority while handing back a small cover: Cover Art Archive is volunteer-uploaded with no size floor, so CAA-first gave a 599x531 (Taylor Swift) and a 600x600 (Kendrick GNX) -- front-1200 only caps the max, so a ~600px upload stays ~600px -- and Deezer/iTunes lower in the order never got a turn. Fix: - Minimum-resolution guard: artwork._min_size_art_validator builds the resolver's validate hook -- it fetches each candidate, caches the bytes (so the winner isn't fetched twice), and accepts art only when its shortest side >= metadata_enhancement.min_art_size (default 1000px; 0 disables). Art that's too small is a miss, so the resolver falls through to the next source instead of winning on priority. Unmeasurable images are accepted (don't over-reject; fallback is still today's art). Wired into both embed_album_art_metadata and download_cover_art. - iTunes art upgraded to /3000x3000bb/ (was the 600px default) so it contributes high-res when it wins. - select_preferred_art_url gains a validate passthrough to the resolver. - config default metadata_enhancement.min_art_size: 1000. Effect: with an order like caa > deezer > spotify > itunes, a ~600px CAA upload is now skipped and Deezer's ~1900px wins -- consistent big art. (Spotify art often maxes ~640px, so it's skipped at the 1000 floor in favor of bigger sources; lower min_art_size to ~640 to allow it.) Tests: tests/metadata/test_art_min_size.py (6 -- incl. the real 599x531 and 600x600 cases, shortest-side logic, unmeasurable-accept, no-bytes-reject, 0-disables) + iTunes max-res upgrade test. Full metadata suite green (617).
54 lines
1.8 KiB
Python
54 lines
1.8 KiB
Python
"""Tests for the minimum-resolution guard on preferred cover art.
|
|
|
|
A source's art is only accepted when its shortest side meets the threshold, so
|
|
a low-res cover (e.g. a small Cover Art Archive upload) is skipped and the
|
|
resolver falls through to the next source instead of winning on priority alone.
|
|
Reproduces the two real cases that motivated it: Taylor Swift 599x531 and
|
|
Kendrick GNX 600x600 — both rejected at the default 1000px floor.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import patch
|
|
|
|
from core.metadata import artwork
|
|
|
|
|
|
def _run(min_px, fetch_return, dims):
|
|
with patch.object(artwork, "_fetch_art_bytes", return_value=fetch_return), \
|
|
patch.object(artwork, "get_image_dimensions", return_value=dims):
|
|
validate, cache = artwork._min_size_art_validator(min_px)
|
|
return validate("deezer", "http://x/cover.jpg"), cache
|
|
|
|
|
|
def test_rejects_small_square_art():
|
|
ok, cache = _run(1000, (b"img", "image/jpeg"), (600, 600)) # GNX case
|
|
assert ok is False
|
|
# Bytes are cached even on reject (so a later accepted source reuses fetches).
|
|
assert cache["http://x/cover.jpg"] == (b"img", "image/jpeg")
|
|
|
|
|
|
def test_rejects_small_non_square_using_shortest_side():
|
|
ok, _ = _run(1000, (b"img", "image/jpeg"), (599, 531)) # Taylor case
|
|
assert ok is False
|
|
|
|
|
|
def test_accepts_big_art():
|
|
ok, cache = _run(1000, (b"img", "image/jpeg"), (1900, 1900))
|
|
assert ok is True
|
|
assert cache["http://x/cover.jpg"] == (b"img", "image/jpeg")
|
|
|
|
|
|
def test_accepts_unmeasurable_art_to_avoid_over_rejecting():
|
|
ok, _ = _run(1000, (b"img", "image/jpeg"), None)
|
|
assert ok is True
|
|
|
|
|
|
def test_rejects_when_fetch_returns_no_bytes():
|
|
ok, _ = _run(1000, (None, None), (4000, 4000))
|
|
assert ok is False
|
|
|
|
|
|
def test_zero_threshold_disables_the_gate():
|
|
ok, _ = _run(0, (b"img", "image/jpeg"), (10, 10))
|
|
assert ok is True
|