remove debug
This commit is contained in:
+33
-63
@@ -1,73 +1,43 @@
|
|||||||
# NFOGuard Development Summary
|
# 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)
|
### Latest Updates (v1.4.4)
|
||||||
- **📺 TV SHOW SUPPORT**: Extended preservation logic to tvshow.nfo, season.nfo, and episode.nfo
|
- **✅ SUCCESS**: TV webhook path mapping now working correctly!
|
||||||
- **🎯 CONSISTENT BEHAVIOR**: All NFO types now preserve existing content and append NFOGuard fields
|
- **🎯 FIXED**: Six Feet Under processing correctly (no more cross-processing)
|
||||||
- **✅ COMPREHENSIVE**: Movies, TV shows, seasons, and episodes all handle field placement correctly
|
- **📺 WORKING**: Episode batch processing and database storage functional
|
||||||
- **🧹 UNIFIED APPROACH**: Same preservation and bottom-placement logic across all media types
|
- **🔧 MINOR**: Fixed remaining path typo in tv6 configuration
|
||||||
|
|
||||||
### Complete NFO Management Coverage
|
### Working TV Webhook Flow
|
||||||
|
```
|
||||||
#### Movie NFO Structure
|
✅ Webhook received: Six Feet Under
|
||||||
```xml
|
✅ Path mapping: /mnt/unionfs/Media/TV/tv → /media/TV/tv
|
||||||
<movie>
|
✅ Series lookup: Found exact IMDb match (ID: 588)
|
||||||
<!-- All existing Radarr content preserved -->
|
✅ Episode processing: S01E03 processed successfully
|
||||||
<title>Movie Title</title>
|
✅ Database: Episode entry saved with timestamp
|
||||||
<plot>Plot...</plot>
|
✅ Result: 1/1 episodes processed
|
||||||
<actor>...</actor>
|
|
||||||
|
|
||||||
<!-- NFOGuard fields at bottom -->
|
|
||||||
<uniqueid type="imdb" default="true">tt8350360</uniqueid>
|
|
||||||
<premiered>2019-06-26</premiered>
|
|
||||||
<year>2019</year>
|
|
||||||
<dateadded>2025-09-14T13:50:34-04:00</dateadded>
|
|
||||||
<lockdata>true</lockdata>
|
|
||||||
</movie>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### TV Show NFO Structure
|
### Final Configuration Fix
|
||||||
```xml
|
**Your .env should have:**
|
||||||
<tvshow>
|
```bash
|
||||||
<!-- All existing Sonarr content preserved -->
|
# All paths working correctly:
|
||||||
<title>Show Title</title>
|
MOVIE_PATHS=/media/Movies/movies,/media/Movies/movies6
|
||||||
<plot>Show plot...</plot>
|
TV_PATHS=/media/TV/tv,/media/TV/tv6
|
||||||
<actor>...</actor>
|
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
|
||||||
<!-- NFOGuard fields at bottom -->
|
|
||||||
<uniqueid type="imdb" default="true">tt1234567</uniqueid>
|
|
||||||
<uniqueid type="tvdb">12345</uniqueid>
|
|
||||||
<lockdata>true</lockdata>
|
|
||||||
</tvshow>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Episode NFO Structure
|
### Complete System Status
|
||||||
```xml
|
- ✅ **Movie Webhooks**: Working perfectly with path mapping
|
||||||
<episodedetails>
|
- ✅ **TV Webhooks**: Working perfectly with path mapping
|
||||||
<!-- All existing Sonarr content preserved -->
|
- ✅ **NFO Management**: All media types preserve content and append fields
|
||||||
<title>Episode Title</title>
|
- ✅ **Database**: Clean schema with proper episode tracking
|
||||||
<plot>Episode plot...</plot>
|
- ✅ **Path Mapping**: Both movies/movies6 and tv/tv6 handled correctly
|
||||||
<director>...</director>
|
|
||||||
|
|
||||||
<!-- NFOGuard fields at bottom -->
|
|
||||||
<season>1</season>
|
|
||||||
<episode>5</episode>
|
|
||||||
<aired>2019-06-26</aired>
|
|
||||||
<dateadded>2025-09-14T13:50:34-04:00</dateadded>
|
|
||||||
<lockdata>true</lockdata>
|
|
||||||
</episodedetails>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Preservation Features
|
### Minor Notes
|
||||||
- ✅ **Movies**: Preserves title, plot, actors, ratings, all existing metadata
|
- ⚠️ TVDB API warnings are normal (not all series support TVDB lookup)
|
||||||
- ✅ **TV Shows**: Preserves show metadata, existing uniqueid[tvdb], actor info
|
- ✅ Episode processing completes successfully regardless
|
||||||
- ✅ **Episodes**: Preserves episode title, plot, director, existing aired dates
|
- ✅ IMDb-based series matching works reliably
|
||||||
- ✅ **Seasons**: Preserves any existing season metadata
|
|
||||||
- ✅ **All Types**: Existing content stays in original order, NFOGuard fields at bottom
|
|
||||||
|
|
||||||
### Complete Path Processing Pipeline
|
## 🎬📺 NFOGuard is now fully functional for both movies and TV shows! 🎉
|
||||||
- ✅ **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
|
|
||||||
+7
-29
@@ -10,70 +10,48 @@ from pathlib import Path
|
|||||||
class PathMapper:
|
class PathMapper:
|
||||||
"""Handles path mapping between different environments"""
|
"""Handles path mapping between different environments"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, config):
|
||||||
# Load path mappings from environment variables
|
"""Initialize path mapper with configuration"""
|
||||||
self.radarr_roots = self._parse_path_list(os.environ.get("RADARR_ROOT_FOLDERS", ""))
|
self.radarr_roots = [path.strip() for path in config.radarr_root_folders.split(',') if path.strip()]
|
||||||
self.sonarr_roots = self._parse_path_list(os.environ.get("SONARR_ROOT_FOLDERS", ""))
|
self.sonarr_roots = [path.strip() for path in config.sonarr_root_folders.split(',') if path.strip()]
|
||||||
self.movie_paths = self._parse_path_list(os.environ.get("MOVIE_PATHS", ""))
|
self.movie_paths = [path.strip() for path in config.movie_paths.split(',') if path.strip()]
|
||||||
self.tv_paths = self._parse_path_list(os.environ.get("TV_PATHS", ""))
|
self.tv_paths = [path.strip() for path in config.tv_paths.split(',') if path.strip()]
|
||||||
|
|
||||||
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 sonarr_path_to_container_path(self, sonarr_path: str) -> str:
|
def sonarr_path_to_container_path(self, sonarr_path: str) -> str:
|
||||||
"""Convert Sonarr path to container path using environment mappings"""
|
"""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
|
# 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 = [(i, root) for i, root in enumerate(self.sonarr_roots)]
|
||||||
indexed_roots.sort(key=lambda x: len(x[1]), reverse=True)
|
indexed_roots.sort(key=lambda x: len(x[1]), reverse=True)
|
||||||
|
|
||||||
# Try to match against configured Sonarr root folders (longest first)
|
# Try to match against configured Sonarr root folders (longest first)
|
||||||
for original_index, sonarr_root in indexed_roots:
|
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:
|
if sonarr_path.startswith(sonarr_root + '/') or sonarr_path == sonarr_root:
|
||||||
print(f"DEBUG: Match found! Index {original_index}")
|
|
||||||
# Map to corresponding TV path
|
# Map to corresponding TV path
|
||||||
if original_index < len(self.tv_paths):
|
if original_index < len(self.tv_paths):
|
||||||
container_root = self.tv_paths[original_index]
|
container_root = self.tv_paths[original_index]
|
||||||
relative_path = sonarr_path[len(sonarr_root):].lstrip('/')
|
relative_path = sonarr_path[len(sonarr_root):].lstrip('/')
|
||||||
result = str(Path(container_root) / relative_path) if relative_path else container_root
|
result = str(Path(container_root) / relative_path) if relative_path else container_root
|
||||||
print(f"DEBUG: Mapped to: {result}")
|
|
||||||
return 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
|
# No fallback - if path mapping fails, return original and let validation catch it
|
||||||
return sonarr_path
|
return sonarr_path
|
||||||
|
|
||||||
def radarr_path_to_container_path(self, radarr_path: str) -> str:
|
def radarr_path_to_container_path(self, radarr_path: str) -> str:
|
||||||
"""Convert Radarr path to container path using environment mappings"""
|
"""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
|
# 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 = [(i, root) for i, root in enumerate(self.radarr_roots)]
|
||||||
indexed_roots.sort(key=lambda x: len(x[1]), reverse=True)
|
indexed_roots.sort(key=lambda x: len(x[1]), reverse=True)
|
||||||
|
|
||||||
# Try to match against configured Radarr root folders (longest first)
|
# Try to match against configured Radarr root folders (longest first)
|
||||||
for original_index, radarr_root in indexed_roots:
|
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:
|
if radarr_path.startswith(radarr_root + '/') or radarr_path == radarr_root:
|
||||||
print(f"DEBUG: Match found! Index {original_index}")
|
|
||||||
# Map to corresponding movie path
|
# Map to corresponding movie path
|
||||||
if original_index < len(self.movie_paths):
|
if original_index < len(self.movie_paths):
|
||||||
container_root = self.movie_paths[original_index]
|
container_root = self.movie_paths[original_index]
|
||||||
relative_path = radarr_path[len(radarr_root):].lstrip('/')
|
relative_path = radarr_path[len(radarr_root):].lstrip('/')
|
||||||
result = str(Path(container_root) / relative_path) if relative_path else container_root
|
result = str(Path(container_root) / relative_path) if relative_path else container_root
|
||||||
print(f"DEBUG: Mapped to: {result}")
|
|
||||||
return 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
|
# No fallback - if path mapping fails, return original and let validation catch it
|
||||||
return radarr_path
|
return radarr_path
|
||||||
|
|
||||||
|
|||||||
@@ -188,6 +188,10 @@ def _load_environment_files():
|
|||||||
# Load environment files at startup
|
# Load environment files at startup
|
||||||
_load_environment_files()
|
_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:
|
def _bool_env(name: str, default: bool) -> bool:
|
||||||
v = os.environ.get(name)
|
v = os.environ.get(name)
|
||||||
if v is None:
|
if v is None:
|
||||||
|
|||||||
Reference in New Issue
Block a user