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"