sonarrissues #40
+30
-45
@@ -152,54 +152,39 @@ async def sonarr_webhook(request: Request, background_tasks: BackgroundTasks, de
|
||||
if recent_renames:
|
||||
# Take the most recent rename event
|
||||
latest_rename = recent_renames[0]
|
||||
print(f"DEBUG: Latest rename event keys: {list(latest_rename.keys())}")
|
||||
print(f"DEBUG: Latest rename event full structure: {latest_rename}")
|
||||
print(f"DEBUG: Processing latest rename event")
|
||||
|
||||
# Try different possible episode data locations
|
||||
episode_info = latest_rename.get("episode", {})
|
||||
episode_file_info = latest_rename.get("episodeFile", {})
|
||||
data_info = latest_rename.get("data", {})
|
||||
# Extract episodeId directly from the rename event
|
||||
episode_id = latest_rename.get("episodeId")
|
||||
print(f"DEBUG: Found episodeId {episode_id} in rename event")
|
||||
|
||||
print(f"DEBUG: Episode info: {episode_info}")
|
||||
print(f"DEBUG: EpisodeFile info: {episode_file_info}")
|
||||
print(f"DEBUG: Data info: {data_info}")
|
||||
|
||||
# Try to extract episode info from any available source
|
||||
season_num = None
|
||||
episode_num = None
|
||||
episode_id = None
|
||||
episode_title = None
|
||||
|
||||
# Check episode object first
|
||||
if episode_info:
|
||||
season_num = episode_info.get("seasonNumber")
|
||||
episode_num = episode_info.get("episodeNumber")
|
||||
episode_id = episode_info.get("id")
|
||||
episode_title = episode_info.get("title")
|
||||
|
||||
# Check episodeFile object
|
||||
if not season_num and episode_file_info:
|
||||
season_num = episode_file_info.get("seasonNumber")
|
||||
episode_num = episode_file_info.get("episodeNumber")
|
||||
episode_id = episode_file_info.get("episodeId") or episode_file_info.get("id")
|
||||
|
||||
# Check data object
|
||||
if not season_num and data_info:
|
||||
season_num = data_info.get("seasonNumber")
|
||||
episode_num = data_info.get("episodeNumber")
|
||||
|
||||
print(f"DEBUG: Extracted - Season: {season_num}, Episode: {episode_num}, ID: {episode_id}")
|
||||
|
||||
if season_num and episode_num:
|
||||
episodes_data = [{
|
||||
"seasonNumber": season_num,
|
||||
"episodeNumber": episode_num,
|
||||
"id": episode_id,
|
||||
"title": episode_title
|
||||
}]
|
||||
print(f"INFO: Found recently renamed episode from history: S{season_num:02d}E{episode_num:02d}")
|
||||
if episode_id:
|
||||
# Fetch episode details using the episodeId
|
||||
episode_detail_url = f"{config.sonarr_url}/api/v3/episode/{episode_id}"
|
||||
episode_response = requests.get(episode_detail_url, headers={"X-Api-Key": os.environ.get("SONARR_API_KEY", "")}, timeout=10)
|
||||
|
||||
if episode_response.status_code == 200:
|
||||
episode_detail = episode_response.json()
|
||||
season_num = episode_detail.get("seasonNumber")
|
||||
episode_num = episode_detail.get("episodeNumber")
|
||||
episode_title = episode_detail.get("title")
|
||||
|
||||
print(f"DEBUG: Episode details - Season: {season_num}, Episode: {episode_num}, Title: {episode_title}")
|
||||
|
||||
if season_num is not None and episode_num is not None:
|
||||
episodes_data = [{
|
||||
"seasonNumber": season_num,
|
||||
"episodeNumber": episode_num,
|
||||
"id": episode_id,
|
||||
"title": episode_title
|
||||
}]
|
||||
print(f"INFO: Successfully identified renamed episode: S{season_num:02d}E{episode_num:02d} - {episode_title}")
|
||||
else:
|
||||
print(f"DEBUG: Episode details missing season/episode numbers")
|
||||
else:
|
||||
print(f"DEBUG: Failed to fetch episode details: {episode_response.status_code}")
|
||||
else:
|
||||
print(f"DEBUG: Could not extract episode data from rename event")
|
||||
print(f"DEBUG: No episodeId found in rename event")
|
||||
else:
|
||||
print(f"DEBUG: No recent rename events found in last hour")
|
||||
else:
|
||||
|
||||
+68
-32
@@ -102,47 +102,70 @@ class TVProcessor:
|
||||
|
||||
|
||||
def _gather_episode_dates(self, series_path: Path, imdb_id: str, disk_episodes: Dict[Tuple[int, int], List[Path]]) -> Dict[Tuple[int, int], Tuple[Optional[str], Optional[str], str]]:
|
||||
"""Gather episode air dates and date added information"""
|
||||
"""Gather episode air dates and date added information with database-first optimization"""
|
||||
episode_dates = {}
|
||||
episodes_needing_lookup = []
|
||||
|
||||
# Get data from Sonarr first if available
|
||||
sonarr_episodes = self._get_sonarr_episodes(imdb_id)
|
||||
# OPTIMIZATION: Check database first for existing dates
|
||||
_log("DEBUG", f"Checking database for existing episode dates for {len(disk_episodes)} episodes")
|
||||
db_cache_hits = 0
|
||||
|
||||
# Get data from external sources for missing information
|
||||
for (season, episode) in disk_episodes:
|
||||
aired = None
|
||||
dateadded = None
|
||||
source = "unknown"
|
||||
# Try database first - this is much faster than API calls
|
||||
db_result = self.db.get_episode_date(imdb_id, season, episode)
|
||||
|
||||
# Try Sonarr first
|
||||
if (season, episode) in sonarr_episodes:
|
||||
sonarr_data = sonarr_episodes[(season, episode)]
|
||||
aired = sonarr_data.get('airDate')
|
||||
dateadded = sonarr_data.get('dateAdded')
|
||||
if dateadded:
|
||||
# Use more specific source to indicate this came from Sonarr import history
|
||||
source = "sonarr:history.import"
|
||||
if db_result and db_result.get('dateadded'):
|
||||
# Found in database - use cached data
|
||||
aired = db_result.get('aired')
|
||||
dateadded = db_result.get('dateadded')
|
||||
source = db_result.get('source', 'database_cache')
|
||||
episode_dates[(season, episode)] = (aired, dateadded, source)
|
||||
db_cache_hits += 1
|
||||
_log("DEBUG", f"Database cache hit for S{season:02d}E{episode:02d}: {dateadded}")
|
||||
else:
|
||||
# Not in database or incomplete - needs lookup
|
||||
episodes_needing_lookup.append((season, episode))
|
||||
|
||||
_log("INFO", f"Database cache hits: {db_cache_hits}/{len(disk_episodes)} episodes. Need API lookup: {len(episodes_needing_lookup)}")
|
||||
|
||||
# Only call Sonarr API for episodes not in database
|
||||
if episodes_needing_lookup:
|
||||
_log("DEBUG", f"Querying Sonarr for {len(episodes_needing_lookup)} episodes missing from database")
|
||||
sonarr_episodes = self._get_sonarr_episodes(imdb_id, episodes_needing_lookup)
|
||||
|
||||
# Fallback to external sources if needed
|
||||
if not aired:
|
||||
external_aired = self.external_clients.get_episode_air_date(imdb_id, season, episode)
|
||||
if external_aired:
|
||||
aired = external_aired
|
||||
if not dateadded:
|
||||
source = "external"
|
||||
|
||||
# ONLY use air date as fallback for dateadded if we have no Sonarr import date at all
|
||||
# and if we couldn't get any import information from Sonarr history
|
||||
if not dateadded and aired and source != "sonarr:history.import":
|
||||
dateadded = aired
|
||||
source = f"{source}_fallback" if source != "unknown" else "aired_fallback"
|
||||
|
||||
episode_dates[(season, episode)] = (aired, dateadded, source)
|
||||
# Process episodes that needed lookup
|
||||
for (season, episode) in episodes_needing_lookup:
|
||||
aired = None
|
||||
dateadded = None
|
||||
source = "unknown"
|
||||
|
||||
# Try Sonarr first
|
||||
if (season, episode) in sonarr_episodes:
|
||||
sonarr_data = sonarr_episodes[(season, episode)]
|
||||
aired = sonarr_data.get('airDate')
|
||||
dateadded = sonarr_data.get('dateAdded')
|
||||
if dateadded:
|
||||
source = "sonarr:history.import"
|
||||
|
||||
# Fallback to external sources if needed
|
||||
if not aired:
|
||||
external_aired = self.external_clients.get_episode_air_date(imdb_id, season, episode)
|
||||
if external_aired:
|
||||
aired = external_aired
|
||||
if not dateadded:
|
||||
source = "external"
|
||||
|
||||
# Use air date as fallback for dateadded if no import date found
|
||||
if not dateadded and aired and source != "sonarr:history.import":
|
||||
dateadded = aired
|
||||
source = f"{source}_fallback" if source != "unknown" else "aired_fallback"
|
||||
|
||||
episode_dates[(season, episode)] = (aired, dateadded, source)
|
||||
|
||||
return episode_dates
|
||||
|
||||
def _get_sonarr_episodes(self, imdb_id: str) -> Dict[Tuple[int, int], Dict[str, Any]]:
|
||||
"""Get episode information from Sonarr including import history"""
|
||||
def _get_sonarr_episodes(self, imdb_id: str, episodes_filter: List[Tuple[int, int]] = None) -> Dict[Tuple[int, int], Dict[str, Any]]:
|
||||
"""Get episode information from Sonarr including import history - optimized to only fetch needed episodes"""
|
||||
try:
|
||||
series_data = self.sonarr.series_by_imdb(imdb_id)
|
||||
if not series_data:
|
||||
@@ -154,11 +177,20 @@ class TVProcessor:
|
||||
|
||||
episodes = self.sonarr.episodes_for_series(series_id)
|
||||
|
||||
# Convert episodes_filter to set for faster lookup
|
||||
filter_set = set(episodes_filter) if episodes_filter else None
|
||||
|
||||
episode_map = {}
|
||||
api_calls_made = 0
|
||||
|
||||
for episode in episodes:
|
||||
season = episode.get('seasonNumber', 0)
|
||||
episode_num = episode.get('episodeNumber', 0)
|
||||
|
||||
# Skip episodes not in filter if filter is provided
|
||||
if filter_set and (season, episode_num) not in filter_set:
|
||||
continue
|
||||
|
||||
if season > 0 and episode_num > 0:
|
||||
# Get basic episode info
|
||||
episode_data = {
|
||||
@@ -170,6 +202,7 @@ class TVProcessor:
|
||||
episode_id = episode.get('id')
|
||||
if episode_id and episode.get('hasFile'):
|
||||
import_date = self.sonarr.get_episode_import_history(episode_id)
|
||||
api_calls_made += 1
|
||||
if import_date:
|
||||
episode_data['dateAdded'] = import_date
|
||||
_log("DEBUG", f"Got import date from history for S{season:02d}E{episode_num:02d}: {import_date}")
|
||||
@@ -183,6 +216,9 @@ class TVProcessor:
|
||||
|
||||
episode_map[(season, episode_num)] = episode_data
|
||||
|
||||
if filter_set:
|
||||
_log("DEBUG", f"Made {api_calls_made} Sonarr history API calls for filtered episodes (instead of all episodes)")
|
||||
|
||||
return episode_map
|
||||
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user