From 41bccb82b1fc8c85945b60b75750c7e452d20a3c Mon Sep 17 00:00:00 2001 From: sbcrumb Date: Sun, 12 Oct 2025 10:42:26 -0400 Subject: [PATCH 1/2] fix: Correct IMDb ID pattern matching in TV show webhook processing - Fix glob pattern to escape brackets for literal [imdb-ID] matching - Resolves issue where webhook for Girls (2012) [tt1723816] was incorrectly matching Gachiakuta (2025) [tt32612521] - Previous pattern treated brackets as character sets instead of literal strings --- utils/file_utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/file_utils.py b/utils/file_utils.py index 205be99..8bce466 100644 --- a/utils/file_utils.py +++ b/utils/file_utils.py @@ -62,7 +62,8 @@ def find_media_path_by_imdb_and_title( # Search by IMDb ID first (more reliable) if imdb_id: - pattern = str(media_path / f"*[imdb-{imdb_id}]*") + # Use proper glob pattern - escape brackets to match literal [imdb-ID] + pattern = str(media_path / f"*\\[imdb-{imdb_id}\\]*") matches = glob.glob(pattern) if matches: return Path(matches[0]) -- 2.39.5 From 348f83d547b66303b29e0f047961ae441497c7a9 Mon Sep 17 00:00:00 2001 From: sbcrumb Date: Sun, 12 Oct 2025 10:46:43 -0400 Subject: [PATCH 2/2] feat: Add comprehensive IMDb detection for TV shows - Add find_series_imdb_id method to check directory, filenames, and tvshow.nfo - Add TV show batch validation in webhook batcher (like movies) - Ensures TV webhooks process correct series by validating IMDb match - Prevents mismatched processing like Girls (2012) -> Gachiakuta (2025) - Comprehensive detection checks: folder name, file names, NFO content --- core/nfo_manager.py | 31 +++++++++++++++++++++++++++++++ webhooks/webhook_batcher.py | 27 ++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/core/nfo_manager.py b/core/nfo_manager.py index fc77d18..d387c5a 100644 --- a/core/nfo_manager.py +++ b/core/nfo_manager.py @@ -126,6 +126,37 @@ class NFOManager: print(f"❌ No IMDb or TMDB ID found in directory, filenames, or NFO for: {movie_dir.name}") return None + def find_series_imdb_id(self, series_dir: Path) -> Optional[str]: + """Find IMDb ID from TV series directory name, filenames, or tvshow.nfo file""" + print(f"🔍 Searching for IMDb ID in TV series: {series_dir.name}") + + # First try directory name + imdb_id = self.parse_imdb_from_path(series_dir) + if imdb_id: + print(f"✅ Found IMDb ID in series directory name: {imdb_id}") + return imdb_id + + # Try all files in the directory for IMDb ID patterns + for file_path in series_dir.iterdir(): + if file_path.is_file(): + imdb_id = self.parse_imdb_from_path(file_path) + if imdb_id: + print(f"✅ Found IMDb ID in series filename: {imdb_id} from {file_path.name}") + return imdb_id + + # Finally, try tvshow.nfo file content + nfo_path = series_dir / "tvshow.nfo" + imdb_id = self.parse_imdb_from_nfo(nfo_path) + if imdb_id: + if imdb_id.startswith("tmdb-"): + print(f"✅ Found TMDB ID in tvshow.nfo: {imdb_id} from {nfo_path} (fallback mode)") + else: + print(f"✅ Found IMDb ID in tvshow.nfo: {imdb_id} from {nfo_path}") + return imdb_id + + print(f"❌ No IMDb or TMDB ID found in series directory, filenames, or tvshow.nfo for: {series_dir.name}") + return None + def extract_nfoguard_dates_from_nfo(self, nfo_path: Path) -> Optional[Dict[str, str]]: """Extract NFOGuard-managed dates from existing NFO file""" if not nfo_path.exists(): diff --git a/webhooks/webhook_batcher.py b/webhooks/webhook_batcher.py index 3688057..0810791 100644 --- a/webhooks/webhook_batcher.py +++ b/webhooks/webhook_batcher.py @@ -107,8 +107,33 @@ class WebhookBatcher: return _log("DEBUG", f"Batch validation passed: IMDb {expected_imdb} found in path (fallback mode)") - # Process based on media type + # CRITICAL: Validate that the path contains the expected IMDb ID for TV shows if media_type == 'tv': + expected_imdb = key.replace('tv:', '') if key.startswith('tv:') else key + + # Use comprehensive IMDb detection (directory, filenames, tvshow.nfo files) + if self.nfo_manager: + detected_imdb = self.nfo_manager.find_series_imdb_id(path_obj) + imdb_match = False + if detected_imdb: + # Compare with and without 'tt' prefix for flexibility + if detected_imdb == expected_imdb or detected_imdb.replace('tt', '') == expected_imdb.replace('tt', ''): + imdb_match = True + + if not imdb_match: + _log("ERROR", f"BATCH VALIDATION FAILED: Expected IMDb {expected_imdb} not found via comprehensive detection in TV path {path_str}") + _log("ERROR", f"Detected TV IMDb: {detected_imdb}, Expected: {expected_imdb}") + _log("ERROR", f"This prevents processing wrong TV series due to batch corruption") + return + _log("DEBUG", f"TV batch validation passed: IMDb {expected_imdb} matches detected {detected_imdb}") + else: + # Fallback to simple string search if nfo_manager not available + if expected_imdb not in path_str.lower(): + _log("ERROR", f"BATCH VALIDATION FAILED: Expected IMDb {expected_imdb} not found in TV path {path_str} (fallback mode)") + _log("ERROR", f"This prevents processing wrong TV series due to batch corruption") + return + _log("DEBUG", f"TV batch validation passed: IMDb {expected_imdb} found in path (fallback mode)") + if not self.tv_processor: _log("ERROR", "TV processor not available") return -- 2.39.5