feat: intial commits
This commit is contained in:
+99
-17
@@ -312,8 +312,11 @@ class RadarrClient:
|
||||
"sortKey": "date", "sortDirection": "ascending"
|
||||
})
|
||||
if not data:
|
||||
_log("DEBUG", f"No history data returned for movie_id {movie_id}")
|
||||
return None
|
||||
items = data if isinstance(data, list) else data.get("records") or []
|
||||
_log("DEBUG", f"Found {len(items)} history items for movie_id {movie_id}")
|
||||
|
||||
first_grab = None
|
||||
for it in items:
|
||||
ev = (it.get("eventType") or it.get("type") or "").lower()
|
||||
@@ -323,13 +326,27 @@ class RadarrClient:
|
||||
date_iso = datetime.fromisoformat(it["date"].replace("Z", "+00:00")).astimezone(timezone.utc).isoformat(timespec="seconds")
|
||||
except Exception:
|
||||
date_iso = None
|
||||
if ev in ("downloadfolderimported", "moviefileimported"):
|
||||
|
||||
_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",
|
||||
"downloadimported", "fileimported", "movieimported"
|
||||
}
|
||||
|
||||
if ev in import_events:
|
||||
if date_iso:
|
||||
_log("INFO", f"Found import event '{ev}' at {date_iso} for movie_id {movie_id}")
|
||||
return date_iso
|
||||
if ev == "grabbed" and date_iso and first_grab is None:
|
||||
first_grab = date_iso
|
||||
|
||||
if first_grab:
|
||||
_log("INFO", f"Using grab date {first_grab} as fallback for movie_id {movie_id}")
|
||||
return first_grab
|
||||
|
||||
_log("WARNING", f"No usable import/grab events found for movie_id {movie_id}")
|
||||
return None
|
||||
|
||||
# ---------------------------
|
||||
@@ -523,7 +540,11 @@ def upsert_movie_nfo(
|
||||
_ensure_child_text(root, "year", ymd.split("-")[0], overwrite=False)
|
||||
|
||||
if dateadded:
|
||||
_ensure_child_text(root, "dateadded", dateadded, overwrite=True)
|
||||
if dateadded == "MANUAL_REVIEW_NEEDED":
|
||||
_ensure_child_text(root, "dateadded", "MANUAL_REVIEW_NEEDED", overwrite=True)
|
||||
_log("WARNING", f"Set MANUAL_REVIEW_NEEDED marker in NFO: {movie_dir}/movie.nfo")
|
||||
else:
|
||||
_ensure_child_text(root, "dateadded", dateadded, overwrite=True)
|
||||
|
||||
if lock_metadata:
|
||||
_ensure_child_text(root, "lockdata", "true", overwrite=True)
|
||||
@@ -552,9 +573,16 @@ def _parse_date_to_iso(d: str) -> Optional[str]:
|
||||
try:
|
||||
if re.fullmatch(r"\d{4}-\d{2}-\d{2}", d):
|
||||
dt = datetime.fromisoformat(d).replace(tzinfo=timezone.utc)
|
||||
return dt.isoformat(timespec="seconds")
|
||||
dt = datetime.fromisoformat(d.replace("Z", "+00:00"))
|
||||
return dt.astimezone(timezone.utc).isoformat(timespec="seconds")
|
||||
else:
|
||||
dt = datetime.fromisoformat(d.replace("Z", "+00:00")).astimezone(timezone.utc)
|
||||
|
||||
# Reject dates that are too recent (prevent bogus timestamps)
|
||||
now = datetime.now(timezone.utc)
|
||||
if (now - dt).days < 1:
|
||||
_log("WARNING", f"Rejecting recent timestamp (less than 1 day old): {d} -> {dt.isoformat()}")
|
||||
return None
|
||||
|
||||
return dt.isoformat(timespec="seconds")
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
@@ -587,21 +615,32 @@ def _strategy_movie_date_from_movie_obj(movie_obj: Dict[str, Any], which: str) -
|
||||
|
||||
def _collect_digital_candidates(imdb_id: str, movie_obj: Optional[Dict[str, Any]]) -> List[Tuple[str, str]]:
|
||||
cands: List[Tuple[str, str]] = []
|
||||
_log("DEBUG", f"Collecting digital dates for {imdb_id}")
|
||||
|
||||
if movie_obj:
|
||||
iso = _strategy_movie_date_from_movie_obj(movie_obj, "digital")
|
||||
if iso:
|
||||
cands.append((iso, "radarr:digitalRelease"))
|
||||
_log("DEBUG", f"Found Radarr digital date: {iso}")
|
||||
|
||||
iso = tmdb_digital_date_from_imdb(imdb_id)
|
||||
if iso:
|
||||
cands.append((iso, "tmdb:digital"))
|
||||
_log("DEBUG", f"Found TMDB digital date: {iso}")
|
||||
|
||||
tmdb_id = _tmdb_id_from_imdb(imdb_id)
|
||||
if tmdb_id:
|
||||
iso = jellyseerr_digital_date_from_tmdb(tmdb_id)
|
||||
if iso:
|
||||
cands.append((iso, "jellyseerr:digital"))
|
||||
_log("DEBUG", f"Found Jellyseerr digital date: {iso}")
|
||||
|
||||
iso = omdb_dvd_date(imdb_id)
|
||||
if iso:
|
||||
cands.append((iso, "omdb:dvd"))
|
||||
_log("DEBUG", f"Found OMDb DVD date: {iso}")
|
||||
|
||||
_log("INFO", f"Found {len(cands)} digital date candidates: {[f'{src}={date}' for date, src in cands]}")
|
||||
return cands
|
||||
|
||||
def _pick_earliest(cands: List[Tuple[str, str]]) -> Optional[Tuple[str, str]]:
|
||||
@@ -654,15 +693,24 @@ def _decide_movie_date(imdb_id: str, movie_dir: Path, poll_external: bool) -> Tu
|
||||
|
||||
def from_import_history() -> Tuple[Optional[str], str]:
|
||||
ensure_movie()
|
||||
if poll_external and movie_id:
|
||||
iso = _radarr_earliest_import_history_iso(movie_id)
|
||||
if iso:
|
||||
return iso, "radarr:history.import"
|
||||
if poll_external and movie_id:
|
||||
iso2 = _radarr_earliest_file_dateadded_iso(movie_id)
|
||||
if iso2:
|
||||
return iso2, "radarr:moviefile.dateAdded"
|
||||
return None, "radarr:history"
|
||||
if not (poll_external and movie_id):
|
||||
_log("DEBUG", f"Skipping import history: poll_external={poll_external}, movie_id={movie_id}")
|
||||
return None, "radarr:history.skipped"
|
||||
|
||||
# Try import history events first (most reliable)
|
||||
iso = _radarr_earliest_import_history_iso(movie_id)
|
||||
if iso:
|
||||
_log("INFO", f"Using Radarr import history date: {iso}")
|
||||
return iso, "radarr:history.import"
|
||||
|
||||
# Fallback to moviefile dateAdded
|
||||
iso2 = _radarr_earliest_file_dateadded_iso(movie_id)
|
||||
if iso2:
|
||||
_log("INFO", f"Using Radarr moviefile dateAdded: {iso2}")
|
||||
return iso2, "radarr:moviefile.dateAdded"
|
||||
|
||||
_log("WARNING", f"No import dates found for movie_id {movie_id}")
|
||||
return None, "radarr:history.none"
|
||||
|
||||
def from_radarr_field(which: str) -> Tuple[Optional[str], str]:
|
||||
ensure_movie()
|
||||
@@ -715,33 +763,67 @@ def _decide_movie_date(imdb_id: str, movie_dir: Path, poll_external: bool) -> Tu
|
||||
return digi_iso, "radarr:digitalRelease"
|
||||
|
||||
# Priority flows
|
||||
_log("INFO", f"Date selection for {imdb_id}: priority={config.movie_priority}, poll_external={poll_external}")
|
||||
|
||||
if config.movie_priority == "import_then_digital":
|
||||
_log("DEBUG", "Trying import history first (import_then_digital mode)")
|
||||
imp_iso, imp_src = from_import_history()
|
||||
if imp_iso:
|
||||
_log("INFO", f"Selected import date: {imp_iso} ({imp_src})")
|
||||
return imp_iso, imp_src, released_iso
|
||||
|
||||
_log("DEBUG", "No import date found, trying digital release dates")
|
||||
digi_iso, digi_src = from_external_digital_bundle()
|
||||
digi_iso, digi_src = maybe_sanitize_digital(digi_iso)
|
||||
if digi_iso:
|
||||
_log("INFO", f"Selected digital date: {digi_iso} ({digi_src})")
|
||||
return digi_iso, digi_src, released_iso
|
||||
|
||||
_log("DEBUG", "No digital date found, trying cinema release")
|
||||
cine_iso, cine_src = from_radarr_field("cinema")
|
||||
if cine_iso:
|
||||
_log("INFO", f"Selected cinema date: {cine_iso} ({cine_src})")
|
||||
return cine_iso, cine_src, released_iso or cine_iso
|
||||
|
||||
_log("DEBUG", "No external dates found, falling back to file mtime")
|
||||
mtime_iso, mtime_src = from_file_mtime()
|
||||
return mtime_iso, mtime_src, released_iso
|
||||
if mtime_iso:
|
||||
_log("WARNING", f"Using file mtime as last resort: {mtime_iso} ({mtime_src})")
|
||||
return mtime_iso, mtime_src, released_iso
|
||||
|
||||
# No valid date found - create manual review marker
|
||||
_log("ERROR", f"No valid dateadded found for {imdb_id} - marking for MANUAL_REVIEW_NEEDED")
|
||||
return "MANUAL_REVIEW_NEEDED", "manual_review_required", released_iso
|
||||
|
||||
# digital_then_import
|
||||
_log("DEBUG", "Trying digital release dates first (digital_then_import mode)")
|
||||
digi_iso, digi_src = from_external_digital_bundle()
|
||||
digi_iso, digi_src = maybe_sanitize_digital(digi_iso)
|
||||
if digi_iso:
|
||||
_log("INFO", f"Selected digital date: {digi_iso} ({digi_src})")
|
||||
return digi_iso, digi_src, released_iso
|
||||
|
||||
_log("DEBUG", "No digital date found, trying import history")
|
||||
imp_iso, imp_src = from_import_history()
|
||||
if imp_iso:
|
||||
_log("INFO", f"Selected import date: {imp_iso} ({imp_src})")
|
||||
return imp_iso, imp_src, released_iso
|
||||
|
||||
_log("DEBUG", "No import date found, trying cinema release")
|
||||
cine_iso, cine_src = from_radarr_field("cinema")
|
||||
if cine_iso:
|
||||
_log("INFO", f"Selected cinema date: {cine_iso} ({cine_src})")
|
||||
return cine_iso, cine_src, released_iso or cine_iso
|
||||
|
||||
_log("DEBUG", "No external dates found, falling back to file mtime")
|
||||
mtime_iso, mtime_src = from_file_mtime()
|
||||
return mtime_iso, mtime_src, released_iso
|
||||
if mtime_iso:
|
||||
_log("WARNING", f"Using file mtime as last resort: {mtime_iso} ({mtime_src})")
|
||||
return mtime_iso, mtime_src, released_iso
|
||||
|
||||
# No valid date found - create manual review marker
|
||||
_log("ERROR", f"No valid dateadded found for {imdb_id} - marking for MANUAL_REVIEW_NEEDED")
|
||||
return "MANUAL_REVIEW_NEEDED", "manual_review_required", released_iso
|
||||
|
||||
# ---------------------------
|
||||
# Movie apply
|
||||
@@ -854,7 +936,7 @@ def apply_movie(movie_dir: Path, conn: sqlite3.Connection):
|
||||
brand=config.manager_brand,
|
||||
)
|
||||
|
||||
if config.fix_dir_mtimes and dateadded_iso:
|
||||
if config.fix_dir_mtimes and dateadded_iso and dateadded_iso != "MANUAL_REVIEW_NEEDED":
|
||||
set_movie_file_mtime(movie_dir, dateadded_iso)
|
||||
|
||||
conn.commit()
|
||||
|
||||
Reference in New Issue
Block a user