diff --git a/core/nfo_manager.py b/core/nfo_manager.py index 94ade70..d16e213 100644 --- a/core/nfo_manager.py +++ b/core/nfo_manager.py @@ -248,6 +248,59 @@ class NFOManager: print(f"⚠️ Error enhancing NFO with title: {e}") return False + 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 metadata 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}" + print(f"🔍 Searching for title in files for {season_pattern} in directory: {season_dir}") + + for video_file in season_dir.glob("*.mkv"): + filename = video_file.name + print(f"🔍 Checking file: {filename}") + if season_pattern in filename: + print(f"✅ Found matching file: {filename}") + # Pattern: SeriesName-S01E01-Episode Title[WEBDL-1080p][AAC2.0][h264].mkv + # Extract the part between season/episode and the first bracket + pattern = rf'{season_pattern}-(.*?)\[' + print(f"🔍 Using regex pattern: {pattern}") + match = re.search(pattern, filename) + if match: + title = match.group(1).strip() + print(f"🔍 Raw extracted title: '{title}'") + # Clean up common encoding artifacts and separators + title = title.replace('-', ' ').strip() + if title: + print(f"✅ Extracted title from filename: '{title}' for {season_pattern}") + return title + else: + print(f"⚠️ Title was empty after cleanup") + else: + print(f"⚠️ Regex pattern didn't match filename") + + # Also check .mp4 files + for video_file in season_dir.glob("*.mp4"): + filename = video_file.name + print(f"🔍 Checking .mp4 file: {filename}") + if season_pattern in filename: + print(f"✅ Found matching .mp4 file: {filename}") + pattern = rf'{season_pattern}-(.*?)\[' + match = re.search(pattern, filename) + if match: + title = match.group(1).strip() + print(f"🔍 Raw extracted title from .mp4: '{title}'") + title = title.replace('-', ' ').strip() + if title: + print(f"✅ Extracted title from .mp4 filename: '{title}' for {season_pattern}") + return title + + except Exception as e: + print(f"⚠️ Error extracting title from filename for S{season_num:02d}E{episode_num:02d}: {e}") + + print(f"⚠️ No title found in filenames for {season_pattern}") + return None + def _parse_nfo_with_tolerance(self, nfo_path: Path): """Parse NFO file with tolerance for URLs appended after XML""" try: @@ -643,6 +696,23 @@ class NFOManager: runtime_elem = ET.SubElement(episode, "runtime") runtime_elem.text = str(enhanced_metadata["runtime"]) + # Fallback: Extract title from filename if no title present + if not episode.find("title") or not episode.find("title").text: + print(f"🔍 No title found in NFO for S{season_num:02d}E{episode_num:02d}, attempting filename extraction") + filename_title = self._extract_title_from_filename(season_dir, season_num, episode_num) + if filename_title: + # Remove existing empty title element if present + existing_title = episode.find("title") + if existing_title is not None: + episode.remove(existing_title) + + # Add new title element + title_elem = ET.SubElement(episode, "title") + title_elem.text = filename_title + print(f"✅ Added filename-extracted title to NFO: S{season_num:02d}E{episode_num:02d} - '{filename_title}'") + else: + print(f"⚠️ Could not extract title from filename for S{season_num:02d}E{episode_num:02d}") + # Add NFOGuard fields at the bottom # Basic episode info at the end