dev #62

Merged
sbcrumb merged 56 commits from dev into main 2025-10-26 15:45:15 -04:00
Showing only changes of commit d1480e1b96 - Show all commits
+165 -25
View File
@@ -2579,6 +2579,9 @@ def register_routes(app, dependencies: dict):
print("🔍 Looking up dateadded values from database for missing items...") print("🔍 Looking up dateadded values from database for missing items...")
# Enhance episodes with database data # Enhance episodes with database data
episodes_with_dates = 0
episodes_missing_db = 0
for episode in missing_items["episodes"]: for episode in missing_items["episodes"]:
if episode["imdb_id"] != "unknown": if episode["imdb_id"] != "unknown":
try: try:
@@ -2595,12 +2598,47 @@ def register_routes(app, dependencies: dict):
if result: if result:
episode["dateadded"] = result["dateadded"] episode["dateadded"] = result["dateadded"]
episode["source"] = result.get("source", "database") episode["source"] = result.get("source", "database")
episodes_with_dates += 1
print(f"✅ Found database date for {episode['imdb_id']} S{episode['season']:02d}E{episode['episode']:02d}: {result['dateadded']}")
else: else:
print(f"⚠️ No database entry for {episode['imdb_id']} S{episode['season']:02d}E{episode['episode']:02d}") episodes_missing_db += 1
# Try to find other episodes from same series to estimate date
cursor.execute("""
SELECT dateadded, season, episode
FROM episodes
WHERE imdb_id = %s AND dateadded IS NOT NULL
ORDER BY season DESC, episode DESC
LIMIT 3
""", (episode["imdb_id"],))
similar_episodes = cursor.fetchall()
if similar_episodes:
latest_date = similar_episodes[0]["dateadded"]
episode["dateadded"] = latest_date
episode["source"] = f"estimated_from_series_latest"
print(f"🔮 Estimated date for {episode['imdb_id']} S{episode['season']:02d}E{episode['episode']:02d} from latest episode: {latest_date}")
else:
# Use NFO file modification time as fallback
try:
import os
from datetime import datetime
if os.path.exists(episode["nfo_path"]):
file_mtime = os.path.getmtime(episode["nfo_path"])
file_date = datetime.fromtimestamp(file_mtime)
episode["dateadded"] = file_date
episode["source"] = "nfo_file_mtime"
print(f"📅 Using NFO file date for {episode['imdb_id']} S{episode['season']:02d}E{episode['episode']:02d}: {file_date}")
else:
print(f"❌ No fallback date available for {episode['imdb_id']} S{episode['season']:02d}E{episode['episode']:02d}")
except Exception as fallback_error:
print(f"⚠️ Fallback date lookup failed for {episode['imdb_id']}: {fallback_error}")
except Exception as e: except Exception as e:
print(f"⚠️ Database lookup failed for episode {episode['imdb_id']}: {e}") print(f"⚠️ Database lookup failed for episode {episode['imdb_id']}: {e}")
# Enhance movies with database data # Enhance movies with database data
movies_with_dates = 0
movies_missing_db = 0
for movie in missing_items["movies"]: for movie in missing_items["movies"]:
if movie["imdb_id"] != "unknown": if movie["imdb_id"] != "unknown":
try: try:
@@ -2617,11 +2655,34 @@ def register_routes(app, dependencies: dict):
if result: if result:
movie["dateadded"] = result["dateadded"] movie["dateadded"] = result["dateadded"]
movie["source"] = result.get("source", "database") movie["source"] = result.get("source", "database")
movies_with_dates += 1
print(f"✅ Found database date for movie {movie['imdb_id']}: {result['dateadded']}")
else: else:
print(f"⚠️ No database entry for movie {movie['imdb_id']}") movies_missing_db += 1
# Use NFO file modification time as fallback for movies
try:
import os
from datetime import datetime
if os.path.exists(movie["nfo_path"]):
file_mtime = os.path.getmtime(movie["nfo_path"])
file_date = datetime.fromtimestamp(file_mtime)
movie["dateadded"] = file_date
movie["source"] = "nfo_file_mtime"
print(f"📅 Using NFO file date for movie {movie['imdb_id']}: {file_date}")
else:
print(f"❌ No fallback date available for movie {movie['imdb_id']}")
except Exception as fallback_error:
print(f"⚠️ Fallback date lookup failed for movie {movie['imdb_id']}: {fallback_error}")
except Exception as e: except Exception as e:
print(f"⚠️ Database lookup failed for movie {movie['imdb_id']}: {e}") print(f"⚠️ Database lookup failed for movie {movie['imdb_id']}: {e}")
# Print summary statistics
total_episodes = len(missing_items["episodes"])
total_movies = len(missing_items["movies"])
print(f"📊 Database lookup summary:")
print(f" Episodes: {episodes_with_dates}/{total_episodes} found in DB, {episodes_missing_db} missing from DB")
print(f" Movies: {movies_with_dates}/{total_movies} found in DB, {movies_missing_db} missing from DB")
total_missing = len(missing_items["episodes"]) + len(missing_items["movies"]) total_missing = len(missing_items["episodes"]) + len(missing_items["movies"])
print(f"✅ NFO repair scan complete: {total_missing} items missing dateadded elements") print(f"✅ NFO repair scan complete: {total_missing} items missing dateadded elements")
@@ -2707,18 +2768,52 @@ def register_routes(app, dependencies: dict):
# Write back to file # Write back to file
tree.write(nfo_path, encoding='utf-8', xml_declaration=True) tree.write(nfo_path, encoding='utf-8', xml_declaration=True)
fixed_count += 1 # VERIFY the write was successful by re-reading the file
results.append({ try:
"type": "episode", verify_tree = ET.parse(nfo_path)
"imdb_id": episode["imdb_id"], verify_root = verify_tree.getroot()
"season": episode["season"], verify_dateadded = verify_root.find("dateadded")
"episode": episode["episode"],
"nfo_path": nfo_path, if verify_dateadded is not None and verify_dateadded.text and verify_dateadded.text.strip():
"dateadded": nfo_dateadded, # Verification successful
"status": "fixed" fixed_count += 1
}) results.append({
"type": "episode",
print(f"✅ Fixed episode {episode['imdb_id']} S{episode['season']:02d}E{episode['episode']:02d}") "imdb_id": episode["imdb_id"],
"season": episode["season"],
"episode": episode["episode"],
"nfo_path": nfo_path,
"dateadded": nfo_dateadded,
"verified_dateadded": verify_dateadded.text.strip(),
"status": "fixed_and_verified"
})
print(f"✅ Fixed and verified episode {episode['imdb_id']} S{episode['season']:02d}E{episode['episode']:02d}")
else:
# Verification failed - dateadded missing after write
failed_count += 1
results.append({
"type": "episode",
"imdb_id": episode["imdb_id"],
"season": episode["season"],
"episode": episode["episode"],
"nfo_path": nfo_path,
"dateadded": nfo_dateadded,
"status": "write_failed_verification"
})
print(f"❌ Write verification FAILED for episode {episode['imdb_id']} S{episode['season']:02d}E{episode['episode']:02d} - dateadded not found after write")
except Exception as verify_error:
# Verification failed due to parse error
failed_count += 1
results.append({
"type": "episode",
"imdb_id": episode["imdb_id"],
"season": episode["season"],
"episode": episode["episode"],
"nfo_path": nfo_path,
"status": "verification_parse_error",
"error": str(verify_error)
})
print(f"❌ Verification parse error for episode {episode['imdb_id']} S{episode['season']:02d}E{episode['episode']:02d}: {verify_error}")
else: else:
failed_count += 1 failed_count += 1
print(f"❌ NFO file not found: {nfo_path}") print(f"❌ NFO file not found: {nfo_path}")
@@ -2759,17 +2854,49 @@ def register_routes(app, dependencies: dict):
# Write back to file # Write back to file
tree.write(nfo_path, encoding='utf-8', xml_declaration=True) tree.write(nfo_path, encoding='utf-8', xml_declaration=True)
fixed_count += 1 # VERIFY the write was successful by re-reading the file
results.append({ try:
"type": "movie", verify_tree = ET.parse(nfo_path)
"imdb_id": movie["imdb_id"], verify_root = verify_tree.getroot()
"title": movie["title"], verify_dateadded = verify_root.find("dateadded")
"nfo_path": nfo_path,
"dateadded": nfo_dateadded, if verify_dateadded is not None and verify_dateadded.text and verify_dateadded.text.strip():
"status": "fixed" # Verification successful
}) fixed_count += 1
results.append({
print(f"✅ Fixed movie {movie['imdb_id']} ({movie['title']})") "type": "movie",
"imdb_id": movie["imdb_id"],
"title": movie["title"],
"nfo_path": nfo_path,
"dateadded": nfo_dateadded,
"verified_dateadded": verify_dateadded.text.strip(),
"status": "fixed_and_verified"
})
print(f"✅ Fixed and verified movie {movie['imdb_id']} ({movie['title']})")
else:
# Verification failed - dateadded missing after write
failed_count += 1
results.append({
"type": "movie",
"imdb_id": movie["imdb_id"],
"title": movie["title"],
"nfo_path": nfo_path,
"dateadded": nfo_dateadded,
"status": "write_failed_verification"
})
print(f"❌ Write verification FAILED for movie {movie['imdb_id']} ({movie['title']}) - dateadded not found after write")
except Exception as verify_error:
# Verification failed due to parse error
failed_count += 1
results.append({
"type": "movie",
"imdb_id": movie["imdb_id"],
"title": movie["title"],
"nfo_path": nfo_path,
"status": "verification_parse_error",
"error": str(verify_error)
})
print(f"❌ Verification parse error for movie {movie['imdb_id']} ({movie['title']}): {verify_error}")
else: else:
failed_count += 1 failed_count += 1
print(f"❌ NFO file not found: {nfo_path}") print(f"❌ NFO file not found: {nfo_path}")
@@ -2780,11 +2907,24 @@ def register_routes(app, dependencies: dict):
print(f"✅ NFO repair fix complete: {fixed_count} fixed, {failed_count} failed") print(f"✅ NFO repair fix complete: {fixed_count} fixed, {failed_count} failed")
# Final summary with detailed statistics
verification_summary = {
"fixed_and_verified": sum(1 for r in results if r.get("status") == "fixed_and_verified"),
"write_failed_verification": sum(1 for r in results if r.get("status") == "write_failed_verification"),
"verification_parse_error": sum(1 for r in results if r.get("status") == "verification_parse_error")
}
print(f"📊 Final summary: {fixed_count} fixed, {failed_count} failed")
print(f" ✅ Verified successful: {verification_summary['fixed_and_verified']}")
print(f" ❌ Write verification failed: {verification_summary['write_failed_verification']}")
print(f" ⚠️ Verification parse errors: {verification_summary['verification_parse_error']}")
return { return {
"status": "success", "status": "success",
"total_processed": total_episodes + total_movies, "total_processed": total_episodes + total_movies,
"fixed_count": fixed_count, "fixed_count": fixed_count,
"failed_count": failed_count, "failed_count": failed_count,
"verification_summary": verification_summary,
"results": results[:20] # Show first 20 for UI "results": results[:20] # Show first 20 for UI
} }