summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-node')
-rw-r--r--packages/meshbay-node/src/meshbay_node/musicbrainz.py14
-rw-r--r--packages/meshbay-node/tests/test_musicbrainz.py17
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()