From 51be777e7d69fa2498061046cd4b6c321d75cec8 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 20 May 2026 19:38:37 +0200 Subject: [PATCH] fix: strip all trailing year suffixes to prevent duplication - series.py: use regex to remove all trailing (YYYY) before appending year - nfo_service.py: _extract_year_from_name strips all trailing year suffixes - nfo_repair_service.py: add _read_tmdb_id() helper to extract TMDB ID from NFO --- src/core/entities/series.py | 7 +++--- src/core/services/nfo_repair_service.py | 31 +++++++++++++++++++++++++ src/core/services/nfo_service.py | 5 ++-- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/core/entities/series.py b/src/core/entities/series.py index 3a743e2..3ab0f11 100644 --- a/src/core/entities/series.py +++ b/src/core/entities/series.py @@ -271,10 +271,11 @@ class Serie: 'Dororo (2025)' """ if self._year: + import re year_suffix = f" ({self._year})" - if self._name.endswith(year_suffix): - return self._name - return f"{self._name}{year_suffix}" + # Strip ALL trailing year suffixes before appending to prevent duplication + clean_name = re.sub(r'(\s*\(\d{4}\))+\s*$', '', self._name).strip() + return f"{clean_name}{year_suffix}" return self._name @property diff --git a/src/core/services/nfo_repair_service.py b/src/core/services/nfo_repair_service.py index ffc45b6..b97d7f6 100644 --- a/src/core/services/nfo_repair_service.py +++ b/src/core/services/nfo_repair_service.py @@ -120,6 +120,37 @@ def nfo_needs_repair(nfo_path: Path) -> bool: return bool(find_missing_tags(nfo_path)) +def _read_tmdb_id(nfo_path: Path) -> int | None: + """Return the TMDB ID stored in an existing NFO, or ``None``. + + Checks both ```` and ```` elements. + + Args: + nfo_path: Absolute path to the ``tvshow.nfo`` file. + + Returns: + Integer TMDB ID, or ``None`` if not found or not parseable. + """ + if not nfo_path.exists(): + return None + try: + root = etree.parse(str(nfo_path)).getroot() + + for uniqueid in root.findall(".//uniqueid"): + if uniqueid.get("type") == "tmdb" and uniqueid.text: + return int(uniqueid.text) + + tmdbid_elem = root.find(".//tmdbid") + if tmdbid_elem is not None and tmdbid_elem.text: + return int(tmdbid_elem.text) + + except (etree.XMLSyntaxError, ValueError): + pass + except Exception: # pylint: disable=broad-except + pass + return None + + class NfoRepairService: """Service that detects and repairs incomplete tvshow.nfo files. diff --git a/src/core/services/nfo_service.py b/src/core/services/nfo_service.py index 46d05f2..8274830 100644 --- a/src/core/services/nfo_service.py +++ b/src/core/services/nfo_service.py @@ -83,11 +83,12 @@ class NFOService: >>> _extract_year_from_name("Attack on Titan") ("Attack on Titan", None) """ - # Match year in parentheses at the end: (YYYY) + # Match the last year in parentheses at the end: (YYYY) match = re.search(r'\((\d{4})\)\s*$', serie_name) if match: year = int(match.group(1)) - clean_name = serie_name[:match.start()].strip() + # Strip ALL trailing year suffixes to get a fully clean name + clean_name = re.sub(r'(\s*\(\d{4}\))+\s*$', '', serie_name).strip() return clean_name, year return serie_name, None