From 1bf2725a5b8a7402ec1b53f4d8bdc744fddbf449 Mon Sep 17 00:00:00 2001 From: SBCrumb Date: Sat, 13 Sep 2025 19:15:22 -0400 Subject: [PATCH] iupdate --- nfoguard.py | 92 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 74 insertions(+), 18 deletions(-) diff --git a/nfoguard.py b/nfoguard.py index 80f633c..48d164d 100644 --- a/nfoguard.py +++ b/nfoguard.py @@ -619,39 +619,51 @@ class TVProcessor: return episode_dates def _get_single_episode_date(self, imdb_id: str, season_num: int, episode_num: int, series_metadata: Optional[Dict[str, Any]] = None) -> Tuple[Optional[str], Optional[str], str]: - """Get date info for a single episode""" - # Try database first + """ + Get date info for a single episode during backfill scans. + Priority: 1) Database 2) Sonarr import history 3) Air dates + """ + # Step 1: Try database first existing = self.db.get_episode_date(imdb_id, season_num, episode_num) if existing and existing.get("dateadded"): - return existing.get("aired"), existing["dateadded"], existing.get("source", "database") + _log("DEBUG", f"Using existing database entry for S{season_num:02d}E{episode_num:02d}") + return existing.get("aired"), existing["dateadded"], existing.get("source", "database:existing") - # Try Sonarr API if metadata available - if series_metadata and "episodes" in series_metadata: - for episode in series_metadata["episodes"]: - if episode.get("seasonNumber") == season_num and episode.get("episodeNumber") == episode_num: - aired = episode.get("airDateUtc") - if aired: - return aired, aired, "sonarr:episode.airDateUtc" + # Step 2: Try Sonarr import history (the real import date) + aired = None + import_date = None - # Try Sonarr API history if self.sonarr.enabled: try: - # Get episode ID from Sonarr series = self.sonarr.series_by_imdb(imdb_id) if series: episodes = self.sonarr.episodes_for_series(series["id"]) for ep in episodes: if ep.get("seasonNumber") == season_num and ep.get("episodeNumber") == episode_num: + aired = ep.get("airDateUtc") import_date = self.sonarr.get_episode_import_history(ep["id"]) if import_date: - return ep.get("airDateUtc"), import_date, "sonarr:history.import" - elif ep.get("airDateUtc"): - return ep.get("airDateUtc"), ep.get("airDateUtc"), "sonarr:episode.airDateUtc" + _log("INFO", f"Found Sonarr import history for S{season_num:02d}E{episode_num:02d}: {import_date}") + return aired, import_date, "sonarr:history.import" + break except Exception as e: _log("DEBUG", f"Sonarr API error for episode S{season_num:02d}E{episode_num:02d}: {e}") - # Fallback to current time + # Step 3: Try Sonarr metadata for air date + if not aired and series_metadata and "episodes" in series_metadata: + for episode in series_metadata["episodes"]: + if episode.get("seasonNumber") == season_num and episode.get("episodeNumber") == episode_num: + aired = episode.get("airDateUtc") + break + + # Step 4: Only if we have an air date but no import history, use air date as fallback + if aired: + _log("WARNING", f"No import history found for S{season_num:02d}E{episode_num:02d}, using air date as fallback") + return aired, aired, "sonarr:episode.airDateUtc" + + # Step 5: Last resort - current time (shouldn't happen in normal operation) current_time = datetime.now(timezone.utc).isoformat(timespec="seconds") + _log("WARNING", f"No data found for S{season_num:02d}E{episode_num:02d}, using current time") return None, current_time, "fallback:current_time" def process_webhook_episodes(self, series_path: Path, webhook_episodes: List[Dict[str, Any]]) -> None: @@ -701,8 +713,8 @@ class TVProcessor: _log("WARNING", f"No video files found for S{season_num:02d}E{episode_num:02d}") continue - # Get episode date information - aired, dateadded, source = self._get_single_episode_date(imdb_id, season_num, episode_num, series_metadata) + # Get episode date information - webhook processing prioritizes existing DB entries + aired, dateadded, source = self._get_webhook_episode_date(imdb_id, season_num, episode_num, series_metadata) enhanced_metadata = self._get_episode_metadata(series_metadata, season_num, episode_num) if series_metadata else None # Create NFO @@ -739,6 +751,50 @@ class TVProcessor: _log("INFO", f"Completed targeted processing: {episodes_processed}/{len(webhook_episodes)} episodes processed") + def _get_webhook_episode_date(self, imdb_id: str, season_num: int, episode_num: int, series_metadata: Optional[Dict[str, Any]] = None) -> Tuple[Optional[str], Optional[str], str]: + """ + Get episode date for webhook processing with correct priority: + 1. Check existing NFOGuard database entry (preserve previous import dates) + 2. If not found, use current time (webhook = new download) + 3. Get aired date from Sonarr/TMDB for reference + """ + # Step 1: Check if we already have this episode in our database + existing = self.db.get_episode_date(imdb_id, season_num, episode_num) + if existing and existing.get("dateadded"): + _log("INFO", f"Using existing database entry for S{season_num:02d}E{episode_num:02d}: {existing['dateadded']}") + return existing.get("aired"), existing["dateadded"], existing.get("source", "database:existing") + + # Step 2: This is a new download (webhook triggered) - use current time + current_time = datetime.now(timezone.utc).isoformat(timespec="seconds") + _log("INFO", f"New episode download detected via webhook - using current time: {current_time}") + + # Step 3: Try to get air date for reference + aired = None + + # Try Sonarr metadata first + if series_metadata and "episodes" in series_metadata: + for episode in series_metadata["episodes"]: + if episode.get("seasonNumber") == season_num and episode.get("episodeNumber") == episode_num: + aired = episode.get("airDateUtc") + if aired: + break + + # Fallback to Sonarr API if no metadata + if not aired and self.sonarr.enabled: + try: + series = self.sonarr.series_by_imdb(imdb_id) + if series: + episodes = self.sonarr.episodes_for_series(series["id"]) + for ep in episodes: + if ep.get("seasonNumber") == season_num and ep.get("episodeNumber") == episode_num: + aired = ep.get("airDateUtc") + break + except Exception as e: + _log("DEBUG", f"Error getting air date from Sonarr: {e}") + + # Return: aired date for reference, current time as import date + return aired, current_time, "webhook:new_download" + class MovieProcessor: """Handles movie processing"""