This commit is contained in:
2025-09-08 08:57:29 -04:00
parent c3d1f50cfb
commit d8f304c352
+132 -24
View File
@@ -348,23 +348,28 @@ class RadarrClient:
imdb_id = imdb_id if imdb_id.startswith("tt") else f"tt{imdb_id}"
_log("DEBUG", f"Radarr API: Looking up movie by IMDb ID: {imdb_id}")
# Radarr's IMDb filtering is unreliable, so fetch all movies and filter client-side
res = self._get("/api/v3/movie")
if isinstance(res, list):
# Filter results to find exact IMDb ID match
# Try direct movie search with IMDb filter (even if unreliable)
res = self._get("/api/v3/movie", {"imdbId": imdb_id})
if isinstance(res, list) and len(res) > 0:
# CRITICAL: Validate that returned movie actually matches requested IMDb ID
for movie in res:
if movie.get("imdbId") == imdb_id:
movie_imdb = movie.get("imdbId", "").lower()
if movie_imdb == imdb_id.lower():
_log("DEBUG", f"Radarr API: Found exact match: {movie.get('title')} (ID: {movie.get('id')})")
return movie
_log("WARNING", f"Radarr API: Searched {len(res)} movies but none match IMDb {imdb_id}")
# Fallback: Try lookup endpoint
# Log the mismatch for debugging
returned_ids = [m.get("imdbId", "None") for m in res[:3]] # Show first 3
_log("ERROR", f"Radarr API returned WRONG movies for {imdb_id}! Got: {returned_ids}")
_log("DEBUG", f"Will reject mismatched results and try lookup endpoint")
# Fallback: Try lookup endpoint which might be more reliable
res = self._get("/api/v3/movie/lookup/imdb", {"imdbId": imdb_id})
if isinstance(res, dict) and res.get("id") and res.get("imdbId") == imdb_id:
if isinstance(res, dict) and res.get("imdbId", "").lower() == imdb_id.lower():
_log("DEBUG", f"Radarr API: Found movie via lookup: {res.get('title')} (ID: {res.get('id')})")
return res
_log("DEBUG", f"Radarr API: No movie found for IMDb ID: {imdb_id}")
_log("WARNING", f"Radarr API: No valid movie found for IMDb ID: {imdb_id}")
return None
def movie_files(self, movie_id: int) -> List[Dict[str, Any]]:
@@ -394,6 +399,8 @@ class RadarrClient:
page = 1
page_size = 1000
_log("INFO", f"Starting history lookup for movie_id {movie_id}")
while True:
data = self._get("/api/v3/history", {
"movieId": movie_id, "page": page, "pageSize": page_size,
@@ -419,11 +426,23 @@ class RadarrClient:
_log("WARNING", f"Stopped pagination at page 10 for movie_id {movie_id} - may have missed some history")
break
_log("DEBUG", f"Found {len(all_items)} total history items across {page} pages for movie_id {movie_id}")
items = all_items
_log("INFO", f"Found {len(all_items)} total history items across {page} pages for movie_id {movie_id}")
# Log ALL events first for debugging
_log("INFO", f"=== COMPLETE HISTORY ANALYSIS for movie_id {movie_id} ===")
for i, it in enumerate(all_items):
ev = (it.get("eventType") or it.get("type") or "").lower()
date_str = it.get("date", "NO_DATE")
event_data = it.get('data', {})
source_path = event_data.get('sourcePath', '') or event_data.get('path', '') or event_data.get('sourceTitle', '')
_log("INFO", f"Event #{i+1}: type='{ev}', date='{date_str}', sourcePath='{source_path}'")
_log("DEBUG", f" Full data: {json.dumps(event_data, indent=2) if event_data else 'No data'}")
first_grab = None
for it in items:
earliest_real_import = None
for it in all_items:
ev = (it.get("eventType") or it.get("type") or "").lower()
date_iso = None
if it.get("date"):
@@ -432,8 +451,6 @@ class RadarrClient:
except Exception:
date_iso = None
_log("DEBUG", f"History event: type='{ev}', date={date_iso}, data={it.get('data', {})}")
# Expanded event types for Radarr v4/v5 compatibility
import_events = {
"downloadfolderimported", "moviefileimported", "imported",
@@ -443,27 +460,41 @@ class RadarrClient:
if ev in import_events:
# Check if this is a real import (from downloads) vs existing file rename
event_data = it.get('data', {})
source_path = event_data.get('sourcePath', '') or event_data.get('path', '')
source_path = event_data.get('sourcePath', '') or event_data.get('path', '') or event_data.get('sourceTitle', '')
_log("INFO", f"Analyzing import event '{ev}' with source: '{source_path}'")
# Real imports typically come from download folders
is_real_import = any(download_indicator in source_path.lower() for download_indicator in [
download_indicators = [
'/downloads/', '/download/', '/completed/', '/nzbs/', '/torrents/',
'sabnzbd', 'nzbget', 'deluge', 'qbittorrent', 'transmission'
])
'sabnzbd', 'nzbget', 'deluge', 'qbittorrent', 'transmission',
'/radarr/', 'completed/' # Add more specific patterns
]
is_real_import = any(indicator in source_path.lower() for indicator in download_indicators)
_log("INFO", f"Import analysis: is_real_import={is_real_import}, date={date_iso}")
if is_real_import and date_iso:
_log("INFO", f"Found REAL import event '{ev}' from downloads at {date_iso} (source: {source_path})")
return date_iso
_log("INFO", f"✅ FOUND REAL IMPORT EVENT '{ev}' from downloads at {date_iso} (source: {source_path})")
if earliest_real_import is None:
earliest_real_import = date_iso
elif date_iso:
_log("DEBUG", f"Skipping non-import event '{ev}' (rename/existing file) from {source_path}")
if ev == "grabbed" and date_iso and first_grab is None:
_log("INFO", f"⚠️ Skipping non-download import '{ev}' from {source_path}")
elif ev == "grabbed" and date_iso and first_grab is None:
first_grab = date_iso
_log("INFO", f"Found grab event at {date_iso}")
if earliest_real_import:
_log("INFO", f"✅ USING EARLIEST REAL IMPORT DATE: {earliest_real_import}")
return earliest_real_import
if first_grab:
_log("INFO", f"Using grab date {first_grab} as fallback for movie_id {movie_id}")
_log("INFO", f"⚠️ Using grab date {first_grab} as fallback for movie_id {movie_id}")
return first_grab
_log("WARNING", f"No real import/grab events found for movie_id {movie_id} (only renames/existing files)")
_log("ERROR", f"No real import/grab events found for movie_id {movie_id}")
return None
# ---------------------------
@@ -1650,6 +1681,83 @@ async def get_stats():
async def get_batch_status():
return batcher.get_status()
@app.get("/debug/movie/{imdb_id}")
async def debug_movie_import_date(imdb_id: str):
"""Debug endpoint to analyze movie import date detection"""
try:
if not imdb_id.startswith("tt"):
imdb_id = f"tt{imdb_id}"
_log("INFO", f"=== DEBUG MOVIE IMPORT DATE: {imdb_id} ===")
if not (config.radarr_url and config.radarr_api_key):
return {
"error": "Radarr not configured",
"imdb_id": imdb_id,
"radarr_configured": False
}
# Create Radarr client
rc = RadarrClient(config.radarr_url, config.radarr_api_key, config.radarr_timeout, config.radarr_retries)
# Look up movie
movie_obj = rc.movie_by_imdb(imdb_id)
if not movie_obj:
return {
"error": f"Movie not found in Radarr for IMDb ID {imdb_id}",
"imdb_id": imdb_id,
"radarr_configured": True,
"movie_found": False
}
movie_id = movie_obj.get("id")
movie_title = movie_obj.get("title")
_log("INFO", f"Found movie: {movie_title} (Radarr ID: {movie_id})")
# Get import history with detailed logging
import_date = rc.earliest_import_event(movie_id)
# Get movie files for additional context
movie_files = rc.movie_files(movie_id)
file_dates = []
for f in movie_files:
file_dates.append({
"id": f.get("id"),
"relativePath": f.get("relativePath"),
"dateAdded": f.get("dateAdded"),
"quality": f.get("quality", {}).get("quality", {}).get("name", "Unknown")
})
return {
"imdb_id": imdb_id,
"radarr_configured": True,
"movie_found": True,
"movie_title": movie_title,
"movie_id": movie_id,
"detected_import_date": import_date,
"movie_files": file_dates,
"analysis": {
"import_date_found": import_date is not None,
"expected_july_7_2025": "2025-07-07" in (import_date or ""),
"method_used": "radarr:history.import" if import_date else "none"
},
"debug_info": {
"radarr_url": config.radarr_url,
"movie_digital_release": movie_obj.get("digitalRelease"),
"movie_in_cinemas": movie_obj.get("inCinemas"),
"movie_physical_release": movie_obj.get("physicalRelease")
}
}
except Exception as e:
_log("ERROR", f"Debug endpoint error for {imdb_id}: {e}")
return {
"error": str(e),
"imdb_id": imdb_id,
"success": False
}
# ---------------------------
# Manual scans
# ---------------------------