diff options
Diffstat (limited to 'packages/meshbay-node')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/musicbrainz.py | 14 | ||||
| -rw-r--r-- | packages/meshbay-node/tests/test_musicbrainz.py | 17 |
2 files changed, 30 insertions, 1 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/musicbrainz.py b/packages/meshbay-node/src/meshbay_node/musicbrainz.py index 59f3778..d5ca1e9 100644 --- a/packages/meshbay-node/src/meshbay_node/musicbrainz.py +++ b/packages/meshbay-node/src/meshbay_node/musicbrainz.py @@ -105,12 +105,24 @@ class MusicBrainzClient: self._client = httpx.AsyncClient(timeout=_TIMEOUT, transport=transport) self._rate_lock = asyncio.Lock() self._last_request_monotonic: float | None = None + self._warned_no_contact = False async def close(self) -> None: await self._client.aclose() async def _resolve_contact(self) -> str | None: - return self._owner_email or None + if self._owner_email: + return self._owner_email + # Staying inert is deliberate (see the module docstring), but doing it + # silently is not: the operator sees Music tiles with no metadata and + # nothing anywhere says why. Once per client, not per lookup. + if not self._warned_no_contact: + self._warned_no_contact = True + log.warning( + "MusicBrainz lookups are inert: the node owner's hub account has " + "no email on file, and the usage policy requires a contact in the " + "User-Agent. Music tiles will show no metadata or cover art.") + return None async def _pace(self) -> None: """Serializes every call through this client to >= _MIN_INTERVAL_SECS apart.""" diff --git a/packages/meshbay-node/tests/test_musicbrainz.py b/packages/meshbay-node/tests/test_musicbrainz.py index 843a691..cff7fea 100644 --- a/packages/meshbay-node/tests/test_musicbrainz.py +++ b/packages/meshbay-node/tests/test_musicbrainz.py @@ -246,3 +246,20 @@ async def test_calls_are_paced_at_least_min_interval_apart(): assert elapsed >= _MIN_INTERVAL_SECS * 0.9 await client.close() + + +@pytest.mark.asyncio +async def test_a_missing_contact_is_reported_once_not_silently(caplog): + """Staying inert is the policy; staying quiet about it left an operator with + blank Music tiles and nothing to search for.""" + def handle(request: httpx.Request) -> httpx.Response: # pragma: no cover + raise AssertionError("no request may be sent without a contact") + + client = MusicBrainzClient(owner_email="", transport=httpx.MockTransport(handle)) + with caplog.at_level("WARNING"): + await client.search_release("Anyone", "Anything") + await client.search_release("Anyone Else", "Anything Else") + + warnings = [r for r in caplog.records if "MusicBrainz lookups are inert" in r.message] + assert len(warnings) == 1, "warn once per client, not once per lookup" + await client.close() |