Add phone-based EAN scanning, scanner server for cover upload, Vision-LLM integration
New features: - EAN/Barcode can now be entered by typing or by photographing the CD sleeve; Vision-LLM (extract_barcode_from_image) reads the barcode from the photo - Scanner server (port 8765) starts at the beginning of every album loop, serving both EAN barcode scanning and back cover upload via QR code - Vision-LLM analyses back cover in background thread while ripping; priority: Vision-LLM > MusicBrainz > CDDB - _find_abcde_mbid reads MBID from abcde temp dirs for CAA cover download even when the CD barcode is not linked in MusicBrainz - Concrete copy-paste apply commands shown after each album in 'Next steps' - _sanitize_name: whitelist approach (removes brackets and punctuation) - qrcode added as dependency for terminal QR code display Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6c12510f76
commit
32c84b9edb
15 changed files with 1027 additions and 92 deletions
|
|
@ -160,11 +160,12 @@ class TestLookupByBarcode:
|
|||
patch("musiksammlung.musicbrainz.httpx.get", side_effect=responses),
|
||||
patch("musiksammlung.musicbrainz.time.sleep"),
|
||||
):
|
||||
album = lookup_by_barcode("0602557360561")
|
||||
album, mbid = lookup_by_barcode("0602557360561")
|
||||
|
||||
assert album.artist == "The Beatles"
|
||||
assert album.album == "Abbey Road"
|
||||
assert album.year == 1969
|
||||
assert mbid == "abc-123"
|
||||
|
||||
def test_raises_when_no_releases(self) -> None:
|
||||
empty = _mock_response({"releases": []})
|
||||
|
|
@ -173,7 +174,7 @@ class TestLookupByBarcode:
|
|||
patch("musiksammlung.musicbrainz.time.sleep"),
|
||||
pytest.raises(ValueError, match="Kein MusicBrainz-Eintrag"),
|
||||
):
|
||||
lookup_by_barcode("0000000000000")
|
||||
lookup_by_barcode("0000000000000") # raises before returning tuple
|
||||
|
||||
def test_uses_first_release(self) -> None:
|
||||
barcode_data = {"releases": [{"id": "first-id"}, {"id": "second-id"}]}
|
||||
|
|
@ -182,11 +183,12 @@ class TestLookupByBarcode:
|
|||
patch("musiksammlung.musicbrainz.httpx.get", side_effect=responses) as mock_get,
|
||||
patch("musiksammlung.musicbrainz.time.sleep"),
|
||||
):
|
||||
lookup_by_barcode("1234567890123")
|
||||
_album, mbid = lookup_by_barcode("1234567890123")
|
||||
|
||||
# Zweiter Request muss die MBID des ersten Treffers verwenden
|
||||
second_call_url = mock_get.call_args_list[1][0][0]
|
||||
assert "first-id" in second_call_url
|
||||
assert mbid == "first-id"
|
||||
|
||||
def test_rate_limit_sleep_is_called(self) -> None:
|
||||
responses = [_mock_response(_BARCODE_RESPONSE), _mock_response(_RELEASE_RESPONSE)]
|
||||
|
|
@ -194,7 +196,7 @@ class TestLookupByBarcode:
|
|||
patch("musiksammlung.musicbrainz.httpx.get", side_effect=responses),
|
||||
patch("musiksammlung.musicbrainz.time.sleep") as mock_sleep,
|
||||
):
|
||||
lookup_by_barcode("0602557360561")
|
||||
_album, _mbid = lookup_by_barcode("0602557360561")
|
||||
|
||||
mock_sleep.assert_called_once()
|
||||
assert mock_sleep.call_args[0][0] >= 1.0
|
||||
|
|
@ -206,4 +208,4 @@ class TestLookupByBarcode:
|
|||
patch("musiksammlung.musicbrainz.httpx.get", side_effect=httpx.HTTPError("timeout")),
|
||||
pytest.raises(httpx.HTTPError),
|
||||
):
|
||||
lookup_by_barcode("0000000000000")
|
||||
lookup_by_barcode("0000000000000") # raises before returning tuple
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue