updates
This commit is contained in:
+132
-24
@@ -348,23 +348,28 @@ class RadarrClient:
|
|||||||
imdb_id = imdb_id if imdb_id.startswith("tt") else f"tt{imdb_id}"
|
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}")
|
_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
|
# Try direct movie search with IMDb filter (even if unreliable)
|
||||||
res = self._get("/api/v3/movie")
|
res = self._get("/api/v3/movie", {"imdbId": imdb_id})
|
||||||
if isinstance(res, list):
|
if isinstance(res, list) and len(res) > 0:
|
||||||
# Filter results to find exact IMDb ID match
|
# CRITICAL: Validate that returned movie actually matches requested IMDb ID
|
||||||
for movie in res:
|
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')})")
|
_log("DEBUG", f"Radarr API: Found exact match: {movie.get('title')} (ID: {movie.get('id')})")
|
||||||
return movie
|
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})
|
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')})")
|
_log("DEBUG", f"Radarr API: Found movie via lookup: {res.get('title')} (ID: {res.get('id')})")
|
||||||
return res
|
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
|
return None
|
||||||
|
|
||||||
def movie_files(self, movie_id: int) -> List[Dict[str, Any]]:
|
def movie_files(self, movie_id: int) -> List[Dict[str, Any]]:
|
||||||
@@ -394,6 +399,8 @@ class RadarrClient:
|
|||||||
page = 1
|
page = 1
|
||||||
page_size = 1000
|
page_size = 1000
|
||||||
|
|
||||||
|
_log("INFO", f"Starting history lookup for movie_id {movie_id}")
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
data = self._get("/api/v3/history", {
|
data = self._get("/api/v3/history", {
|
||||||
"movieId": movie_id, "page": page, "pageSize": page_size,
|
"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")
|
_log("WARNING", f"Stopped pagination at page 10 for movie_id {movie_id} - may have missed some history")
|
||||||
break
|
break
|
||||||
|
|
||||||
_log("DEBUG", f"Found {len(all_items)} total history items across {page} pages for movie_id {movie_id}")
|
_log("INFO", f"Found {len(all_items)} total history items across {page} pages for movie_id {movie_id}")
|
||||||
items = all_items
|
|
||||||
|
# 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
|
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()
|
ev = (it.get("eventType") or it.get("type") or "").lower()
|
||||||
date_iso = None
|
date_iso = None
|
||||||
if it.get("date"):
|
if it.get("date"):
|
||||||
@@ -432,8 +451,6 @@ class RadarrClient:
|
|||||||
except Exception:
|
except Exception:
|
||||||
date_iso = None
|
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
|
# Expanded event types for Radarr v4/v5 compatibility
|
||||||
import_events = {
|
import_events = {
|
||||||
"downloadfolderimported", "moviefileimported", "imported",
|
"downloadfolderimported", "moviefileimported", "imported",
|
||||||
@@ -443,27 +460,41 @@ class RadarrClient:
|
|||||||
if ev in import_events:
|
if ev in import_events:
|
||||||
# Check if this is a real import (from downloads) vs existing file rename
|
# Check if this is a real import (from downloads) vs existing file rename
|
||||||
event_data = it.get('data', {})
|
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
|
# 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/',
|
'/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:
|
if is_real_import and date_iso:
|
||||||
_log("INFO", f"Found REAL import event '{ev}' from downloads at {date_iso} (source: {source_path})")
|
_log("INFO", f"✅ FOUND REAL IMPORT EVENT '{ev}' from downloads at {date_iso} (source: {source_path})")
|
||||||
return date_iso
|
if earliest_real_import is None:
|
||||||
|
earliest_real_import = date_iso
|
||||||
elif date_iso:
|
elif date_iso:
|
||||||
_log("DEBUG", f"Skipping non-import event '{ev}' (rename/existing file) from {source_path}")
|
_log("INFO", f"⚠️ Skipping non-download import '{ev}' from {source_path}")
|
||||||
if ev == "grabbed" and date_iso and first_grab is None:
|
|
||||||
|
elif ev == "grabbed" and date_iso and first_grab is None:
|
||||||
first_grab = date_iso
|
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:
|
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
|
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
|
return None
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
@@ -1650,6 +1681,83 @@ async def get_stats():
|
|||||||
async def get_batch_status():
|
async def get_batch_status():
|
||||||
return batcher.get_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
|
# Manual scans
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user