- introduce the in-process metadata engine and fresh provider adapters - normalize external identity through source_id while keeping id as a compatibility alias - route metadata callers through the new seam and add regression coverage
71 lines
1.9 KiB
Python
71 lines
1.9 KiB
Python
"""Typed metadata engine contracts."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import Any, Generic, Literal, Optional, Sequence, TypeVar
|
|
|
|
T = TypeVar("T")
|
|
|
|
MetadataEntityKind = Literal["artist", "album", "track"]
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class MetadataSearchRequest:
|
|
entity_kind: MetadataEntityKind
|
|
query: str
|
|
limit: int = 20
|
|
source_override: Optional[str] = None
|
|
enabled_sources: Optional[Sequence[str]] = None
|
|
allow_fallback: bool = True
|
|
skip_cache: bool = False
|
|
max_pages: int = 0
|
|
dedup_variants: bool = True
|
|
artist_source_ids: Optional[dict[str, str]] = None
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class MetadataLookupRequest:
|
|
entity_kind: MetadataEntityKind
|
|
entity_id: str
|
|
source_override: Optional[str] = None
|
|
enabled_sources: Optional[Sequence[str]] = None
|
|
allow_fallback: bool = True
|
|
skip_cache: bool = False
|
|
include_tracks: bool = True
|
|
limit: int = 50
|
|
max_pages: int = 0
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class MetadataSearchOutcome(Generic[T]):
|
|
items: list[T] = field(default_factory=list)
|
|
source: Optional[str] = None
|
|
attempted_sources: tuple[str, ...] = ()
|
|
cache_hit: bool = False
|
|
status: str = "miss"
|
|
errors: tuple[str, ...] = ()
|
|
raw_payload: Any = None
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class MetadataLookupOutcome(Generic[T]):
|
|
value: Optional[T] = None
|
|
source: Optional[str] = None
|
|
attempted_sources: tuple[str, ...] = ()
|
|
cache_hit: bool = False
|
|
status: str = "miss"
|
|
errors: tuple[str, ...] = ()
|
|
raw_payload: Any = None
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class MetadataProviderStatus:
|
|
provider: str
|
|
configured: bool
|
|
available: bool
|
|
authenticated: bool = False
|
|
rate_limited: bool = False
|
|
retry_after: Optional[int] = None
|
|
last_error: Optional[str] = None
|
|
details: dict[str, Any] = field(default_factory=dict)
|