feat: complete multiplatform pipeline hardening, neutral anchor scoring, and automated health checks
This commit is contained in:
1 parent
56cbd08248
commit
66db687a58
11 files changed
+1097
-1005
No files matched your search
@@ -0,0 +1,71 @@
|
||||
"""
|
||||
collectors/social_fallback_collector.py
|
||||
Resolves missing Instagram handles via the official MusicBrainz REST API.
|
||||
Extracts verified url-rel claims without scraping search engines.
|
||||
"""
|
||||
|
||||
import re
|
||||
import time
|
||||
import requests
|
||||
from typing import Optional, Dict, List
|
||||
|
||||
MB_BASE_URL = "https://musicbrainz.org/ws/2/artist/"
|
||||
HEADERS = {
|
||||
"User-Agent": "HIFFIArtistIntelligence/1.0 (sri@superlabs.ai)",
|
||||
"Accept": "application/json"
|
||||
}
|
||||
|
||||
def resolve_musicbrainz_instagram(artist_name: str) -> Optional[str]:
|
||||
"""
|
||||
Searches MusicBrainz for the artist and inspects url-rels for Instagram profiles.
|
||||
"""
|
||||
search_url = f"{MB_BASE_URL}?query=artist:{requests.utils.quote(artist_name)}&fmt=json&limit=3"
|
||||
try:
|
||||
res = requests.get(search_url, headers=HEADERS, timeout=8)
|
||||
if res.status_code != 200:
|
||||
return None
|
||||
|
||||
artists = res.json().get("artists", [])
|
||||
if not artists:
|
||||
return None
|
||||
|
||||
# Check top matches
|
||||
for artist in artists:
|
||||
mbid = artist.get("id")
|
||||
if not mbid:
|
||||
continue
|
||||
|
||||
rel_url = f"{MB_BASE_URL}{mbid}?inc=url-rels&fmt=json"
|
||||
time.sleep(1.0) # MusicBrainz rate limit compliance: 1 req/sec
|
||||
rel_res = requests.get(rel_url, headers=HEADERS, timeout=8)
|
||||
if rel_res.status_code == 200:
|
||||
relations = rel_res.json().get("relations", [])
|
||||
for rel in relations:
|
||||
target = rel.get("url", {}).get("resource", "")
|
||||
if "instagram.com" in target:
|
||||
match = re.search(r"instagram\.com/([A-Za-z0-9_.]+)", target)
|
||||
if match:
|
||||
handle = match.group(1).lower().rstrip("/.")
|
||||
if handle not in {"p", "reel", "explore"}:
|
||||
return handle
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class SocialFallbackResolver:
|
||||
def resolve_handles(self, artist_names: List[str]) -> Dict[str, Optional[str]]:
|
||||
results = {}
|
||||
for name in artist_names:
|
||||
results[name] = resolve_musicbrainz_instagram(name)
|
||||
return results
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
resolver = SocialFallbackResolver()
|
||||
test_cohort = ["Rylo Rodriguez", "Q Da Fool", "Flatbush Zombies"]
|
||||
print("Testing MusicBrainz Entity Fallback Resolver:")
|
||||
for artist in test_cohort:
|
||||
h = resolve_musicbrainz_instagram(artist)
|
||||
print(f" {artist} -> @{h}")
|
||||
Reference in new issue
Block a user