feat: enricher: +1

This commit is contained in:
2026-04-05 01:52:19 +02:00
parent d8c3813e39
commit 1ed51fdbdb
10 changed files with 97 additions and 10 deletions
+80
View File
@@ -0,0 +1,80 @@
"""
Author: Uyanide pywang0608@foxmail.com
Date: 2026-04-05 02:13:49
Description: Musixmatch metadata enricher (matcher.track.get by Spotify track ID)
"""
from typing import Optional
from urllib.parse import urlencode
import httpx
from loguru import logger
from .base import BaseEnricher
from ..models import TrackMeta
from ..config import (
HTTP_TIMEOUT,
MUSIXMATCH_TRACK_MATCH_URL,
MUSIXMATCH_USERTOKEN,
)
_MXM_HEADERS = {"Cookie": "x-mxm-token-guid="}
_MXM_TRACK_MATCH_BASE_PARAMS = {
"format": "json",
"app_id": "web-desktop-app-v1.0",
"usertoken": MUSIXMATCH_USERTOKEN,
}
class MusixmatchSpotifyEnricher(BaseEnricher):
"""Fill title, artist, album, and length from Musixmatch using Spotify track ID."""
@property
def name(self) -> str:
return "musixmatch"
@property
def provides(self) -> set[str]:
return {"title", "artist", "album", "length"}
async def enrich(self, track: TrackMeta) -> Optional[dict]:
if not track.trackid or not MUSIXMATCH_USERTOKEN:
return None
params = {
**_MXM_TRACK_MATCH_BASE_PARAMS,
"track_spotify_id": track.trackid,
}
url = f"{MUSIXMATCH_TRACK_MATCH_URL}?{urlencode(params)}"
logger.debug(f"Musixmatch enricher: looking up trackid={track.trackid}")
try:
async with httpx.AsyncClient(timeout=HTTP_TIMEOUT) as client:
resp = await client.get(url, headers=_MXM_HEADERS)
resp.raise_for_status()
data = resp.json()
except Exception as e:
logger.warning(f"Musixmatch enricher: request failed: {e}")
return None
body = data.get("message", {}).get("body")
t = body.get("track") if isinstance(body, dict) else None
if not isinstance(t, dict):
logger.debug(
f"Musixmatch enricher: no track data for trackid={track.trackid}"
)
return None
updates: dict = {}
if isinstance(t.get("track_name"), str) and t["track_name"]:
updates["title"] = t["track_name"]
if isinstance(t.get("artist_name"), str) and t["artist_name"]:
updates["artist"] = t["artist_name"]
if isinstance(t.get("album_name"), str) and t["album_name"]:
updates["album"] = t["album_name"]
if isinstance(t.get("track_length"), int) and t["track_length"] > 0:
updates["length"] = t["track_length"] * 1000
if updates:
logger.debug(f"Musixmatch enricher: filled {list(updates.keys())}")
return updates or None