diff --git a/docs/task3_status.md b/docs/task3_status.md index a45cf6b..66bb73f 100644 --- a/docs/task3_status.md +++ b/docs/task3_status.md @@ -149,23 +149,16 @@ The unit tests were written based on assumptions about the API that don't match 2. **Unit Test Refactoring** (2-3 hours, optional) - - Update test_image_downloader.py with dependency injection - - Fix test_nfo_generator.py validation tests - - Update test_tmdb_client.py mocking strategy - - Add test_nfo_service.py with comprehensive tests + - ✅ NFO XML parsing tests added (4 tests passing) + - ⚠️ TMDBClient tests need refactoring (async mocking challenges) + - ⚠️ ImageDownloader tests need dependency injection - Alternative: Replace with more integration tests -3. **NFOService.update_tvshow_nfo()** (1 hour, optional) - - - Currently raises NotImplementedError - - Parse existing NFO to extract TMDB ID - - Refetch from TMDB and regenerate - - Update media files - -4. **Error Recovery** (1 hour, optional) +3. **Enhanced Error Recovery** (1 hour, optional) - Graceful handling if TMDB API fails during scan - - Don't block scan if NFO creation fails + - Retry queue for failed NFO creations - Enhanced logging for debugging + - Background job for bulk operations ### Future API Integration (Separate Tasks) @@ -176,11 +169,13 @@ The unit tests were written based on assumptions about the API that don't match ## 🐛 Known Issues / Future Enhancements -1. **NFOService.update_tvshow_nfo()** - Not implemented (optional) +1. **NFOService.update_tvshow_nfo()** - ✅ **IMPLEMENTED** - - Currently raises `NotImplementedError` - - Would need to parse existing NFO to extract TMDB ID - - Then refetch and regenerate + - Parses existing NFO to extract TMDB ID from uniqueid or tmdbid elements + - Fetches fresh metadata from TMDB API + - Regenerates NFO with updated data + - Optionally re-downloads media files + - Comprehensive error handling for edge cases 2. **Unit Tests** - Need refactoring (optional) @@ -263,9 +258,9 @@ Task 3 is **95% Complete** and **Production Ready**. **Optional Future Work (Not blocking):** -- Unit test refactoring (mocking strategy needs redesign) -- update_tvshow_nfo() implementation -- Advanced error recovery features +- Unit test refactoring (mocking strategy needs redesign for async code) +- ~~update_tvshow_nfo() implementation~~ ✅ **DONE** +- Advanced error recovery features (retry queue, background jobs) ## ⏱️ Time Investment Summary diff --git a/src/cli/nfo_cli.py b/src/cli/nfo_cli.py index 951cc54..795885d 100644 --- a/src/cli/nfo_cli.py +++ b/src/cli/nfo_cli.py @@ -165,17 +165,102 @@ async def check_nfo_status(): return 0 +async def update_nfo_files(): + """Update existing NFO files with fresh data from TMDB.""" + print("=" * 70) + print("NFO Update Tool") + print("=" * 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") + return 1 + + if not settings.anime_directory: + print("\n❌ 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}") + + # Get series with NFO + from src.core.entities.SerieList import SerieList + serie_list = SerieList(settings.anime_directory) + all_series = serie_list.get_all() + 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") + 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)") + + # Initialize NFO service + from src.core.services.nfo_service import NFOService + nfo_service = NFOService( + tmdb_api_key=settings.tmdb_api_key, + anime_directory=settings.anime_directory, + image_size=settings.nfo_image_size + ) + + 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}") + + 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_fanart + ) + ) + print(f" ✅ Updated successfully") + success_count += 1 + + # Small delay to respect API rate limits + await asyncio.sleep(0.5) + + except Exception as e: + print(f" ❌ Error: {e}") + 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() + return 1 + finally: + await nfo_service.close() + + return 0 + + def main(): """Main CLI entry point.""" if len(sys.argv) < 2: print("NFO Management Tool") print("\nUsage:") - print(" python -m src.cli.nfo_cli scan # Scan and create/update NFO files") + 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") + print(" Set NFO_UPDATE_ON_SCAN=true to update existing NFOs during scan") return 1 command = sys.argv[1].lower() @@ -184,9 +269,11 @@ def main(): return asyncio.run(scan_and_create_nfo()) elif command == "status": return asyncio.run(check_nfo_status()) + elif command == "update": + return asyncio.run(update_nfo_files()) else: print(f"Unknown command: {command}") - print("Use 'scan' or 'status'") + print("Use 'scan', 'status', or 'update'") return 1