================================================================================ CRUNCHYROLL DOWNLOADER - CHALLENGE 3 SOLUTION Chapter 4: Building Utilities Challenge: Error Handling ================================================================================ PROBLEM: Handle API errors, token expiration, network issues gracefully. SOLUTION: ================================================================================ File: crunchyroll_utils.py (error handling in CrunchyrollClient) class CrunchyrollClient: """Crunchyroll client with robust error handling.""" def __init__(self, config, token): self.config = config self.token = token self.base_url = config.api_base self.last_error = None def handle_error(self, status_code: int, response_text: str) -> bool: """Handle API errors with appropriate recovery.""" if status_code == 401: self.last_error = "Token expired or invalid" print("❌ Unauthorized - token needs refresh") return False elif status_code == 403: self.last_error = "No permission" print("❌ Forbidden - account doesn't have access") return False elif status_code == 404: self.last_error = "Endpoint not found" print("❌ Not found - API endpoint changed?") return False elif status_code == 429: self.last_error = "Rate limited" print("⚠️ Rate limited - wait before retrying") return False elif status_code >= 500: self.last_error = "Server error" print(f"⚠️ Server error ({status_code}) - temporary issue") return False else: self.last_error = f"Unknown error ({status_code})" return False def get_episodes_safe(self, max_retries: int = 3) -> list: """Fetch episodes with retry logic.""" for attempt in range(1, max_retries + 1): try: print(f"📡 Attempt {attempt}/{max_retries}") episodes = self.get_episodes() if episodes: return episodes if self.last_error == "Token expired or invalid": print("⚠️ Token expired, would need to re-login") return [] except Exception as e: print(f"⚠️ Error on attempt {attempt}: {e}") if attempt < max_retries: print(f" Retrying...") continue else: print(f" Max retries reached") return [] return [] ================================================================================