MusicBrainz: Add project URL to User-Agent per API requirements

MusicBrainz mandates a meaningful User-Agent with contact info, warning
that bare strings can trigger IP blocking under load. Our client was
sending `SoulSync/2.3` with no contact — and the search adapter passed
an app version hard-coded at "2.3" that's now stale (UI is at 2.40).

Fix: default contact to the project URL (`https://github.com/Nezreka/SoulSync`)
when no email is supplied, so every request lands as
`SoulSync/<version> ( https://github.com/Nezreka/SoulSync )`. Drop the
search-adapter version suffix to a generic "2" since the exact UI minor
version would add noise to every MB request without helping operators
track issues.

Reference: https://musicbrainz.org/doc/MusicBrainz_API — "it is
important that your application sets a proper User-Agent string."
pull/372/head
Broque Thomas 1 month ago
parent 7285c6f55a
commit 3c48508c3f

@ -44,28 +44,31 @@ def rate_limited(func):
class MusicBrainzClient:
"""Client for interacting with MusicBrainz API"""
BASE_URL = "https://musicbrainz.org/ws/2"
# MusicBrainz mandates a meaningful User-Agent with contact info. Falling back
# to a bare name/version risks IP blocking under load — include the project
# URL so MB operators have a way to reach us if we misbehave.
DEFAULT_CONTACT = "https://github.com/Nezreka/SoulSync"
def __init__(self, app_name: str = "SoulSync", app_version: str = "1.0", contact_email: str = ""):
"""
Initialize MusicBrainz client
Args:
app_name: Name of the application
app_version: Version of the application
contact_email: Contact email (optional but recommended)
contact_email: Contact email or URL (defaults to project URL when empty)
"""
self.user_agent = f"{app_name}/{app_version}"
if contact_email:
self.user_agent += f" ( {contact_email} )"
contact = contact_email or self.DEFAULT_CONTACT
self.user_agent = f"{app_name}/{app_version} ( {contact} )"
self.session = requests.Session()
self.session.headers.update({
'User-Agent': self.user_agent,
'Accept': 'application/json'
})
logger.info(f"MusicBrainz client initialized with user agent: {self.user_agent}")
@rate_limited

@ -116,7 +116,10 @@ class MusicBrainzSearchClient:
def __init__(self):
from core.musicbrainz_client import MusicBrainzClient
self._client = MusicBrainzClient("SoulSync", "2.3")
# Client defaults to the project URL as its User-Agent contact,
# which is what MusicBrainz wants. Version stays generic ("2") —
# the exact UI minor version would add noise to every request.
self._client = MusicBrainzClient("SoulSync", "2")
self._art_cache: Dict[str, Optional[str]] = {} # mbid -> url
def _cached_art(self, release_mbid: str, release_group_mbid: str = '') -> Optional[str]:

Loading…
Cancel
Save