From 179f8f51d7738944db1f14444ddbdad1c951a658 Mon Sep 17 00:00:00 2001 From: SBCrumb Date: Sun, 14 Sep 2025 13:49:15 -0400 Subject: [PATCH] nfo dates to the bottom --- SUMMARY.md | 138 ++++++++++---------------------------------- VERSION | 2 +- core/nfo_manager.py | 24 +++++--- 3 files changed, 48 insertions(+), 116 deletions(-) diff --git a/SUMMARY.md b/SUMMARY.md index 09b87c9..697daef 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,113 +1,39 @@ # NFOGuard Development Summary -## Current Status: v1.3.7 - NFO XML Parsing Fix +## Current Status: v1.3.8 - NFO Field Ordering Fix -### Latest Updates (v1.3.7) -- **๏ฟฝ FIXED**: XML comment parsing error causing NFO creation to fail -- **๐Ÿ”ง XML HANDLING**: Improved XML comment insertion and file writing -- **โœ… PRESERVATION**: Existing movie metadata properly preserved during updates -- **๐ŸŽฏ ROBUST**: Better error handling for malformed XML files +### Latest Updates (v1.3.8) +- **๐ŸŽฏ FIELD ORDERING**: NFOGuard fields now append at bottom of existing NFO content +- **๐Ÿ“‹ STRUCTURE**: Date fields (premiered, dateadded, lockdata) appear after all existing metadata +- **โœ… PRESERVATION**: All existing content (actors, plot, ratings, etc.) maintained in original order +- **๐Ÿงน SMART CLEANUP**: Only removes NFOGuard-added elements, preserves existing uniqueid[tmdb] -### NFO Update Process (Fixed) -``` -1. โœ… Load existing movie.nfo (if exists) -2. โœ… Parse and validate XML structure -3. โœ… Remove old NFOGuard elements to avoid duplicates -4. โœ… Preserve all existing content (title, plot, cast, etc.) -5. โœ… Add/update NFOGuard fields (dateadded, lockdata, uniqueid) -6. โœ… Write properly formatted XML with comment +### NFO Field Order (Fixed) +**Now places NFOGuard fields at the bottom:** +```xml + + + Movie Title + Plot content... + ... + + + + tt8350360 + 2019-06-26 + 2025-09-14T13:45:54-04:00 + true + ``` -### Error Resolution -- **v1.3.6**: XML comment handling caused `'()` error -- **v1.3.7**: Fixed comment insertion and XML serialization -- **Result**: NFO files now update correctly while preserving contentlopment Summary +### Smart Element Management +- โœ… Preserves existing `uniqueid[tmdb]` and other IDs +- โœ… Only removes NFOGuard-managed `uniqueid[imdb]` to avoid duplicates +- โœ… Appends new fields using `ET.SubElement()` for bottom placement +- โœ… Maintains clean XML structure and formatting -## Current Status: v1.3.3 - Database Migration & Path Validation Complete - -### Latest Updates (v1.3.3) -- **๏ฟฝ DATABASE**: Fixed missing `path` column migration in movies table -- **โœ… MIGRATION**: Automatic schema updates with graceful error handling -- **๐Ÿ” VALIDATION**: Enhanced database migration with column existence checks -- **๐ŸŽฏ COMPATIBILITY**: Backward compatibility with existing databases maintained - -### Path Mapping Success (v1.3.2-v1.3.3) -- **๐Ÿ› CRITICAL**: Fixed substring matching bug (movies/movies6, tv/tv6) -- **๐ŸŽฏ ALGORITHM**: Longest-path-first matching prevents incorrect mappings -- **๏ฟฝ DEBUG**: Comprehensive debug logging for troubleshooting -- **โœ… TESTED**: Annabelle webhook now processes correctly - -### Working Path Mapping Example -``` -Radarr webhook: /mnt/unionfs/Media/Movies/movies6/Annabelle... -โœ… Sort by length: [movies6, movies] (longest first) -โœ… Match movies6: /mnt/unionfs/Media/Movies/movies6 -โœ… Map to index 1: /media/Movies/movies6 -โœ… Result: /media/Movies/movies6/Annabelle (2014) [tt3322940] -โœ… Path exists: Validation passes -โœ… Processing: Movie webhook succeeds -``` - -### Environment Configuration Required -- `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` - -### Previous Updates (v1.3.1) -- **๐Ÿ› FIXED**: 'container_path' undefined variable error in Radarr webhook handler -- **๐Ÿ”ง ENHANCED**: Webhook now properly handles both 'folderPath' and 'path' fields -- **โœ… VALIDATION**: Added mandatory path validation before processing -- **๐ŸŽฏ BATCH**: Enhanced batch processing with IMDb ID validation to prevent cross-processing - -### Zero Hardcoded Paths -- โœ… No default fallback paths in configuration -- โœ… Application fails with clear error if paths not configured -- โœ… Works with any folder structure -- โœ… Completely portable between environments - -### Database Migration Support -- โœ… Automatic schema updates for existing databases -- โœ… Graceful handling of missing columns -- โœ… Backward compatibility maintained - -### Webhook Processing Flow -1. **Reception**: Webhook received and parsed -2. **Path Resolution**: External path mapped to container path using environment mappings -3. **Validation**: Verify mapped path exists and IMDb ID matches -4. **Batching**: Add to processing queue with anti-storm protection -5. **Processing**: Date resolution, NFO creation, file timestamp updates -6. **Database**: Record processing history and results - -### Technical Architecture -- **Path Mapper**: Environment-configurable path translation -- **NFO Manager**: Creates metadata files with proper date attribution -- **Database Manager**: SQLite with automatic migration support -- **Webhook Batcher**: Intelligent batching with validation -- **Client Managers**: API access for external services - -### Debug Features -- **Path Mapping Debug**: Detailed logging of path translation process -- **Health Endpoint**: Database and external service status -- **Statistics API**: Comprehensive media library statistics -- **Debug Endpoints**: Movie import analysis, TMDB lookup testing - -## Configuration Requirements - -### Critical Environment Variables -```bash -# Required - Application will fail without these -MOVIE_PATHS=/your/container/movie/paths -TV_PATHS=/your/container/tv/paths -RADARR_ROOT_FOLDERS=/host/radarr/paths -SONARR_ROOT_FOLDERS=/host/sonarr/paths - -# Database and logging -DB_PATH=/app/data/media_dates.db -LOG_DIR=/app/data/logs -``` - -### Known Issues -- Path mapping must exactly match your container and host configurations -- Database requires migration for existing installations -- Debug logging may be verbose during path mapping troubleshooting \ No newline at end of file +### 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 diff --git a/VERSION b/VERSION index 3336003..e05cb33 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.7 +1.3.8 diff --git a/core/nfo_manager.py b/core/nfo_manager.py index 0ca9f17..c1a36bc 100644 --- a/core/nfo_manager.py +++ b/core/nfo_manager.py @@ -52,14 +52,17 @@ class NFOManager: raise ValueError("Root element is not ") # Remove existing NFOGuard-managed elements to avoid duplicates + # These will be re-added at the bottom for tag in ["dateadded", "lockdata"]: existing = movie.find(tag) if existing is not None: movie.remove(existing) - # Remove any existing uniqueid with type="imdb" + # Remove any existing uniqueid with type="imdb" added by NFOGuard + # (Keep other uniqueid elements like tmdb) for uniqueid in movie.findall("uniqueid[@type='imdb']"): - movie.remove(uniqueid) + if uniqueid.get('default') == 'true': + movie.remove(uniqueid) except (ET.ParseError, ValueError) as e: print(f"Warning: Could not parse existing NFO {nfo_path}, creating new: {e}") @@ -68,21 +71,24 @@ class NFOManager: # Create new NFO structure movie = ET.Element("movie") - # Add/update IMDb uniqueid + # Now append NFOGuard fields at the END of the file + # This ensures they appear after all existing content + + # Add/update IMDb uniqueid at the end uniqueid = ET.SubElement(movie, "uniqueid", type="imdb", default="true") uniqueid.text = imdb_id - # Add dateadded - if dateadded: - dateadded_elem = ET.SubElement(movie, "dateadded") - dateadded_elem.text = dateadded - # Add premiered if we have release date (only if not already present) if released and movie.find("premiered") is None: premiered_elem = ET.SubElement(movie, "premiered") premiered_elem.text = released[:10] if len(released) >= 10 else released - # Add lockdata if requested + # Add dateadded at the end + if dateadded: + dateadded_elem = ET.SubElement(movie, "dateadded") + dateadded_elem.text = dateadded + + # Add lockdata at the very end if lock_metadata: lockdata = ET.SubElement(movie, "lockdata") lockdata.text = "true"