This commit is contained in:
@@ -19,8 +19,8 @@ from core.logging import _log, convert_utc_to_local
|
||||
|
||||
class TVSeriesProcessor:
|
||||
"""Clean TV series processor with video filename matching"""
|
||||
|
||||
def __init__(self, db: NFOGuardDatabase, nfo_manager: NFOManager,
|
||||
|
||||
def __init__(self, db: NFOGuardDatabase, nfo_manager: NFOManager,
|
||||
path_mapper: PathMapper, sonarr_client: SonarrClient):
|
||||
self.db = db
|
||||
self.nfo_manager = nfo_manager # Keep for series/season NFOs
|
||||
@@ -28,6 +28,19 @@ class TVSeriesProcessor:
|
||||
self.path_mapper = path_mapper
|
||||
self.sonarr = sonarr_client
|
||||
self.external_manager = ExternalClientManager()
|
||||
|
||||
# Initialize Sonarr database client for high-performance queries
|
||||
self.sonarr_db = None
|
||||
try:
|
||||
from clients.sonarr_db_client import SonarrDbClient
|
||||
self.sonarr_db = SonarrDbClient.from_env()
|
||||
if self.sonarr_db:
|
||||
_log("INFO", "✅ SONARR DB MODE: Direct database access enabled")
|
||||
else:
|
||||
_log("INFO", "⚠️ SONARR API MODE: Using API (configure SONARR_DB_TYPE for better performance)")
|
||||
except Exception as e:
|
||||
_log("WARNING", f"Sonarr DB client initialization failed, using API: {e}")
|
||||
self.sonarr_db = None
|
||||
|
||||
def process_series_manual_scan(self, series_path: Path) -> bool:
|
||||
"""Process a TV series during manual scan"""
|
||||
@@ -219,15 +232,66 @@ class TVSeriesProcessor:
|
||||
return False
|
||||
|
||||
def _get_episode_dates_from_sonarr(self, imdb_id: str, season_num: int, episode_num: int) -> Tuple[Optional[str], Optional[str], str]:
|
||||
"""Get episode dates from Sonarr API with proper fallback"""
|
||||
"""Get episode dates from Sonarr (DB first, then API fallback)"""
|
||||
aired = None
|
||||
dateadded = None
|
||||
source = "no_data_found"
|
||||
|
||||
|
||||
# TIER 1: Try Sonarr database (high performance)
|
||||
if self.sonarr_db:
|
||||
try:
|
||||
# Find series by IMDb
|
||||
series = self.sonarr_db.get_series_by_imdb(imdb_id)
|
||||
if series:
|
||||
series_id = series['id']
|
||||
|
||||
# Get all episodes for series
|
||||
episodes = self.sonarr_db.get_all_episodes_for_series(series_id)
|
||||
|
||||
# Find target episode
|
||||
target_episode = None
|
||||
for ep in episodes:
|
||||
if ep['season'] == season_num and ep['episode'] == episode_num:
|
||||
target_episode = ep
|
||||
break
|
||||
|
||||
if target_episode:
|
||||
# Get air date
|
||||
aired = target_episode.get('air_date')
|
||||
|
||||
# Try to get import date from history
|
||||
episode_id = target_episode['id']
|
||||
import_date, import_source = self.sonarr_db.get_episode_import_date(episode_id)
|
||||
|
||||
if import_date:
|
||||
dateadded = import_date
|
||||
source = import_source
|
||||
_log("INFO", f"✅ DB: Found import date for S{season_num:02d}E{episode_num:02d}: {dateadded}")
|
||||
return aired, dateadded, source
|
||||
|
||||
# Fallback to episode file date
|
||||
file_date = self.sonarr_db.get_episode_file_date(series_id, season_num, episode_num)
|
||||
if file_date:
|
||||
dateadded = file_date
|
||||
source = "sonarr:db.file.dateAdded"
|
||||
_log("INFO", f"✅ DB: Using file date for S{season_num:02d}E{episode_num:02d}: {dateadded}")
|
||||
return aired, dateadded, source
|
||||
|
||||
# Use air date as fallback
|
||||
if aired:
|
||||
dateadded = convert_utc_to_local(aired)
|
||||
source = "sonarr:db.airDate"
|
||||
_log("WARNING", f"⚠️ DB: No import date, using air date for S{season_num:02d}E{episode_num:02d}: {dateadded}")
|
||||
return aired, dateadded, source
|
||||
|
||||
except Exception as e:
|
||||
_log("WARNING", f"Sonarr DB query failed for S{season_num:02d}E{episode_num:02d}, falling back to API: {e}")
|
||||
|
||||
# TIER 2: Fall back to Sonarr API
|
||||
if not self.sonarr.enabled:
|
||||
_log("WARNING", "Sonarr not enabled, cannot get episode dates")
|
||||
return aired, dateadded, source
|
||||
|
||||
|
||||
try:
|
||||
# Find series in Sonarr using lookup endpoint first
|
||||
series = self.sonarr.series_by_imdb(imdb_id)
|
||||
@@ -239,25 +303,25 @@ class TVSeriesProcessor:
|
||||
if not series:
|
||||
_log("WARNING", f"Series not found via direct search either for IMDb: {imdb_id}")
|
||||
# Fall through to external API fallback
|
||||
|
||||
|
||||
if series:
|
||||
# Get episodes for series
|
||||
episodes = self.sonarr.episodes_for_series(series["id"])
|
||||
target_episode = None
|
||||
|
||||
|
||||
for episode in episodes:
|
||||
if (episode.get("seasonNumber") == season_num and
|
||||
if (episode.get("seasonNumber") == season_num and
|
||||
episode.get("episodeNumber") == episode_num):
|
||||
target_episode = episode
|
||||
break
|
||||
|
||||
|
||||
if not target_episode:
|
||||
_log("WARNING", f"Episode S{season_num:02d}E{episode_num:02d} not found in Sonarr")
|
||||
# Don't return here - fall through to external API fallback
|
||||
else:
|
||||
# Get airdate
|
||||
aired = target_episode.get("airDateUtc")
|
||||
|
||||
|
||||
# Try to get import history
|
||||
episode_id = target_episode.get("id")
|
||||
if episode_id:
|
||||
@@ -266,17 +330,17 @@ class TVSeriesProcessor:
|
||||
# Sonarr import dates are already in local timezone despite 'Z' suffix
|
||||
# Remove 'Z' and use as-is to avoid double timezone conversion
|
||||
dateadded = import_date.replace('Z', '') if 'Z' in import_date else import_date
|
||||
source = "sonarr:history.import"
|
||||
_log("INFO", f"Found import date for S{season_num:02d}E{episode_num:02d}: {dateadded} (no timezone conversion)")
|
||||
source = "sonarr:api.history.import"
|
||||
_log("INFO", f"✅ API: Found import date for S{season_num:02d}E{episode_num:02d}: {dateadded}")
|
||||
return aired, dateadded, source
|
||||
|
||||
|
||||
# Fallback to airdate if no import history
|
||||
if aired:
|
||||
dateadded = convert_utc_to_local(aired)
|
||||
source = "sonarr:episode.airDateUtc"
|
||||
_log("WARNING", f"No import history for S{season_num:02d}E{episode_num:02d}, using airdate: {dateadded}")
|
||||
source = "sonarr:api.episode.airDateUtc"
|
||||
_log("WARNING", f"⚠️ API: No import history for S{season_num:02d}E{episode_num:02d}, using airdate: {dateadded}")
|
||||
return aired, dateadded, source
|
||||
|
||||
|
||||
except Exception as e:
|
||||
_log("ERROR", f"Sonarr API error for S{season_num:02d}E{episode_num:02d}: {e}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user