feat: Add anime metadata extraction and fix episode selection bug

Features:
- Added rich metadata extraction for all anime providers (Anime-Sama, Neko-Sama, Anime-Ultime, Vostfree)
- New AnimeMetadata model with synopsis, genres, rating, release year, studio, poster/banner images, episode count, and status
- New /api/anime/metadata endpoint for fetching metadata of specific anime
- Enhanced /api/anime/search endpoint with optional include_metadata parameter
- Updated web interface with metadata display (expandable synopsis, genres, rating, year)
- Added metadata toggle checkbox in search UI (disabled by default for performance)

Bug Fixes:
- Fixed episode selection bug where select would reset to default after any change
- Removed onchange event from select element that was causing unwanted reloads
- Fixed download button disappearing after episode download
- Episodes can now be downloaded multiple times without page refresh

Enhancements:
- Metadata displayed with icons (📅 year,  rating, 🏷️ genres, 📺 episodes, 📡 status)
- Expandable synopsis section for detailed descriptions
- Better visual organization of anime information
- Maintains backward compatibility (metadata is optional)

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:
root
2026-01-23 09:36:59 +00:00
parent 40977438ff
commit 20cad0b4fe
7 changed files with 693 additions and 29 deletions
+23
View File
@@ -40,3 +40,26 @@ class DownloadTask(BaseModel):
class DownloadRequest(BaseModel):
url: str
filename: Optional[str] = None
class AnimeMetadata(BaseModel):
"""Metadata for anime series"""
synopsis: Optional[str] = None
genres: list[str] = []
rating: Optional[str] = None # Could be "PG-13", "R", etc., or numeric like "8.5/10"
release_year: Optional[int] = None
studio: Optional[str] = None
poster_image: Optional[str] = None
banner_image: Optional[str] = None
total_episodes: Optional[int] = None
status: Optional[str] = None # "Ongoing", "Completed", etc.
alternative_titles: list[str] = []
class AnimeSearchResult(BaseModel):
"""Enhanced search result with metadata"""
title: str
url: str
cover_image: Optional[str] = None
type: str # "search_result" or "direct"
metadata: Optional[AnimeMetadata] = None