Add YAPF style + ignore, and format tracked Python files

This commit is contained in:
2025-12-29 18:42:02 -08:00
parent c019c00aed
commit 507946a3e4
108 changed files with 11664 additions and 6494 deletions

View File

@@ -16,7 +16,6 @@ try: # Optional dependency
except ImportError: # pragma: no cover - optional
musicbrainzngs = None
try: # Optional dependency
import yt_dlp # type: ignore
except ImportError: # pragma: no cover - optional
@@ -62,9 +61,18 @@ class ITunesProvider(MetadataProvider):
"""Metadata provider using the iTunes Search API."""
def search(self, query: str, limit: int = 10) -> List[Dict[str, Any]]:
params = {"term": query, "media": "music", "entity": "song", "limit": limit}
params = {
"term": query,
"media": "music",
"entity": "song",
"limit": limit
}
try:
resp = requests.get("https://itunes.apple.com/search", params=params, timeout=10)
resp = requests.get(
"https://itunes.apple.com/search",
params=params,
timeout=10
)
resp.raise_for_status()
results = resp.json().get("results", [])
except Exception as exc:
@@ -77,7 +85,8 @@ class ITunesProvider(MetadataProvider):
"title": r.get("trackName"),
"artist": r.get("artistName"),
"album": r.get("collectionName"),
"year": str(r.get("releaseDate", ""))[:4],
"year": str(r.get("releaseDate",
""))[:4],
"provider": self.name,
"raw": r,
}
@@ -100,17 +109,22 @@ class OpenLibraryMetadataProvider(MetadataProvider):
try:
# Prefer ISBN-specific search when the query looks like one
if query_clean.replace("-", "").isdigit() and len(query_clean.replace("-", "")) in (
10,
13,
):
if query_clean.replace("-",
"").isdigit() and len(query_clean.replace("-",
"")) in (
10,
13,
):
q = f"isbn:{query_clean.replace('-', '')}"
else:
q = query_clean
resp = requests.get(
"https://openlibrary.org/search.json",
params={"q": q, "limit": limit},
params={
"q": q,
"limit": limit
},
timeout=10,
)
resp.raise_for_status()
@@ -202,7 +216,10 @@ class GoogleBooksMetadataProvider(MetadataProvider):
return []
# Prefer ISBN queries when possible
if query_clean.replace("-", "").isdigit() and len(query_clean.replace("-", "")) in (10, 13):
if query_clean.replace("-",
"").isdigit() and len(query_clean.replace("-",
"")) in (10,
13):
q = f"isbn:{query_clean.replace('-', '')}"
else:
q = query_clean
@@ -210,7 +227,10 @@ class GoogleBooksMetadataProvider(MetadataProvider):
try:
resp = requests.get(
"https://www.googleapis.com/books/v1/volumes",
params={"q": q, "maxResults": limit},
params={
"q": q,
"maxResults": limit
},
timeout=10,
)
resp.raise_for_status()
@@ -228,7 +248,10 @@ class GoogleBooksMetadataProvider(MetadataProvider):
year = str(published_date)[:4] if published_date else ""
identifiers_raw = info.get("industryIdentifiers") or []
identifiers: Dict[str, Optional[str]] = {"googlebooks": volume.get("id")}
identifiers: Dict[str,
Optional[str]] = {
"googlebooks": volume.get("id")
}
for ident in identifiers_raw:
if not isinstance(ident, dict):
continue
@@ -253,7 +276,8 @@ class GoogleBooksMetadataProvider(MetadataProvider):
"authors": authors,
"publisher": publisher,
"identifiers": identifiers,
"description": info.get("description", ""),
"description": info.get("description",
""),
}
)
@@ -341,7 +365,8 @@ class ISBNsearchMetadataProvider(MetadataProvider):
if m_title:
title = self._strip_html_to_text(m_title.group(1))
raw_fields: Dict[str, str] = {}
raw_fields: Dict[str,
str] = {}
strong_matches = list(re.finditer(r"(?is)<strong\b[^>]*>(.*?)</strong>", html))
for idx, m in enumerate(strong_matches):
label_raw = self._strip_html_to_text(m.group(1))
@@ -354,13 +379,14 @@ class ISBNsearchMetadataProvider(MetadataProvider):
chunk_start = m.end()
# Stop at next <strong> or end of document.
chunk_end = (
strong_matches[idx + 1].start() if (idx + 1) < len(strong_matches) else len(html)
strong_matches[idx + 1].start() if
(idx + 1) < len(strong_matches) else len(html)
)
chunk = html[chunk_start:chunk_end]
# Prefer stopping within the same paragraph when possible.
m_end = re.search(r"(?is)(</p>|<br\s*/?>)", chunk)
if m_end:
chunk = chunk[: m_end.start()]
chunk = chunk[:m_end.start()]
val_text = self._strip_html_to_text(chunk)
if not val_text:
@@ -391,7 +417,9 @@ class ISBNsearchMetadataProvider(MetadataProvider):
authors: List[str] = []
if author_text:
# Split on common separators; keep multi-part names intact.
for part in re.split(r"\s*(?:,|;|\band\b|\&|\|)\s*", author_text, flags=re.IGNORECASE):
for part in re.split(r"\s*(?:,|;|\band\b|\&|\|)\s*",
author_text,
flags=re.IGNORECASE):
p = str(part or "").strip()
if p:
authors.append(p)
@@ -412,23 +440,28 @@ class ISBNsearchMetadataProvider(MetadataProvider):
if t and t not in isbn_tokens:
isbn_tokens.append(t)
item: Dict[str, Any] = {
"title": title or "",
# Keep UI columns compatible with the generic metadata table.
"artist": ", ".join(authors) if authors else "",
"album": publisher or "",
"year": year or "",
"provider": self.name,
"authors": authors,
"publisher": publisher or "",
"language": language or "",
"pages": pages or "",
"identifiers": {
"isbn_13": next((t for t in isbn_tokens if len(t) == 13), None),
"isbn_10": next((t for t in isbn_tokens if len(t) == 10), None),
},
"raw_fields": raw_fields,
}
item: Dict[str,
Any] = {
"title": title or "",
# Keep UI columns compatible with the generic metadata table.
"artist": ", ".join(authors) if authors else "",
"album": publisher or "",
"year": year or "",
"provider": self.name,
"authors": authors,
"publisher": publisher or "",
"language": language or "",
"pages": pages or "",
"identifiers": {
"isbn_13":
next((t for t in isbn_tokens if len(t) == 13),
None),
"isbn_10":
next((t for t in isbn_tokens if len(t) == 10),
None),
},
"raw_fields": raw_fields,
}
# Only return usable items.
if not item.get("title") and not any(item["identifiers"].values()):
@@ -495,7 +528,10 @@ class MusicBrainzMetadataProvider(MetadataProvider):
def search(self, query: str, limit: int = 10) -> List[Dict[str, Any]]:
if not musicbrainzngs:
log("musicbrainzngs is not installed; skipping MusicBrainz scrape", file=sys.stderr)
log(
"musicbrainzngs is not installed; skipping MusicBrainz scrape",
file=sys.stderr
)
return []
q = (query or "").strip()
@@ -526,12 +562,15 @@ class MusicBrainzMetadataProvider(MetadataProvider):
if isinstance(artist_credit, list) and artist_credit:
first = artist_credit[0]
if isinstance(first, dict):
artist = first.get("name") or first.get("artist", {}).get("name", "")
artist = first.get("name") or first.get("artist",
{}).get("name",
"")
elif isinstance(first, str):
artist = first
album = ""
release_list = rec.get("release-list") or rec.get("releases") or rec.get("release")
release_list = rec.get("release-list") or rec.get("releases"
) or rec.get("release")
if isinstance(release_list, list) and release_list:
first_rel = release_list[0]
if isinstance(first_rel, dict):
@@ -634,7 +673,8 @@ class YtdlpMetadataProvider(MetadataProvider):
upload_date = str(info.get("upload_date") or "")
release_date = str(info.get("release_date") or "")
year = (release_date or upload_date)[:4] if (release_date or upload_date) else ""
year = (release_date
or upload_date)[:4] if (release_date or upload_date) else ""
# Provide basic columns for the standard metadata selection table.
# NOTE: This is best-effort; many extractors don't provide artist/album.
@@ -716,15 +756,16 @@ class YtdlpMetadataProvider(MetadataProvider):
# Registry ---------------------------------------------------------------
_METADATA_PROVIDERS: Dict[str, Type[MetadataProvider]] = {
"itunes": ITunesProvider,
"openlibrary": OpenLibraryMetadataProvider,
"googlebooks": GoogleBooksMetadataProvider,
"google": GoogleBooksMetadataProvider,
"isbnsearch": ISBNsearchMetadataProvider,
"musicbrainz": MusicBrainzMetadataProvider,
"ytdlp": YtdlpMetadataProvider,
}
_METADATA_PROVIDERS: Dict[str,
Type[MetadataProvider]] = {
"itunes": ITunesProvider,
"openlibrary": OpenLibraryMetadataProvider,
"googlebooks": GoogleBooksMetadataProvider,
"google": GoogleBooksMetadataProvider,
"isbnsearch": ISBNsearchMetadataProvider,
"musicbrainz": MusicBrainzMetadataProvider,
"ytdlp": YtdlpMetadataProvider,
}
def register_provider(name: str, provider_cls: Type[MetadataProvider]) -> None:
@@ -732,7 +773,8 @@ def register_provider(name: str, provider_cls: Type[MetadataProvider]) -> None:
def list_metadata_providers(config: Optional[Dict[str, Any]] = None) -> Dict[str, bool]:
availability: Dict[str, bool] = {}
availability: Dict[str,
bool] = {}
for name, cls in _METADATA_PROVIDERS.items():
try:
_ = cls(config)
@@ -743,9 +785,10 @@ def list_metadata_providers(config: Optional[Dict[str, Any]] = None) -> Dict[str
return availability
def get_metadata_provider(
name: str, config: Optional[Dict[str, Any]] = None
) -> Optional[MetadataProvider]:
def get_metadata_provider(name: str,
config: Optional[Dict[str,
Any]] = None
) -> Optional[MetadataProvider]:
cls = _METADATA_PROVIDERS.get(name.lower())
if not cls:
return None