mirror of
https://github.com/plexguide/Huntarr.io.git
synced 2026-04-20 12:46:53 -04:00
120 lines
4.3 KiB
Python
120 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Missing Episode Processing
|
|
Handles searching for missing episodes in Sonarr
|
|
"""
|
|
|
|
import random
|
|
import time
|
|
from typing import List
|
|
from utils.logger import logger
|
|
from config import HUNT_MISSING_SHOWS, MONITORED_ONLY, RANDOM_SELECTION
|
|
from api import get_series, get_episodes_for_series, refresh_series, episode_search_episodes
|
|
from state import load_processed_ids, save_processed_id, truncate_processed_list, PROCESSED_MISSING_FILE
|
|
|
|
def process_missing_episodes() -> bool:
|
|
"""
|
|
Process shows that have missing episodes, but respect
|
|
unmonitored seasons/episodes. We'll fetch episodes for each show
|
|
and only search for episodes that are BOTH missing and monitored.
|
|
|
|
Returns:
|
|
True if any processing was done, False otherwise
|
|
"""
|
|
logger.info("=== Checking for Missing Episodes ===")
|
|
|
|
# Skip if HUNT_MISSING_SHOWS is set to 0
|
|
if HUNT_MISSING_SHOWS <= 0:
|
|
logger.info("HUNT_MISSING_SHOWS is set to 0, skipping missing content")
|
|
return False
|
|
|
|
shows = get_series()
|
|
if not shows:
|
|
logger.error("ERROR: Unable to retrieve series data from Sonarr.")
|
|
return False
|
|
|
|
# Optionally filter to only monitored shows (if MONITORED_ONLY==true)
|
|
if MONITORED_ONLY:
|
|
logger.info("MONITORED_ONLY=true => only fully monitored shows.")
|
|
shows = [s for s in shows if s.get("monitored") is True]
|
|
else:
|
|
logger.info("MONITORED_ONLY=false => all shows, even if unmonitored.")
|
|
|
|
if not shows:
|
|
logger.info("No shows to process.")
|
|
return False
|
|
|
|
processed_missing_ids = load_processed_ids(PROCESSED_MISSING_FILE)
|
|
shows_processed = 0
|
|
processing_done = False
|
|
|
|
indices = list(range(len(shows)))
|
|
if RANDOM_SELECTION:
|
|
random.shuffle(indices)
|
|
|
|
for idx in indices:
|
|
if shows_processed >= HUNT_MISSING_SHOWS:
|
|
break
|
|
|
|
show = shows[idx]
|
|
series_id = show.get("id")
|
|
if not series_id:
|
|
continue
|
|
|
|
# If we already processed this show ID, skip
|
|
if series_id in processed_missing_ids:
|
|
continue
|
|
|
|
show_title = show.get("title", "Unknown Show")
|
|
|
|
# Fetch the episodes for this show
|
|
episode_list = get_episodes_for_series(series_id)
|
|
if not episode_list:
|
|
logger.warning(f"WARNING: Could not retrieve episodes for series ID={series_id}. Skipping.")
|
|
continue
|
|
|
|
# Find all episodes that are monitored and missing a file
|
|
missing_monitored_eps = [
|
|
e for e in episode_list
|
|
if e.get("monitored") is True
|
|
and e.get("hasFile") is False
|
|
]
|
|
|
|
if not missing_monitored_eps:
|
|
# This show has no missing monitored episodes, skip
|
|
logger.info(f"No missing monitored episodes for '{show_title}' — skipping.")
|
|
continue
|
|
|
|
logger.info(f"Found {len(missing_monitored_eps)} missing monitored episode(s) for '{show_title}'.")
|
|
|
|
# Refresh the series
|
|
logger.info(f" - Refreshing series (ID: {series_id})...")
|
|
refresh_res = refresh_series(series_id)
|
|
if not refresh_res or "id" not in refresh_res:
|
|
logger.warning(f"WARNING: Refresh command failed for {show_title}. Skipping.")
|
|
time.sleep(5)
|
|
continue
|
|
|
|
logger.info(f"Refresh command accepted (ID: {refresh_res['id']}). Waiting 5s...")
|
|
time.sleep(5)
|
|
|
|
# Search specifically for these missing + monitored episodes
|
|
episode_ids = [ep["id"] for ep in missing_monitored_eps]
|
|
logger.info(f" - Searching for {len(episode_ids)} missing episodes in '{show_title}'...")
|
|
search_res = episode_search_episodes(episode_ids)
|
|
if search_res and "id" in search_res:
|
|
logger.info(f"Search command accepted (ID: {search_res['id']}).")
|
|
processing_done = True
|
|
else:
|
|
logger.warning(f"WARNING: EpisodeSearch failed for show '{show_title}' (ID: {series_id}).")
|
|
continue
|
|
|
|
# Mark as processed
|
|
save_processed_id(PROCESSED_MISSING_FILE, series_id)
|
|
shows_processed += 1
|
|
logger.info(f"Processed {shows_processed}/{HUNT_MISSING_SHOWS} missing shows this cycle.")
|
|
|
|
# Truncate processed list if needed
|
|
truncate_processed_list(PROCESSED_MISSING_FILE)
|
|
|
|
return processing_done |