Migrate from Poetry and pyenv to uv

This commit is contained in:
2026-10-12 15:48:26 +02:00
parent c399a6aed3
commit c69f5f9166
93 changed files with 13068 additions and 2401 deletions
+12 -12
View File
@@ -10,23 +10,23 @@ For a flat pool file ``Title (rok) [tmdbid].mkv`` the sidecar is
Both are found. Missing or unparsable NFO → ``None`` (the movie simply has no
genres until Jellyfin has scanned it).
"""
import xml.etree.ElementTree as ET
from dataclasses import dataclass, field
from pathlib import Path
from typing import Optional
@dataclass
class NfoData:
"""The bits of a movie ``.nfo`` Curator uses."""
title: Optional[str] = None
year: Optional[str] = None # four-digit string
title: str | None = None
year: str | None = None # four-digit string
genres: list[str] = field(default_factory=list)
countries: list[str] = field(default_factory=list)
rating: Optional[int] = None # 0–100 (NFO 0–10 scaled up), or None
tmdb_id: Optional[int] = None
csfd_url: Optional[str] = None # ČSFD film URL, if the NFO carries a csfd id
rating: int | None = None # 0–100 (NFO 0–10 scaled up), or None
tmdb_id: int | None = None
csfd_url: str | None = None # ČSFD film URL, if the NFO carries a csfd id
def field_values(self, name: str) -> list[str]:
"""Values for a tag-schema source field (genres/countries/year/rating)."""
@@ -41,7 +41,7 @@ class NfoData:
return []
def find_nfo(video_path: Path) -> Optional[Path]:
def find_nfo(video_path: Path) -> Path | None:
"""Locate the ``.nfo`` for a movie: sibling ``<stem>.nfo`` or ``movie.nfo``."""
video_path = Path(video_path)
sibling = video_path.with_suffix(".nfo")
@@ -57,7 +57,7 @@ def _texts(root: ET.Element, tag: str) -> list[str]:
return [e.text.strip() for e in root.findall(tag) if e.text and e.text.strip()]
def _parse_rating(root: ET.Element) -> Optional[int]:
def _parse_rating(root: ET.Element) -> int | None:
"""Read a 0–10 NFO rating and scale it to 0–100 (to match the old bands)."""
raw = root.findtext("rating")
if raw is None:
@@ -71,7 +71,7 @@ def _parse_rating(root: ET.Element) -> Optional[int]:
return None
def _parse_tmdb_id(root: ET.Element) -> Optional[int]:
def _parse_tmdb_id(root: ET.Element) -> int | None:
for uid in root.findall("uniqueid"):
if uid.get("type") == "tmdb" and uid.text and uid.text.strip().isdigit():
return int(uid.text.strip())
@@ -79,7 +79,7 @@ def _parse_tmdb_id(root: ET.Element) -> Optional[int]:
return int(raw.strip()) if raw and raw.strip().isdigit() else None
def _parse_csfd_url(root: ET.Element) -> Optional[str]:
def _parse_csfd_url(root: ET.Element) -> str | None:
"""A ČSFD film URL from the NFO, if any.
Czech Kodi scrapers record ČSFD as ``<uniqueid type="csfd">`` (a bare id or a
@@ -102,14 +102,14 @@ def _parse_csfd_url(root: ET.Element) -> Optional[str]:
return None
def read_nfo(video_path: Path) -> Optional[NfoData]:
def read_nfo(video_path: Path) -> NfoData | None:
"""Read the movie's ``.nfo`` into :class:`NfoData`, or None if absent/broken."""
path = find_nfo(video_path)
if path is None:
return None
try:
root = ET.parse(path).getroot()
except (ET.ParseError, OSError):
except ET.ParseError, OSError:
return None
year = root.findtext("year")