From 134fb0c5c3b4bbd0595840a0198e26cf894623f7 Mon Sep 17 00:00:00 2001 From: SBCrumb Date: Mon, 8 Sep 2025 13:34:48 -0400 Subject: [PATCH] feat: Track grab dates as fallback when no imports found --- CHANGELOG.md | 5 ++ VERSION | 2 +- clients/radarr_client.py | 129 +++++++++++++++++++++++++++++++-------- 3 files changed, 111 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68acca5..729f2e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +## [0.3.7] - 2025-09-08 +### Changed +- Improved import date detection by tracking grab dates as fallback +- Added warning when falling back to grab date + ## [0.3.6] - 2025-09-08 ### Changed - Improved import detection filtering diff --git a/VERSION b/VERSION index 449d7e7..0f82685 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.3.6 +0.3.7 diff --git a/clients/radarr_client.py b/clients/radarr_client.py index 7c82b7a..c7f8467 100644 --- a/clients/radarr_client.py +++ b/clients/radarr_client.py @@ -275,9 +275,14 @@ class RadarrClient: pass # For import/download events, handle specially + # Grab date of first download/grab event as fallback + if event_type == "grabbed" and not earliest_grab_date: + earliest_grab_date = datetime.fromisoformat(event["date"].replace("Z", "+00:00")).astimezone(timezone.utc).isoformat(timespec="seconds") + _log("DEBUG", f"Found first grab event at {earliest_grab_date}") + if event_type not in ["moviefileimported", "downloadFolderImported"]: continue - + imported_path = None # Try different sources for the path if event_type == "moviefileimported": @@ -431,28 +436,104 @@ class RadarrClient: return None, "radarr:no_date_found" + def _get_earliest_import_date(self, movie_id: int, movie_info: Dict) -> Optional[str]: + """Get the earliest import date from Radarr history.""" + _log("INFO", f"Finding earliest import for movie_id {movie_id}") + + # Get full movie history + earliest_real_import = None + earliest_grab_date = None + page = 1 + page_size = 50 + total_events = 0 -if __name__ == "__main__": - # Test the client - import os - - base_url = os.environ.get("RADARR_URL", "") - api_key = os.environ.get("RADARR_API_KEY", "") - - if base_url and api_key: - client = RadarrClient(base_url, api_key) - - # Test with a known movie - test_imdb = "tt1596343" # Example - movie = client.movie_by_imdb(test_imdb) - - if movie: - movie_id = movie.get("id") - print(f"Found movie: {movie.get('title')} (ID: {movie_id})") + while True: + # Get page of history + history_data = self._get_movie_history_page(movie_id, page, page_size) - import_date, source = client.get_movie_import_date(movie_id) - print(f"Import date: {import_date} ({source})") - else: - print(f"Movie not found: {test_imdb}") - else: - print("Please set RADARR_URL and RADARR_API_KEY environment variables for testing") \ No newline at end of file + # Process events on this page + for event in history_data: + event_type = event.get("eventType", "").lower() + + # Track earliest grab date as fallback + if event_type == "grabbed" and not earliest_grab_date: + earliest_grab_date = datetime.fromisoformat(event["date"].replace("Z", "+00:00")).astimezone(timezone.utc).isoformat(timespec="seconds") + _log("DEBUG", f"Found first grab event at {earliest_grab_date}") + + # Only process import events + if event_type not in ["moviefileimported", "downloadFolderImported"]: + continue + + # Try different sources for the path + imported_path = None + if event_type == "moviefileimported": + imported_path = (event.get("data", {}).get("importedPath", "") or + event.get("data", {}).get("path", "") or + event.get("importedPath", "") or + event.get("sourcePath", "")).lower() + elif event_type == "downloadFolderImported": + imported_path = (event.get("data", {}).get("path", "") or + event.get("sourcePath", "") or + event.get("downloadPath", "")).lower() + + if not imported_path: + continue + + movie_imdb = (movie_info.get("imdbId", "") or "").lower() + movie_title = (movie_info.get("title", "") or "").lower() + movie_year = str(movie_info.get("year", "")) + + # First try IMDb ID match + if movie_imdb and ( + f"[imdb-{movie_imdb}]" in imported_path or + f"[{movie_imdb}]" in imported_path or + movie_imdb in imported_path + ): + _log("INFO", f"Found potential IMDb match in {event_type} event: {imported_path}") + date_iso = datetime.fromisoformat(event["date"].replace("Z", "+00:00")).astimezone(timezone.utc).isoformat(timespec="seconds") + _log("INFO", f"✅ FOUND IMPORT at {date_iso}") + earliest_real_import = date_iso + break + + # Then try title/year match with fuzzy path cleaning + if movie_title and movie_year: + # Clean strings for comparison by replacing common separators + clean_title = movie_title.replace(" ", ".").replace(":", ".").replace("-", ".").replace("_", ".").lower() + clean_path = imported_path.replace(" ", ".").replace("-", ".").replace("_", ".").replace("[", "").replace("]", "").lower() + + # Remove common words for better matching + for word in ["the", "a", "an"]: + clean_title = clean_title.replace(f".{word}.", ".").replace(f"{word}.", "").replace(f".{word}", "") + clean_path = clean_path.replace(f".{word}.", ".").replace(f"{word}.", "").replace(f".{word}", "") + + # Look for both title and year in the path + if clean_title in clean_path and movie_year in clean_path: + date_iso = datetime.fromisoformat(event["date"].replace("Z", "+00:00")).astimezone(timezone.utc).isoformat(timespec="seconds") + _log("INFO", f"Found potential title/year match in {event_type} event: {clean_title} ({movie_year})") + _log("INFO", f"✅ FOUND IMPORT at {date_iso}") + earliest_real_import = date_iso + break + + # Break if no more pages + if not history_data: + break + + # Break if we found an import + if earliest_real_import: + break + + total_events += len(history_data) + page += 1 + + _log("INFO", f"Processed {total_events} events across {page-1} pages") + + # Return earliest real import if found + if earliest_real_import: + return earliest_real_import + + # Fall back to earliest grab date if available + if earliest_grab_date: + _log("WARNING", f"⚠️ No real imports found, using grab date: {earliest_grab_date}") + return earliest_grab_date + + return None \ No newline at end of file