diff --git a/SUMMARY.md b/SUMMARY.md
index 2bdc96e..a355427 100644
--- a/SUMMARY.md
+++ b/SUMMARY.md
@@ -1,73 +1,43 @@
# NFOGuard Development Summary
-## Current Status: v1.4.1 - Complete TV & Movie NFO Management
+## Current Status: v1.4.4 - TV Webhooks Working! ๐
-### Latest Updates (v1.4.1)
-- **๐บ TV SHOW SUPPORT**: Extended preservation logic to tvshow.nfo, season.nfo, and episode.nfo
-- **๐ฏ CONSISTENT BEHAVIOR**: All NFO types now preserve existing content and append NFOGuard fields
-- **โ
COMPREHENSIVE**: Movies, TV shows, seasons, and episodes all handle field placement correctly
-- **๐งน UNIFIED APPROACH**: Same preservation and bottom-placement logic across all media types
+### Latest Updates (v1.4.4)
+- **โ
SUCCESS**: TV webhook path mapping now working correctly!
+- **๐ฏ FIXED**: Six Feet Under processing correctly (no more cross-processing)
+- **๐บ WORKING**: Episode batch processing and database storage functional
+- **๐ง MINOR**: Fixed remaining path typo in tv6 configuration
-### Complete NFO Management Coverage
-
-#### Movie NFO Structure
-```xml
-
-
- Movie Title
- Plot...
- ...
-
-
- tt8350360
- 2019-06-26
- 2019
- 2025-09-14T13:50:34-04:00
- true
-
+### Working TV Webhook Flow
+```
+โ
Webhook received: Six Feet Under
+โ
Path mapping: /mnt/unionfs/Media/TV/tv โ /media/TV/tv
+โ
Series lookup: Found exact IMDb match (ID: 588)
+โ
Episode processing: S01E03 processed successfully
+โ
Database: Episode entry saved with timestamp
+โ
Result: 1/1 episodes processed
```
-#### TV Show NFO Structure
-```xml
-
-
- Show Title
- Show plot...
- ...
-
-
- tt1234567
- 12345
- true
-
+### Final Configuration Fix
+**Your .env should have:**
+```bash
+# All paths working correctly:
+MOVIE_PATHS=/media/Movies/movies,/media/Movies/movies6
+TV_PATHS=/media/TV/tv,/media/TV/tv6
+RADARR_ROOT_FOLDERS=/mnt/unionfs/Media/Movies/movies,/mnt/unionfs/Media/Movies/movies6
+SONARR_ROOT_FOLDERS=/mnt/unionfs/Media/TV/tv,/mnt/unionfs/Media/TV/tv6
```
-#### Episode NFO Structure
-```xml
-
-
- Episode Title
- Episode plot...
- ...
-
-
- 1
- 5
- 2019-06-26
- 2025-09-14T13:50:34-04:00
- true
-
-```
+### Complete System Status
+- โ
**Movie Webhooks**: Working perfectly with path mapping
+- โ
**TV Webhooks**: Working perfectly with path mapping
+- โ
**NFO Management**: All media types preserve content and append fields
+- โ
**Database**: Clean schema with proper episode tracking
+- โ
**Path Mapping**: Both movies/movies6 and tv/tv6 handled correctly
-### Preservation Features
-- โ
**Movies**: Preserves title, plot, actors, ratings, all existing metadata
-- โ
**TV Shows**: Preserves show metadata, existing uniqueid[tvdb], actor info
-- โ
**Episodes**: Preserves episode title, plot, director, existing aired dates
-- โ
**Seasons**: Preserves any existing season metadata
-- โ
**All Types**: Existing content stays in original order, NFOGuard fields at bottom
+### Minor Notes
+- โ ๏ธ TVDB API warnings are normal (not all series support TVDB lookup)
+- โ
Episode processing completes successfully regardless
+- โ
IMDb-based series matching works reliably
-### Complete Path Processing Pipeline
-- โ
**Path Mapping**: Fixed substring matching (movies/movies6, tv/tv6)
-- โ
**Database Schema**: Clean migration with all required columns
-- โ
**NFO Preservation**: Existing metadata maintained with fields appended
-- โ
**Webhook Processing**: End-to-end processing working correctly
\ No newline at end of file
+## ๐ฌ๐บ NFOGuard is now fully functional for both movies and TV shows! ๐
\ No newline at end of file
diff --git a/VERSION b/VERSION
index 347f583..e516bb9 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.4.1
+1.4.5
diff --git a/core/path_mapper.py b/core/path_mapper.py
index 0b1a9d2..3e3e7a2 100644
--- a/core/path_mapper.py
+++ b/core/path_mapper.py
@@ -10,70 +10,48 @@ from pathlib import Path
class PathMapper:
"""Handles path mapping between different environments"""
- def __init__(self):
- # Load path mappings from environment variables
- self.radarr_roots = self._parse_path_list(os.environ.get("RADARR_ROOT_FOLDERS", ""))
- self.sonarr_roots = self._parse_path_list(os.environ.get("SONARR_ROOT_FOLDERS", ""))
- self.movie_paths = self._parse_path_list(os.environ.get("MOVIE_PATHS", ""))
- self.tv_paths = self._parse_path_list(os.environ.get("TV_PATHS", ""))
-
- def _parse_path_list(self, path_string: str) -> list:
- """Parse comma-separated path string into list"""
- if not path_string:
- return []
- return [p.strip() for p in path_string.split(",") if p.strip()]
-
+ def __init__(self, config):
+ """Initialize path mapper with configuration"""
+ self.radarr_roots = [path.strip() for path in config.radarr_root_folders.split(',') if path.strip()]
+ self.sonarr_roots = [path.strip() for path in config.sonarr_root_folders.split(',') if path.strip()]
+ self.movie_paths = [path.strip() for path in config.movie_paths.split(',') if path.strip()]
+ self.tv_paths = [path.strip() for path in config.tv_paths.split(',') if path.strip()]
+
def sonarr_path_to_container_path(self, sonarr_path: str) -> str:
"""Convert Sonarr path to container path using environment mappings"""
- print(f"DEBUG: sonarr_path_to_container_path input: {sonarr_path}")
- print(f"DEBUG: sonarr_roots: {self.sonarr_roots}")
- print(f"DEBUG: tv_paths: {self.tv_paths}")
-
# Sort roots by length (longest first) to avoid substring matching issues
indexed_roots = [(i, root) for i, root in enumerate(self.sonarr_roots)]
indexed_roots.sort(key=lambda x: len(x[1]), reverse=True)
# Try to match against configured Sonarr root folders (longest first)
for original_index, sonarr_root in indexed_roots:
- print(f"DEBUG: Checking sonarr_root[{original_index}]: {sonarr_root}")
if sonarr_path.startswith(sonarr_root + '/') or sonarr_path == sonarr_root:
- print(f"DEBUG: Match found! Index {original_index}")
# Map to corresponding TV path
if original_index < len(self.tv_paths):
container_root = self.tv_paths[original_index]
relative_path = sonarr_path[len(sonarr_root):].lstrip('/')
result = str(Path(container_root) / relative_path) if relative_path else container_root
- print(f"DEBUG: Mapped to: {result}")
return result
- print(f"DEBUG: No match found, returning original: {sonarr_path}")
# No fallback - if path mapping fails, return original and let validation catch it
return sonarr_path
def radarr_path_to_container_path(self, radarr_path: str) -> str:
"""Convert Radarr path to container path using environment mappings"""
- print(f"DEBUG: radarr_path_to_container_path input: {radarr_path}")
- print(f"DEBUG: radarr_roots: {self.radarr_roots}")
- print(f"DEBUG: movie_paths: {self.movie_paths}")
-
# Sort roots by length (longest first) to avoid substring matching issues
indexed_roots = [(i, root) for i, root in enumerate(self.radarr_roots)]
indexed_roots.sort(key=lambda x: len(x[1]), reverse=True)
# Try to match against configured Radarr root folders (longest first)
for original_index, radarr_root in indexed_roots:
- print(f"DEBUG: Checking radarr_root[{original_index}]: {radarr_root}")
if radarr_path.startswith(radarr_root + '/') or radarr_path == radarr_root:
- print(f"DEBUG: Match found! Index {original_index}")
# Map to corresponding movie path
if original_index < len(self.movie_paths):
container_root = self.movie_paths[original_index]
relative_path = radarr_path[len(radarr_root):].lstrip('/')
result = str(Path(container_root) / relative_path) if relative_path else container_root
- print(f"DEBUG: Mapped to: {result}")
return result
- print(f"DEBUG: No match found, returning original: {radarr_path}")
# No fallback - if path mapping fails, return original and let validation catch it
return radarr_path
diff --git a/nfoguard.py b/nfoguard.py
index f4a6d2f..422f5ad 100644
--- a/nfoguard.py
+++ b/nfoguard.py
@@ -188,6 +188,10 @@ def _load_environment_files():
# Load environment files at startup
_load_environment_files()
+# Add debug logging near where configuration is loaded
+print(f"DEBUG: Environment check - SONARR_ROOT_FOLDERS: {os.getenv('SONARR_ROOT_FOLDERS')}")
+print(f"DEBUG: Environment check - TV_PATHS: {os.getenv('TV_PATHS')}")
+
def _bool_env(name: str, default: bool) -> bool:
v = os.environ.get(name)
if v is None: