fix: Address critical issues from PR review
Fix 4 critical issues identified in code review:
**Error Handling Improvements:**
- Replace bare except blocks with specific exception handlers
- Add logging for TimeoutException and ConnectError
- Prevent silent failures in season loading
- Remove misleading "0 episodes" on error
**Robustness Fixes:**
- Add safe None handling in title comparison (main.py)
Prevents crash when title is None
- Add URL validation before encodeURIComponent (anime.js)
Prevents crash when anime.url is undefined
- Fix unreachable code in retry logic (recommendations.py)
Preserve retry context in exception messages
**Changes:**
- animesama.py: Specific exception handling with print statements
- main.py: Safe None handling with (x.get('title') or '')
- anime.js: URL validation before encoding
- recommendations.py: Better exception messages with retry context
All fixes tested and working correctly.
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -943,8 +943,13 @@ class AnimeSamaDownloader(BaseAnimeSite):
|
|||||||
'url': season_url,
|
'url': season_url,
|
||||||
'episode_count': None # Will fetch later if needed
|
'episode_count': None # Will fetch later if needed
|
||||||
}
|
}
|
||||||
except Exception:
|
except httpx.TimeoutException:
|
||||||
|
# Silent skip - season likely doesn't exist
|
||||||
pass
|
pass
|
||||||
|
except httpx.ConnectError as e:
|
||||||
|
print(f"[ANIME-SAMA] Connection error checking season {season_num}: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ANIME-SAMA] Unexpected error checking season {season_num}: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Check seasons 1-10 in parallel
|
# Check seasons 1-10 in parallel
|
||||||
@@ -970,7 +975,10 @@ class AnimeSamaDownloader(BaseAnimeSite):
|
|||||||
# Skip seasons with no episodes
|
# Skip seasons with no episodes
|
||||||
print(f"[ANIME-SAMA] Skipping Saison {season_info['season']} (no episodes)")
|
print(f"[ANIME-SAMA] Skipping Saison {season_info['season']} (no episodes)")
|
||||||
return None
|
return None
|
||||||
except Exception:
|
except httpx.TimeoutException:
|
||||||
|
print(f"[ANIME-SAMA] Timeout fetching episodes for season {season_info['season']}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ANIME-SAMA] Error fetching episodes for season {season_info['season']}: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if seasons:
|
if seasons:
|
||||||
@@ -999,19 +1007,20 @@ class AnimeSamaDownloader(BaseAnimeSite):
|
|||||||
# Get episode count for this season
|
# Get episode count for this season
|
||||||
try:
|
try:
|
||||||
episodes = await self.get_episodes(season_url)
|
episodes = await self.get_episodes(season_url)
|
||||||
|
episode_count = len(episodes) if episodes else 0
|
||||||
|
if episode_count > 0:
|
||||||
seasons.append({
|
seasons.append({
|
||||||
'season': season_num,
|
'season': season_num,
|
||||||
'title': f'Saison {season_num}',
|
'title': f'Saison {season_num}',
|
||||||
'url': season_url,
|
'url': season_url,
|
||||||
'episode_count': len(episodes) if episodes else 0
|
'episode_count': episode_count
|
||||||
})
|
|
||||||
except Exception:
|
|
||||||
seasons.append({
|
|
||||||
'season': season_num,
|
|
||||||
'title': f'Saison {season_num}',
|
|
||||||
'url': season_url,
|
|
||||||
'episode_count': 0
|
|
||||||
})
|
})
|
||||||
|
else:
|
||||||
|
print(f"[ANIME-SAMA] Skipping season {season_num} (no episodes)")
|
||||||
|
except httpx.TimeoutException:
|
||||||
|
print(f"[ANIME-SAMA] Timeout fetching episodes for season {season_num}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ANIME-SAMA] Error fetching episodes for season {season_num}: {e}")
|
||||||
|
|
||||||
# Sort by season number
|
# Sort by season number
|
||||||
seasons.sort(key=lambda x: x['season'])
|
seasons.sort(key=lambda x: x['season'])
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ class AnimeReleasesFetcher:
|
|||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
logger.error("Jikan API rate limit exceeded after all retries")
|
logger.error("Jikan API rate limit exceeded after all retries")
|
||||||
|
raise Exception(f"Jikan API rate limit exceeded after {max_retries} retries")
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@@ -55,10 +56,11 @@ class AnimeReleasesFetcher:
|
|||||||
logger.warning(f"Request timeout, retrying in {delay}s... (attempt {attempt + 1}/{max_retries})")
|
logger.warning(f"Request timeout, retrying in {delay}s... (attempt {attempt + 1}/{max_retries})")
|
||||||
await asyncio.sleep(delay)
|
await asyncio.sleep(delay)
|
||||||
else:
|
else:
|
||||||
|
raise Exception(f"Request timeout after {max_retries} retries") from e
|
||||||
|
except Exception as e:
|
||||||
|
# For any other exception, don't retry
|
||||||
raise
|
raise
|
||||||
|
|
||||||
raise Exception("Max retries exceeded for Jikan API request")
|
|
||||||
|
|
||||||
async def _get_cached(self, key: str, fetcher):
|
async def _get_cached(self, key: str, fetcher):
|
||||||
"""Get cached result or fetch new data"""
|
"""Get cached result or fetch new data"""
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
|
|||||||
@@ -524,7 +524,7 @@ async def search_anime_unified(q: str, lang: str = "vostfr", include_metadata: b
|
|||||||
for provider_id in results:
|
for provider_id in results:
|
||||||
results[provider_id].sort(key=lambda x: (
|
results[provider_id].sort(key=lambda x: (
|
||||||
-x.get('_relevance_boost', 0), # Exact matches first
|
-x.get('_relevance_boost', 0), # Exact matches first
|
||||||
x.get('title', '').lower().find(q.lower()) # Then by position of match
|
(x.get('title') or '').lower().find(q.lower()) # Then by position of match
|
||||||
))
|
))
|
||||||
# Remove temporary boost field
|
# Remove temporary boost field
|
||||||
for item in results[provider_id]:
|
for item in results[provider_id]:
|
||||||
|
|||||||
@@ -38,7 +38,9 @@ async function displaySearchResults(data, lang) {
|
|||||||
// Stagger requests: 500ms delay between each anime
|
// Stagger requests: 500ms delay between each anime
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// Try to load seasons first (for Anime-Sama)
|
// Try to load seasons first (for Anime-Sama)
|
||||||
|
if (anime.url) {
|
||||||
loadSeasonsForAnime(providerId, encodeURIComponent(anime.url));
|
loadSeasonsForAnime(providerId, encodeURIComponent(anime.url));
|
||||||
|
}
|
||||||
}, 500 * index);
|
}, 500 * index);
|
||||||
delayCounter++;
|
delayCounter++;
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user