"""Manual integration test for NFO functionality. This script tests the complete NFO generation workflow with real TMDB API calls. It's intended for manual verification, not automated testing. Usage: 1. Set TMDB_API_KEY environment variable 2. Run: python scripts/test_nfo_integration.py 3. Check output in test_output/ directory Requirements: - Valid TMDB API key (get from https://www.themoviedb.org/settings/api) - Internet connection - Write permissions for test_output/ directory """ import asyncio import os import sys from pathlib import Path # Add src to path sys.path.insert(0, str(Path(__file__).parent.parent)) from src.core.services.tmdb_client import TMDBClient, TMDBAPIError from src.core.services.nfo_service import NFOService from src.core.entities.nfo_models import TVShowNFO from src.core.utils.nfo_generator import generate_tvshow_nfo, validate_nfo_xml async def test_tmdb_client(): """Test TMDB client basic functionality.""" print("\n=== Testing TMDB Client ===") api_key = os.getenv("TMDB_API_KEY") if not api_key: print("❌ TMDB_API_KEY environment variable not set") print(" Get your API key from: https://www.themoviedb.org/settings/api") return False try: async with TMDBClient(api_key=api_key) as client: # Test 1: Search for a show print("\n1. Searching for 'Attack on Titan'...") results = await client.search_tv_show("Attack on Titan") if results and results.get("results"): show = results["results"][0] print(f" ✅ Found: {show['name']} (ID: {show['id']})") show_id = show["id"] else: print(" ❌ No results found") return False # Test 2: Get show details print(f"\n2. Getting details for show ID {show_id}...") details = await client.get_tv_show_details( show_id, append_to_response="credits,external_ids,images" ) print(f" ✅ Title: {details['name']}") print(f" ✅ First Air Date: {details.get('first_air_date', 'N/A')}") print(f" ✅ Rating: {details.get('vote_average', 'N/A')}/10") # Test 3: Get external IDs if "external_ids" in details: ext_ids = details["external_ids"] print(f" ✅ IMDB ID: {ext_ids.get('imdb_id', 'N/A')}") print(f" ✅ TVDB ID: {ext_ids.get('tvdb_id', 'N/A')}") # Test 4: Get images if "images" in details: images = details["images"] print(f" ✅ Posters: {len(images.get('posters', []))}") print(f" ✅ Backdrops: {len(images.get('backdrops', []))}") print(f" ✅ Logos: {len(images.get('logos', []))}") # Test 5: Get image URL if details.get("poster_path"): url = client.get_image_url(details["poster_path"], "w500") print(f" ✅ Poster URL: {url[:60]}...") return True except TMDBAPIError as e: print(f" ❌ TMDB API Error: {e}") return False except Exception as e: print(f" ❌ Unexpected Error: {e}") import traceback traceback.print_exc() return False async def test_nfo_generation(): """Test NFO XML generation.""" print("\n=== Testing NFO Generation ===") try: # Create a sample NFO model print("\n1. Creating sample TVShowNFO model...") from src.core.entities.nfo_models import RatingInfo, ActorInfo, ImageInfo, UniqueID nfo = TVShowNFO( title="Test Show", originaltitle="Test Show Original", year=2020, plot="This is a test show for NFO generation validation.", runtime=45, premiered="2020-01-15", status="Continuing", genre=["Action", "Drama", "Animation"], studio=["Test Studio"], country=["Japan"], ratings=[RatingInfo( name="themoviedb", value=8.5, votes=1000, max_rating=10, default=True )], actors=[ ActorInfo(name="Test Actor 1", role="Main Character"), ActorInfo(name="Test Actor 2", role="Villain") ], thumb=[ImageInfo(url="https://image.tmdb.org/t/p/w500/poster.jpg")], fanart=[ImageInfo(url="https://image.tmdb.org/t/p/original/fanart.jpg")], uniqueid=[ UniqueID(type="tmdb", value="12345", default=False), UniqueID(type="tvdb", value="67890", default=True) ], tmdbid=12345, tvdbid=67890, imdbid="tt1234567" ) print(" ✅ TVShowNFO model created") # Test 2: Generate XML print("\n2. Generating XML...") xml_string = generate_tvshow_nfo(nfo) print(f" ✅ Generated {len(xml_string)} characters") # Test 3: Validate XML print("\n3. Validating XML...") validate_nfo_xml(xml_string) print(" ✅ XML is valid") # Test 4: Save to file output_dir = Path("test_output") output_dir.mkdir(exist_ok=True) nfo_path = output_dir / "test_tvshow.nfo" nfo_path.write_text(xml_string, encoding="utf-8") print(f" ✅ Saved to: {nfo_path}") # Test 5: Show sample print("\n4. Sample XML (first 500 chars):") print(" " + xml_string[:500].replace("\n", "\n ")) return True except Exception as e: print(f" ❌ Error: {e}") import traceback traceback.print_exc() return False async def test_nfo_service(): """Test complete NFO service workflow.""" print("\n=== Testing NFO Service ===") api_key = os.getenv("TMDB_API_KEY") if not api_key: print("❌ TMDB_API_KEY environment variable not set") return False try: # Create test output directory output_dir = Path("test_output") output_dir.mkdir(exist_ok=True) # Create a test series folder test_series = output_dir / "Attack_on_Titan" test_series.mkdir(exist_ok=True) print(f"\n1. Creating NFO for 'Attack on Titan'...") print(f" Output directory: {test_series}") # Initialize NFO service nfo_service = NFOService( tmdb_api_key=api_key, anime_directory=str(output_dir), image_size="w500" ) # Create NFO nfo_path = await nfo_service.create_tvshow_nfo( serie_name="Attack on Titan", serie_folder="Attack_on_Titan", year=2013, download_poster=True, download_logo=True, download_fanart=True ) print(f" ✅ NFO created: {nfo_path}") # Check if files were created print("\n2. Checking created files...") files_created = { "tvshow.nfo": (test_series / "tvshow.nfo").exists(), "poster.jpg": (test_series / "poster.jpg").exists(), "logo.png": (test_series / "logo.png").exists(), "fanart.jpg": (test_series / "fanart.jpg").exists(), } for filename, exists in files_created.items(): status = "✅" if exists else "❌" size = "" if exists: file_path = test_series / filename size = f" ({file_path.stat().st_size:,} bytes)" print(f" {status} {filename}{size}") # Read and validate NFO if files_created["tvshow.nfo"]: print("\n3. Validating generated NFO...") nfo_content = nfo_path.read_text(encoding="utf-8") validate_nfo_xml(nfo_content) print(" ✅ NFO is valid XML") # Show sample print("\n4. NFO Content (first 800 chars):") print(" " + nfo_content[:800].replace("\n", "\n ")) return all(files_created.values()) except Exception as e: print(f" ❌ Error: {e}") import traceback traceback.print_exc() return False async def main(): """Run all integration tests.""" print("=" * 70) print("NFO Functionality Integration Tests") print("=" * 70) print("\nNOTE: This requires a valid TMDB API key set as environment variable.") print("Get your API key from: https://www.themoviedb.org/settings/api") print("Set it with: export TMDB_API_KEY='your_api_key_here'") results = [] # Test 1: TMDB Client results.append(("TMDB Client", await test_tmdb_client())) # Test 2: NFO Generation results.append(("NFO Generation", await test_nfo_generation())) # Test 3: NFO Service (full workflow) results.append(("NFO Service", await test_nfo_service())) # Summary print("\n" + "=" * 70) print("SUMMARY") print("=" * 70) for test_name, passed in results: status = "✅ PASSED" if passed else "❌ FAILED" print(f"{test_name:.<50} {status}") all_passed = all(result for _, result in results) if all_passed: print("\n🎉 All tests passed!") print("\nGenerated files are in the 'test_output/' directory.") print("You can import tvshow.nfo into Kodi/Plex/Jellyfin to verify compatibility.") else: print("\n⚠️ Some tests failed. Check the output above for details.") return 1 return 0 if __name__ == "__main__": exit_code = asyncio.run(main()) sys.exit(exit_code)