This commit is contained in:
+36
-1
@@ -320,4 +320,39 @@ def register_routes(
|
|||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_log("ERROR", f"Optimized scan failed: {e}")
|
_log("ERROR", f"Optimized scan failed: {e}")
|
||||||
raise HTTPException(status_code=500, detail=f"Optimized scan failed: {str(e)}")
|
raise HTTPException(status_code=500, detail=f"Optimized scan failed: {str(e)}")
|
||||||
|
|
||||||
|
@app.post("/nfo/strip-lockdata")
|
||||||
|
async def strip_lockdata_from_library(background_tasks: BackgroundTasks):
|
||||||
|
"""Strip lockdata elements from all NFO files for Emby compatibility"""
|
||||||
|
try:
|
||||||
|
_log("INFO", "Lockdata stripping initiated via API")
|
||||||
|
|
||||||
|
def strip_lockdata_task():
|
||||||
|
total_processed = 0
|
||||||
|
|
||||||
|
# Process TV libraries
|
||||||
|
for tv_path in config.tv_paths:
|
||||||
|
if tv_path.exists():
|
||||||
|
_log("INFO", f"Stripping lockdata from TV library: {tv_path}")
|
||||||
|
processed = tv_processor.nfo_manager.strip_lockdata_from_directory(tv_path)
|
||||||
|
total_processed += processed
|
||||||
|
|
||||||
|
# Process Movie libraries
|
||||||
|
for movie_path in config.movie_paths:
|
||||||
|
if movie_path.exists():
|
||||||
|
_log("INFO", f"Stripping lockdata from movie library: {movie_path}")
|
||||||
|
processed = movie_processor.nfo_manager.strip_lockdata_from_directory(movie_path)
|
||||||
|
total_processed += processed
|
||||||
|
|
||||||
|
_log("INFO", f"Lockdata stripping complete: {total_processed} NFO files processed")
|
||||||
|
|
||||||
|
background_tasks.add_task(strip_lockdata_task)
|
||||||
|
return {
|
||||||
|
"status": "started",
|
||||||
|
"message": "Lockdata stripping initiated for Emby compatibility",
|
||||||
|
"note": "This will remove <lockdata>true</lockdata> from all NFO files"
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
_log("ERROR", f"Lockdata stripping failed: {e}")
|
||||||
|
raise HTTPException(status_code=500, detail=f"Lockdata stripping failed: {str(e)}")
|
||||||
+97
-26
@@ -138,11 +138,26 @@ class NFOManager:
|
|||||||
# Look for NFOGuard fields
|
# Look for NFOGuard fields
|
||||||
dateadded_elem = root.find('.//dateadded')
|
dateadded_elem = root.find('.//dateadded')
|
||||||
premiered_elem = root.find('.//premiered')
|
premiered_elem = root.find('.//premiered')
|
||||||
lockdata_elem = root.find('.//lockdata')
|
# Strip any existing lockdata elements for Emby compatibility
|
||||||
|
lockdata_elements = root.findall('.//lockdata')
|
||||||
|
if lockdata_elements:
|
||||||
|
modified = False
|
||||||
|
for lockdata_elem in lockdata_elements:
|
||||||
|
# Find parent and remove the element
|
||||||
|
for parent in root.iter():
|
||||||
|
if lockdata_elem in parent:
|
||||||
|
parent.remove(lockdata_elem)
|
||||||
|
modified = True
|
||||||
|
_log("DEBUG", f"Stripped lockdata element from {nfo_path.name}")
|
||||||
|
break
|
||||||
|
if modified:
|
||||||
|
# Write back the cleaned NFO
|
||||||
|
tree = ET.ElementTree(root)
|
||||||
|
ET.indent(tree, space=" ", level=0)
|
||||||
|
tree.write(nfo_path, encoding="utf-8", xml_declaration=True)
|
||||||
|
|
||||||
# Only consider it NFOGuard-managed if it has dateadded and lockdata
|
# Only consider it NFOGuard-managed if it has dateadded (lockdata no longer required)
|
||||||
if (dateadded_elem is not None and dateadded_elem.text and
|
if (dateadded_elem is not None and dateadded_elem.text):
|
||||||
lockdata_elem is not None and lockdata_elem.text == "true"):
|
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
"dateadded": dateadded_elem.text.strip(),
|
"dateadded": dateadded_elem.text.strip(),
|
||||||
@@ -176,11 +191,26 @@ class NFOManager:
|
|||||||
# Look for NFOGuard fields in episode NFO
|
# Look for NFOGuard fields in episode NFO
|
||||||
dateadded_elem = root.find('.//dateadded')
|
dateadded_elem = root.find('.//dateadded')
|
||||||
aired_elem = root.find('.//aired')
|
aired_elem = root.find('.//aired')
|
||||||
lockdata_elem = root.find('.//lockdata')
|
# Strip any existing lockdata elements for Emby compatibility
|
||||||
|
lockdata_elements = root.findall('.//lockdata')
|
||||||
|
if lockdata_elements:
|
||||||
|
modified = False
|
||||||
|
for lockdata_elem in lockdata_elements:
|
||||||
|
# Find parent and remove the element
|
||||||
|
for parent in root.iter():
|
||||||
|
if lockdata_elem in parent:
|
||||||
|
parent.remove(lockdata_elem)
|
||||||
|
modified = True
|
||||||
|
_log("DEBUG", f"Stripped lockdata element from {nfo_path.name}")
|
||||||
|
break
|
||||||
|
if modified:
|
||||||
|
# Write back the cleaned NFO
|
||||||
|
tree = ET.ElementTree(root)
|
||||||
|
ET.indent(tree, space=" ", level=0)
|
||||||
|
tree.write(nfo_path, encoding="utf-8", xml_declaration=True)
|
||||||
|
|
||||||
# Only consider it NFOGuard-managed if it has dateadded and lockdata
|
# Only consider it NFOGuard-managed if it has dateadded (lockdata no longer required)
|
||||||
if (dateadded_elem is not None and dateadded_elem.text and
|
if (dateadded_elem is not None and dateadded_elem.text):
|
||||||
lockdata_elem is not None and lockdata_elem.text == "true"):
|
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
"dateadded": dateadded_elem.text.strip(),
|
"dateadded": dateadded_elem.text.strip(),
|
||||||
@@ -350,7 +380,7 @@ class NFOManager:
|
|||||||
|
|
||||||
# Remove existing NFOGuard-managed elements to avoid duplicates
|
# Remove existing NFOGuard-managed elements to avoid duplicates
|
||||||
# These will be re-added at the very bottom
|
# These will be re-added at the very bottom
|
||||||
nfoguard_fields = ["dateadded", "lockdata", "premiered", "year"]
|
nfoguard_fields = ["dateadded", "premiered", "year"]
|
||||||
for tag in nfoguard_fields:
|
for tag in nfoguard_fields:
|
||||||
existing = movie.find(tag)
|
existing = movie.find(tag)
|
||||||
if existing is not None:
|
if existing is not None:
|
||||||
@@ -410,11 +440,7 @@ class NFOManager:
|
|||||||
movie.append(dateadded_elem)
|
movie.append(dateadded_elem)
|
||||||
print(f"✅ Added dateadded to NFO: {dateadded}")
|
print(f"✅ Added dateadded to NFO: {dateadded}")
|
||||||
|
|
||||||
# Add lockdata at the very end
|
# Note: lockdata element removed for Emby compatibility
|
||||||
if lock_metadata:
|
|
||||||
lockdata = ET.Element("lockdata")
|
|
||||||
lockdata.text = "true"
|
|
||||||
movie.append(lockdata)
|
|
||||||
|
|
||||||
# Write file with proper formatting
|
# Write file with proper formatting
|
||||||
tree = ET.ElementTree(movie)
|
tree = ET.ElementTree(movie)
|
||||||
@@ -476,9 +502,7 @@ class NFOManager:
|
|||||||
tvdb_uniqueid = ET.SubElement(tvshow, "uniqueid", type="tvdb")
|
tvdb_uniqueid = ET.SubElement(tvshow, "uniqueid", type="tvdb")
|
||||||
tvdb_uniqueid.text = tvdb_id
|
tvdb_uniqueid.text = tvdb_id
|
||||||
|
|
||||||
# Add lockdata at the very end
|
# Note: lockdata element removed for Emby compatibility
|
||||||
lockdata = ET.SubElement(tvshow, "lockdata")
|
|
||||||
lockdata.text = "true"
|
|
||||||
|
|
||||||
# Add NFOGuard comment at the beginning
|
# Add NFOGuard comment at the beginning
|
||||||
comment_text = f" Created by {self.manager_brand} "
|
comment_text = f" Created by {self.manager_brand} "
|
||||||
@@ -521,7 +545,7 @@ class NFOManager:
|
|||||||
raise ValueError("Root element is not <season>")
|
raise ValueError("Root element is not <season>")
|
||||||
|
|
||||||
# Remove existing NFOGuard-managed elements
|
# Remove existing NFOGuard-managed elements
|
||||||
for tag in ["seasonnumber", "lockdata"]:
|
for tag in ["seasonnumber"]:
|
||||||
existing = season.find(tag)
|
existing = season.find(tag)
|
||||||
if existing is not None:
|
if existing is not None:
|
||||||
season.remove(existing)
|
season.remove(existing)
|
||||||
@@ -538,9 +562,7 @@ class NFOManager:
|
|||||||
seasonnumber = ET.SubElement(season, "seasonnumber")
|
seasonnumber = ET.SubElement(season, "seasonnumber")
|
||||||
seasonnumber.text = str(season_number)
|
seasonnumber.text = str(season_number)
|
||||||
|
|
||||||
# Add lockdata at the end
|
# Note: lockdata element removed for Emby compatibility
|
||||||
lockdata = ET.SubElement(season, "lockdata")
|
|
||||||
lockdata.text = "true"
|
|
||||||
|
|
||||||
# Add NFOGuard comment at the beginning
|
# Add NFOGuard comment at the beginning
|
||||||
comment_text = f" Created by {self.manager_brand} "
|
comment_text = f" Created by {self.manager_brand} "
|
||||||
@@ -653,7 +675,7 @@ class NFOManager:
|
|||||||
preserved_values = {}
|
preserved_values = {}
|
||||||
|
|
||||||
# Extract and preserve NFOGuard-managed fields (we'll re-add these at the bottom)
|
# Extract and preserve NFOGuard-managed fields (we'll re-add these at the bottom)
|
||||||
nfoguard_fields = ["aired", "dateadded", "lockdata", "season", "episode"]
|
nfoguard_fields = ["aired", "dateadded", "season", "episode"]
|
||||||
for tag in nfoguard_fields:
|
for tag in nfoguard_fields:
|
||||||
existing = episode.find(tag)
|
existing = episode.find(tag)
|
||||||
if existing is not None:
|
if existing is not None:
|
||||||
@@ -737,10 +759,7 @@ class NFOManager:
|
|||||||
dateadded_elem = ET.SubElement(episode, "dateadded")
|
dateadded_elem = ET.SubElement(episode, "dateadded")
|
||||||
dateadded_elem.text = dateadded
|
dateadded_elem.text = dateadded
|
||||||
|
|
||||||
# Add lockdata at the very end
|
# Note: lockdata element removed for Emby compatibility
|
||||||
if lock_metadata:
|
|
||||||
lockdata = ET.SubElement(episode, "lockdata")
|
|
||||||
lockdata.text = "true"
|
|
||||||
|
|
||||||
# Add NFOGuard comment at the bottom with other NFOGuard fields
|
# Add NFOGuard comment at the bottom with other NFOGuard fields
|
||||||
nfoguard_comment = ET.Comment(f" Created by {self.manager_brand} - Source: {source} ")
|
nfoguard_comment = ET.Comment(f" Created by {self.manager_brand} - Source: {source} ")
|
||||||
@@ -803,4 +822,56 @@ class NFOManager:
|
|||||||
print(f"✅ Updated {len(updated_files)} video file timestamps in {movie_dir.name}")
|
print(f"✅ Updated {len(updated_files)} video file timestamps in {movie_dir.name}")
|
||||||
else:
|
else:
|
||||||
print(f"⚠️ No video files found to update in {movie_dir.name}")
|
print(f"⚠️ No video files found to update in {movie_dir.name}")
|
||||||
|
|
||||||
|
def strip_lockdata_from_nfo(self, nfo_path: Path) -> bool:
|
||||||
|
"""Strip existing lockdata elements from NFO file for Emby compatibility"""
|
||||||
|
if not nfo_path.exists():
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
tree = ET.parse(nfo_path)
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
# Find and remove all lockdata elements
|
||||||
|
lockdata_elements = root.findall('.//lockdata')
|
||||||
|
if not lockdata_elements:
|
||||||
|
return False # No lockdata found, nothing to remove
|
||||||
|
|
||||||
|
removed_count = 0
|
||||||
|
for lockdata_elem in lockdata_elements:
|
||||||
|
# Find parent and remove the element
|
||||||
|
for parent in root.iter():
|
||||||
|
if lockdata_elem in parent:
|
||||||
|
parent.remove(lockdata_elem)
|
||||||
|
removed_count += 1
|
||||||
|
break
|
||||||
|
|
||||||
|
if removed_count > 0:
|
||||||
|
# Write back the modified NFO
|
||||||
|
ET.indent(tree, space=" ", level=0)
|
||||||
|
tree.write(nfo_path, encoding="utf-8", xml_declaration=True)
|
||||||
|
_log("INFO", f"Removed {removed_count} lockdata elements from {nfo_path.name}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
_log("ERROR", f"Error stripping lockdata from {nfo_path}: {e}")
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def strip_lockdata_from_directory(self, directory_path: Path) -> int:
|
||||||
|
"""Strip lockdata from all NFO files in a directory"""
|
||||||
|
if not directory_path.exists():
|
||||||
|
return 0
|
||||||
|
|
||||||
|
processed_count = 0
|
||||||
|
nfo_files = list(directory_path.glob("**/*.nfo"))
|
||||||
|
|
||||||
|
_log("INFO", f"Scanning {len(nfo_files)} NFO files for lockdata removal in {directory_path}")
|
||||||
|
|
||||||
|
for nfo_file in nfo_files:
|
||||||
|
if self.strip_lockdata_from_nfo(nfo_file):
|
||||||
|
processed_count += 1
|
||||||
|
|
||||||
|
_log("INFO", f"Stripped lockdata from {processed_count} NFO files in {directory_path}")
|
||||||
|
return processed_count
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user