Merge pull request 'fix: Add filename-based title extraction for TV episodes' (#7) from titlename-fix into dev
Local Docker Build (Dev) / build-dev (push) Successful in 22s
Local Docker Build (Dev) / build-dev (push) Successful in 22s
Reviewed-on: #7
This commit is contained in:
+65
-9
@@ -568,7 +568,7 @@ class TVProcessor:
|
||||
for (season, episode), (aired, dateadded, source) in episode_dates.items():
|
||||
if (season, episode) in disk_episodes:
|
||||
# Get enhanced episode metadata
|
||||
enhanced_metadata = self._get_episode_metadata(series_metadata, season, episode) if series_metadata else None
|
||||
enhanced_metadata = self._get_episode_metadata(series_metadata, season, episode, season_path) if series_metadata else self._get_episode_metadata(None, season, episode, season_path)
|
||||
|
||||
# Create NFO
|
||||
if config.manage_nfo:
|
||||
@@ -659,7 +659,7 @@ class TVProcessor:
|
||||
|
||||
# Get enhanced metadata from Sonarr
|
||||
series_metadata = self._get_sonarr_series_metadata(imdb_id)
|
||||
enhanced_metadata = self._get_episode_metadata(series_metadata, season_num, episode_num) if series_metadata else None
|
||||
enhanced_metadata = self._get_episode_metadata(series_metadata, season_num, episode_num, season_path) if series_metadata else self._get_episode_metadata(None, season_num, episode_num, season_path)
|
||||
|
||||
# Get episode date
|
||||
aired, dateadded, source = self._get_single_episode_date(imdb_id, season_num, episode_num, series_metadata)
|
||||
@@ -739,19 +739,75 @@ class TVProcessor:
|
||||
_log("ERROR", f"Error getting Sonarr metadata for {imdb_id}: {e}")
|
||||
return None
|
||||
|
||||
def _get_episode_metadata(self, series_metadata: Dict[str, Any], season_num: int, episode_num: int) -> Optional[Dict[str, Any]]:
|
||||
"""Extract specific episode metadata from series data"""
|
||||
if not series_metadata or "episodes" not in series_metadata:
|
||||
return None
|
||||
def _get_episode_metadata(self, series_metadata: Dict[str, Any], season_num: int, episode_num: int, season_dir: Optional[Path] = None) -> Optional[Dict[str, Any]]:
|
||||
"""Extract specific episode metadata from series data with filename fallback for titles"""
|
||||
metadata = {
|
||||
"title": None,
|
||||
"overview": None,
|
||||
"runtime": None,
|
||||
"ratings": {}
|
||||
}
|
||||
|
||||
# Try to get metadata from Sonarr first
|
||||
if series_metadata and "episodes" in series_metadata:
|
||||
for episode in series_metadata["episodes"]:
|
||||
if episode.get("seasonNumber") == season_num and episode.get("episodeNumber") == episode_num:
|
||||
return {
|
||||
metadata.update({
|
||||
"title": episode.get("title"),
|
||||
"overview": episode.get("overview"),
|
||||
"runtime": episode.get("runtime"),
|
||||
"ratings": episode.get("ratings", {})
|
||||
}
|
||||
})
|
||||
break
|
||||
|
||||
# If no title from Sonarr, try to extract from filename
|
||||
if not metadata["title"] and season_dir:
|
||||
filename_title = self._extract_title_from_filename(season_dir, season_num, episode_num)
|
||||
if filename_title:
|
||||
metadata["title"] = filename_title
|
||||
_log("INFO", f"Using filename-extracted title for S{season_num:02d}E{episode_num:02d}: '{filename_title}'")
|
||||
|
||||
# Return metadata if we have at least some information
|
||||
if any(metadata.values()):
|
||||
return metadata
|
||||
|
||||
return None
|
||||
|
||||
def _extract_title_from_filename(self, season_dir: Path, season_num: int, episode_num: int) -> Optional[str]:
|
||||
"""Extract episode title from video filename as fallback when Sonarr doesn't provide it"""
|
||||
try:
|
||||
import re
|
||||
# Look for video files matching this episode
|
||||
season_pattern = f"S{season_num:02d}E{episode_num:02d}"
|
||||
|
||||
for video_file in season_dir.glob("*.mkv"):
|
||||
filename = video_file.name
|
||||
if season_pattern in filename:
|
||||
# Pattern: SeriesName-S01E01-Episode Title[WEBDL-1080p][AAC2.0][h264].mkv
|
||||
# Extract the part between season/episode and the first bracket
|
||||
match = re.search(rf'{season_pattern}-(.*?)\[', filename)
|
||||
if match:
|
||||
title = match.group(1).strip()
|
||||
# Clean up common encoding artifacts and separators
|
||||
title = title.replace('-', ' ').strip()
|
||||
if title:
|
||||
_log("DEBUG", f"Extracted title from filename: '{title}' for {season_pattern}")
|
||||
return title
|
||||
|
||||
# Also check .mp4 files
|
||||
for video_file in season_dir.glob("*.mp4"):
|
||||
filename = video_file.name
|
||||
if season_pattern in filename:
|
||||
match = re.search(rf'{season_pattern}-(.*?)\[', filename)
|
||||
if match:
|
||||
title = match.group(1).strip()
|
||||
title = title.replace('-', ' ').strip()
|
||||
if title:
|
||||
_log("DEBUG", f"Extracted title from filename: '{title}' for {season_pattern}")
|
||||
return title
|
||||
|
||||
except Exception as e:
|
||||
_log("DEBUG", f"Error extracting title from filename for S{season_num:02d}E{episode_num:02d}: {e}")
|
||||
|
||||
return None
|
||||
|
||||
@@ -869,7 +925,7 @@ class TVProcessor:
|
||||
# Get episode date information - webhook processing prioritizes existing DB entries
|
||||
_log("DEBUG", f"Processing webhook episode: IMDb={imdb_id}, S{season_num:02d}E{episode_num:02d}")
|
||||
aired, dateadded, source = self._get_webhook_episode_date(imdb_id, season_num, episode_num, series_metadata)
|
||||
enhanced_metadata = self._get_episode_metadata(series_metadata, season_num, episode_num) if series_metadata else None
|
||||
enhanced_metadata = self._get_episode_metadata(series_metadata, season_num, episode_num, season_dir) if series_metadata else self._get_episode_metadata(None, season_num, episode_num, season_dir)
|
||||
|
||||
# Create NFO
|
||||
if config.manage_nfo:
|
||||
|
||||
Reference in New Issue
Block a user