chore: apply pending code updates
This commit is contained in:
@@ -5,6 +5,7 @@ and checking NFO metadata files.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
@@ -14,48 +15,50 @@ sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
||||
from src.config.settings import settings
|
||||
from src.core.services.series_manager_service import SeriesManagerService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def scan_and_create_nfo():
|
||||
"""Scan all series and create missing NFO files."""
|
||||
print("=" * 70)
|
||||
print("NFO Auto-Creation Tool")
|
||||
print("=" * 70)
|
||||
|
||||
logger.info("%s", "=" * 70)
|
||||
logger.info("NFO Auto-Creation Tool")
|
||||
logger.info("%s", "=" * 70)
|
||||
|
||||
if not settings.tmdb_api_key:
|
||||
print("\n❌ Error: TMDB_API_KEY not configured")
|
||||
print(" Set TMDB_API_KEY in .env file or environment")
|
||||
print(" Get API key from: https://www.themoviedb.org/settings/api")
|
||||
logger.error("TMDB_API_KEY not configured")
|
||||
logger.error("Set TMDB_API_KEY in .env file or environment")
|
||||
logger.error("Get API key from: https://www.themoviedb.org/settings/api")
|
||||
return 1
|
||||
|
||||
if not settings.anime_directory:
|
||||
print("\n❌ Error: ANIME_DIRECTORY not configured")
|
||||
logger.error("ANIME_DIRECTORY not configured")
|
||||
return 1
|
||||
|
||||
print(f"\nAnime Directory: {settings.anime_directory}")
|
||||
print(f"Auto-create NFO: {settings.nfo_auto_create}")
|
||||
print(f"Update on scan: {settings.nfo_update_on_scan}")
|
||||
print(f"Download poster: {settings.nfo_download_poster}")
|
||||
print(f"Download logo: {settings.nfo_download_logo}")
|
||||
print(f"Download fanart: {settings.nfo_download_fanart}")
|
||||
|
||||
|
||||
logger.info("Anime Directory: %s", settings.anime_directory)
|
||||
logger.info("Auto-create NFO: %s", settings.nfo_auto_create)
|
||||
logger.info("Update on scan: %s", settings.nfo_update_on_scan)
|
||||
logger.info("Download poster: %s", settings.nfo_download_poster)
|
||||
logger.info("Download logo: %s", settings.nfo_download_logo)
|
||||
logger.info("Download fanart: %s", settings.nfo_download_fanart)
|
||||
|
||||
if not settings.nfo_auto_create:
|
||||
print("\n⚠️ Warning: NFO_AUTO_CREATE is set to False")
|
||||
print(" Enable it in .env to auto-create NFO files")
|
||||
print("\n Continuing anyway to demonstrate functionality...")
|
||||
logger.warning("NFO_AUTO_CREATE is set to False")
|
||||
logger.warning("Enable it in .env to auto-create NFO files")
|
||||
logger.info("Continuing anyway to demonstrate functionality...")
|
||||
# Override for demonstration
|
||||
settings.nfo_auto_create = True
|
||||
|
||||
print("\nInitializing series manager...")
|
||||
logger.info("Initializing series manager...")
|
||||
manager = SeriesManagerService.from_settings()
|
||||
|
||||
|
||||
# Get series list first
|
||||
serie_list = manager.get_serie_list()
|
||||
all_series = serie_list.get_all()
|
||||
|
||||
print(f"Found {len(all_series)} series in directory")
|
||||
|
||||
|
||||
logger.info("Found %d series in directory", len(all_series))
|
||||
|
||||
if not all_series:
|
||||
print("\n⚠️ No series found. Add some anime series first.")
|
||||
logger.warning("No series found. Add some anime series first.")
|
||||
return 0
|
||||
|
||||
# Show series without NFO
|
||||
@@ -65,25 +68,25 @@ async def scan_and_create_nfo():
|
||||
series_without_nfo.append(serie)
|
||||
|
||||
if series_without_nfo:
|
||||
print(f"\nSeries without NFO: {len(series_without_nfo)}")
|
||||
logger.info("Series without NFO: %d", len(series_without_nfo))
|
||||
for serie in series_without_nfo[:5]: # Show first 5
|
||||
print(f" - {serie.name} ({serie.folder})")
|
||||
logger.debug("Missing NFO: %s (%s)", serie.name, serie.folder)
|
||||
if len(series_without_nfo) > 5:
|
||||
print(f" ... and {len(series_without_nfo) - 5} more")
|
||||
logger.info("... and %d more", len(series_without_nfo) - 5)
|
||||
else:
|
||||
print("\n✅ All series already have NFO files!")
|
||||
|
||||
logger.info("All series already have NFO files")
|
||||
|
||||
if not settings.nfo_update_on_scan:
|
||||
print("\nNothing to do. Enable NFO_UPDATE_ON_SCAN to update existing NFOs.")
|
||||
logger.info("Nothing to do. Enable NFO_UPDATE_ON_SCAN to update existing NFOs.")
|
||||
return 0
|
||||
|
||||
print("\nProcessing NFO files...")
|
||||
print("(This may take a while depending on the number of series)")
|
||||
|
||||
logger.info("Processing NFO files...")
|
||||
logger.info("This may take a while depending on the number of series")
|
||||
|
||||
try:
|
||||
await manager.scan_and_process_nfo()
|
||||
print("\n✅ NFO processing complete!")
|
||||
|
||||
logger.info("NFO processing complete")
|
||||
|
||||
# Show updated stats
|
||||
serie_list.load_series() # Reload to get updated stats
|
||||
all_series = serie_list.get_all()
|
||||
@@ -91,17 +94,17 @@ async def scan_and_create_nfo():
|
||||
series_with_poster = [s for s in all_series if s.has_poster()]
|
||||
series_with_logo = [s for s in all_series if s.has_logo()]
|
||||
series_with_fanart = [s for s in all_series if s.has_fanart()]
|
||||
|
||||
print("\nFinal Statistics:")
|
||||
print(f" Series with NFO: {len(series_with_nfo)}/{len(all_series)}")
|
||||
print(f" Series with poster: {len(series_with_poster)}/{len(all_series)}")
|
||||
print(f" Series with logo: {len(series_with_logo)}/{len(all_series)}")
|
||||
print(f" Series with fanart: {len(series_with_fanart)}/{len(all_series)}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ Error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
logger.info("Final statistics", extra={
|
||||
"total_series": len(all_series),
|
||||
"with_nfo": len(series_with_nfo),
|
||||
"with_poster": len(series_with_poster),
|
||||
"with_logo": len(series_with_logo),
|
||||
"with_fanart": len(series_with_fanart),
|
||||
})
|
||||
|
||||
except Exception:
|
||||
logger.exception("Failed to process NFO files")
|
||||
return 1
|
||||
finally:
|
||||
await manager.close()
|
||||
@@ -111,78 +114,92 @@ async def scan_and_create_nfo():
|
||||
|
||||
async def check_nfo_status():
|
||||
"""Check NFO status for all series."""
|
||||
print("=" * 70)
|
||||
print("NFO Status Check")
|
||||
print("=" * 70)
|
||||
|
||||
logger.info("%s", "=" * 70)
|
||||
logger.info("NFO Status Check")
|
||||
logger.info("%s", "=" * 70)
|
||||
|
||||
if not settings.anime_directory:
|
||||
print("\n❌ Error: ANIME_DIRECTORY not configured")
|
||||
logger.error("ANIME_DIRECTORY not configured")
|
||||
return 1
|
||||
|
||||
print(f"\nAnime Directory: {settings.anime_directory}")
|
||||
|
||||
|
||||
logger.info("Anime Directory: %s", settings.anime_directory)
|
||||
|
||||
# Create series list (no NFO service needed for status check)
|
||||
from src.core.entities.SerieList import SerieList
|
||||
serie_list = SerieList(settings.anime_directory)
|
||||
all_series = serie_list.get_all()
|
||||
|
||||
|
||||
if not all_series:
|
||||
print("\n⚠️ No series found")
|
||||
logger.warning("No series found")
|
||||
return 0
|
||||
|
||||
print(f"\nTotal series: {len(all_series)}")
|
||||
|
||||
|
||||
logger.info("Total series: %d", len(all_series))
|
||||
|
||||
# Categorize series
|
||||
with_nfo = []
|
||||
without_nfo = []
|
||||
|
||||
|
||||
for serie in all_series:
|
||||
if serie.has_nfo():
|
||||
with_nfo.append(serie)
|
||||
else:
|
||||
without_nfo.append(serie)
|
||||
|
||||
print(f"\nWith NFO: {len(with_nfo)} ({len(with_nfo) * 100 // len(all_series)}%)")
|
||||
print(f"Without NFO: {len(without_nfo)} ({len(without_nfo) * 100 // len(all_series)}%)")
|
||||
|
||||
|
||||
logger.info(
|
||||
"Series NFO coverage",
|
||||
extra={
|
||||
"with_nfo": len(with_nfo),
|
||||
"without_nfo": len(without_nfo),
|
||||
"total": len(all_series),
|
||||
},
|
||||
)
|
||||
|
||||
if without_nfo:
|
||||
print("\nSeries missing NFO:")
|
||||
logger.info("Series missing NFO: %d", len(without_nfo))
|
||||
for serie in without_nfo[:10]:
|
||||
print(f" ❌ {serie.name} ({serie.folder})")
|
||||
logger.debug("Missing NFO: %s (%s)", serie.name, serie.folder)
|
||||
if len(without_nfo) > 10:
|
||||
print(f" ... and {len(without_nfo) - 10} more")
|
||||
|
||||
logger.info("... and %d more", len(without_nfo) - 10)
|
||||
|
||||
# Media file statistics
|
||||
with_poster = sum(1 for s in all_series if s.has_poster())
|
||||
with_logo = sum(1 for s in all_series if s.has_logo())
|
||||
with_fanart = sum(1 for s in all_series if s.has_fanart())
|
||||
|
||||
print("\nMedia Files:")
|
||||
print(f" Posters: {with_poster}/{len(all_series)} ({with_poster * 100 // len(all_series)}%)")
|
||||
print(f" Logos: {with_logo}/{len(all_series)} ({with_logo * 100 // len(all_series)}%)")
|
||||
print(f" Fanart: {with_fanart}/{len(all_series)} ({with_fanart * 100 // len(all_series)}%)")
|
||||
|
||||
|
||||
logger.info(
|
||||
"Media file coverage",
|
||||
extra={
|
||||
"posters": with_poster,
|
||||
"logos": with_logo,
|
||||
"fanart": with_fanart,
|
||||
"total": len(all_series),
|
||||
},
|
||||
)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
async def update_nfo_files():
|
||||
"""Update existing NFO files with fresh data from TMDB."""
|
||||
print("=" * 70)
|
||||
print("NFO Update Tool")
|
||||
print("=" * 70)
|
||||
|
||||
logger.info("%s", "=" * 70)
|
||||
logger.info("NFO Update Tool")
|
||||
logger.info("%s", "=" * 70)
|
||||
|
||||
if not settings.tmdb_api_key:
|
||||
print("\n❌ Error: TMDB_API_KEY not configured")
|
||||
print(" Set TMDB_API_KEY in .env file or environment")
|
||||
print(" Get API key from: https://www.themoviedb.org/settings/api")
|
||||
logger.error("TMDB_API_KEY not configured")
|
||||
logger.error("Set TMDB_API_KEY in .env file or environment")
|
||||
logger.error("Get API key from: https://www.themoviedb.org/settings/api")
|
||||
return 1
|
||||
|
||||
|
||||
if not settings.anime_directory:
|
||||
print("\n❌ Error: ANIME_DIRECTORY not configured")
|
||||
logger.error("ANIME_DIRECTORY not configured")
|
||||
return 1
|
||||
|
||||
print(f"\nAnime Directory: {settings.anime_directory}")
|
||||
print(f"Download media: {settings.nfo_download_poster or settings.nfo_download_logo or settings.nfo_download_fanart}")
|
||||
|
||||
logger.info("Anime Directory: %s", settings.anime_directory)
|
||||
logger.info(
|
||||
"Download media: %s",
|
||||
settings.nfo_download_poster or settings.nfo_download_logo or settings.nfo_download_fanart,
|
||||
)
|
||||
|
||||
# Get series with NFO
|
||||
from src.core.entities.SerieList import SerieList
|
||||
@@ -191,57 +208,55 @@ async def update_nfo_files():
|
||||
series_with_nfo = [s for s in all_series if s.has_nfo()]
|
||||
|
||||
if not series_with_nfo:
|
||||
print("\n⚠️ No series with NFO files found")
|
||||
print(" Run 'scan' command first to create NFO files")
|
||||
logger.warning("No series with NFO files found")
|
||||
logger.info("Run 'scan' command first to create NFO files")
|
||||
return 0
|
||||
|
||||
print(f"\nFound {len(series_with_nfo)} series with NFO files")
|
||||
print("Updating NFO files with fresh data from TMDB...")
|
||||
print("(This may take a while)")
|
||||
|
||||
|
||||
logger.info("Found %d series with NFO files", len(series_with_nfo))
|
||||
logger.info("Updating NFO files with fresh data from TMDB...")
|
||||
logger.info("This may take a while")
|
||||
|
||||
# Initialize NFO service using factory
|
||||
from src.core.services.nfo_factory import create_nfo_service
|
||||
try:
|
||||
nfo_service = create_nfo_service()
|
||||
except ValueError as e:
|
||||
print(f"\nError: {e}")
|
||||
logger.error("Error creating NFO service: %s", e)
|
||||
return 1
|
||||
|
||||
|
||||
success_count = 0
|
||||
error_count = 0
|
||||
|
||||
|
||||
try:
|
||||
for i, serie in enumerate(series_with_nfo, 1):
|
||||
print(f"\n[{i}/{len(series_with_nfo)}] Updating: {serie.name}")
|
||||
|
||||
logger.info("[%d/%d] Updating: %s", i, len(series_with_nfo), serie.name)
|
||||
|
||||
try:
|
||||
await nfo_service.update_tvshow_nfo(
|
||||
serie_folder=serie.folder,
|
||||
download_media=(
|
||||
settings.nfo_download_poster or
|
||||
settings.nfo_download_logo or
|
||||
settings.nfo_download_poster or
|
||||
settings.nfo_download_logo or
|
||||
settings.nfo_download_fanart
|
||||
)
|
||||
),
|
||||
)
|
||||
print(f" ✅ Updated successfully")
|
||||
logger.info("Updated successfully: %s", serie.name)
|
||||
success_count += 1
|
||||
|
||||
|
||||
# Small delay to respect API rate limits
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(f" ❌ Error: {e}")
|
||||
logger.exception("Failed to update NFO for %s", serie.name)
|
||||
error_count += 1
|
||||
|
||||
print("\n" + "=" * 70)
|
||||
print(f"✅ Update complete!")
|
||||
print(f" Success: {success_count}")
|
||||
print(f" Errors: {error_count}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ Fatal error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
logger.info("%s", "=" * 70)
|
||||
logger.info("Update complete")
|
||||
logger.info("Success: %d", success_count)
|
||||
logger.info("Errors: %d", error_count)
|
||||
|
||||
except Exception:
|
||||
logger.exception("Fatal error during NFO update")
|
||||
return 1
|
||||
finally:
|
||||
await nfo_service.close()
|
||||
@@ -251,20 +266,22 @@ async def update_nfo_files():
|
||||
|
||||
def main():
|
||||
"""Main CLI entry point."""
|
||||
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("NFO Management Tool")
|
||||
print("\nUsage:")
|
||||
print(" python -m src.cli.nfo_cli scan # Scan and create missing NFO files")
|
||||
print(" python -m src.cli.nfo_cli status # Check NFO status for all series")
|
||||
print(" python -m src.cli.nfo_cli update # Update existing NFO files with fresh data")
|
||||
print("\nConfiguration:")
|
||||
print(" Set TMDB_API_KEY in .env file")
|
||||
print(" Set NFO_AUTO_CREATE=true to enable auto-creation")
|
||||
print(" Set NFO_UPDATE_ON_SCAN=true to update existing NFOs during scan")
|
||||
logger.info("NFO Management Tool")
|
||||
logger.info("\nUsage:")
|
||||
logger.info(" python -m src.cli.nfo_cli scan # Scan and create missing NFO files")
|
||||
logger.info(" python -m src.cli.nfo_cli status # Check NFO status for all series")
|
||||
logger.info(" python -m src.cli.nfo_cli update # Update existing NFO files with fresh data")
|
||||
logger.info("\nConfiguration:")
|
||||
logger.info(" Set TMDB_API_KEY in .env file")
|
||||
logger.info(" Set NFO_AUTO_CREATE=true to enable auto-creation")
|
||||
logger.info(" Set NFO_UPDATE_ON_SCAN=true to update existing NFOs during scan")
|
||||
return 1
|
||||
|
||||
|
||||
command = sys.argv[1].lower()
|
||||
|
||||
|
||||
if command == "scan":
|
||||
return asyncio.run(scan_and_create_nfo())
|
||||
elif command == "status":
|
||||
@@ -272,8 +289,8 @@ def main():
|
||||
elif command == "update":
|
||||
return asyncio.run(update_nfo_files())
|
||||
else:
|
||||
print(f"Unknown command: {command}")
|
||||
print("Use 'scan', 'status', or 'update'")
|
||||
logger.error("Unknown command: %s", command)
|
||||
logger.info("Use 'scan', 'status', or 'update'")
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user