docs: Update CLAUDE.md with three-tier architecture and new providers
- Added new video players: Vidzy, LuLuvid, Uqload - Added new anime site: French-Manga - Added new series sites category with FS7 - Updated documentation to reflect three-tier architecture (anime sites → series sites → video players) - Added BaseSeriesSite interface documentation - Added "Adding New Series Site" section - Updated test organization with test_french_manga.py 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:
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
## Project Overview
|
||||
|
||||
Ohm Stream Downloader is a FastAPI-based web application for downloading anime episodes and media files from various file hosting services (1fichier, Doodstream, Rapidfile, Uptobox, VidMoly, SendVid, Sibnet, Lpayer) and anime streaming platforms (Anime-Sama, Neko-Sama, Anime-Ultime, Vostfree). It features a modern web interface, parallel downloads, pause/resume support, video streaming, personalized recommendations, and Sonarr webhook integration for automated downloads.
|
||||
Ohm Stream Downloader is a FastAPI-based web application for downloading anime episodes and media files from various file hosting services (1fichier, Doodstream, Rapidfile, Uptobox, VidMoly, SendVid, Sibnet, Lpayer, Vidzy, LuLuvid, Uqload) and streaming platforms (Anime-Sama, Neko-Sama, Anime-Ultime, Vostfree, French-Manga, FS7). It features a modern web interface, parallel downloads, pause/resume support, video streaming, personalized recommendations, and Sonarr webhook integration for automated downloads.
|
||||
|
||||
## Development Commands
|
||||
|
||||
@@ -52,22 +52,35 @@ Ohm_streaming/
|
||||
├── main.py # FastAPI application & API endpoints
|
||||
├── app/
|
||||
│ ├── models/ # Pydantic models (DownloadTask, AnimeMetadata, Sonarr, etc.)
|
||||
│ ├── downloaders/ # Host-specific downloaders
|
||||
│ │ ├── base.py # BaseDownloader abstract class
|
||||
│ │ ├── unfichier.py # 1fichier.com handler
|
||||
│ │ ├── doodstream.py # Doodstream handler
|
||||
│ │ ├── rapidfile.py # Rapidfile handler
|
||||
│ │ ├── uptobox.py # Uptobox handler
|
||||
│ │ ├── vidmoly.py # VidMoly handler
|
||||
│ │ ├── sendvid.py # SendVid handler
|
||||
│ │ ├── sibnet.py # Sibnet handler
|
||||
│ │ ├── lpayer.py # Lpayer handler
|
||||
│ │ ├── vidmoly_old.py # Old VidMoly implementation (deprecated)
|
||||
│ │ ├── animesama.py # Anime-Sama (anime provider)
|
||||
│ │ ├── animeultime.py # Anime-Ultime (anime provider)
|
||||
│ │ ├── nekosama.py # Neko-Sama (anime provider)
|
||||
│ │ ├── vostfree.py # Vostfree (anime provider)
|
||||
│ │ └── __init__.py # Factory function and registry
|
||||
│ ├── downloaders/ # Host-specific downloaders (organized structure)
|
||||
│ │ ├── base.py # BaseDownloader abstract class (legacy, kept for compatibility)
|
||||
│ │ ├── __init__.py # Factory function (three-tier: anime sites → series sites → video players)
|
||||
│ │ ├── anime_sites/ # Anime streaming sites (catalogs)
|
||||
│ │ │ ├── base.py # BaseAnimeSite abstract class
|
||||
│ │ │ ├── __init__.py # Anime site factory
|
||||
│ │ │ ├── animesama.py # Anime-Sama (anime provider)
|
||||
│ │ │ ├── animeultime.py # Anime-Ultime (anime provider)
|
||||
│ │ │ ├── nekosama.py # Neko-Sama (anime provider)
|
||||
│ │ │ ├── vostfree.py # Vostfree (anime provider)
|
||||
│ │ │ └── frenchmanga.py # French-Manga (anime provider)
|
||||
│ │ ├── series_sites/ # TV series streaming sites (catalogs)
|
||||
│ │ │ ├── base.py # BaseSeriesSite abstract class
|
||||
│ │ │ ├── __init__.py # Series site factory
|
||||
│ │ │ └── fs7.py # FS7 (French Stream)
|
||||
│ │ └── video_players/ # File hosting services (players)
|
||||
│ │ ├── base.py # BaseVideoPlayer abstract class
|
||||
│ │ ├── __init__.py # Video player factory
|
||||
│ │ ├── unfichier.py # 1fichier.com handler
|
||||
│ │ ├── doodstream.py # Doodstream handler
|
||||
│ │ ├── rapidfile.py # Rapidfile handler
|
||||
│ │ ├── uptobox.py # Uptobox handler
|
||||
│ │ ├── vidmoly.py # VidMoly handler
|
||||
│ │ ├── sendvid.py # SendVid handler
|
||||
│ │ ├── sibnet.py # Sibnet handler
|
||||
│ │ ├── lpayer.py # Lpayer handler
|
||||
│ │ ├── vidzy.py # Vidzy handler
|
||||
│ │ ├── luluv.py # LuLuvid handler
|
||||
│ │ └── uqload.py # Uqload handler
|
||||
│ ├── providers.py # Provider configuration (domains, icons, colors)
|
||||
│ ├── config.py # Environment-based configuration (Pydantic Settings)
|
||||
│ ├── utils.py # Security utilities (sanitize_filename, is_safe_filename)
|
||||
@@ -105,24 +118,61 @@ Ohm_streaming/
|
||||
|
||||
### 2. Downloaders (`app/downloaders/`)
|
||||
|
||||
**Factory Pattern:**
|
||||
- `get_downloader(url)` in `__init__.py` selects appropriate downloader
|
||||
- Each downloader inherits from `BaseDownloader` abstract class
|
||||
- Order matters: anime providers checked first, then file hosts
|
||||
- Falls back to `GenericDownloader` if no match
|
||||
**Architecture:**
|
||||
The downloaders are organized into three categories with separate base classes:
|
||||
|
||||
**BaseDownloader Interface:**
|
||||
- `can_handle(url)` - Check if downloader supports the URL
|
||||
- `get_download_link(url)` - Extract direct download link and filename
|
||||
- `search_anime(query, lang)` - Search anime (anime providers only)
|
||||
- `get_episodes(anime_url, lang)` - Get episode list (anime providers only)
|
||||
- `get_anime_metadata(anime_url)` - Get metadata dict (anime providers only) - Note: not in base.py, implemented by anime providers
|
||||
**Anime Sites** (`app/downloaders/anime_sites/`):
|
||||
- Provide anime catalogs, metadata, and episode listings
|
||||
- Link to video players for actual file hosting
|
||||
- Inherit from `BaseAnimeSite` abstract class
|
||||
- Factory: `get_anime_site(url)` in `anime_sites/__init__.py`
|
||||
- Implement: `search_anime()`, `get_episodes()`, `get_anime_metadata()`, `get_download_link()`
|
||||
|
||||
**Series Sites** (`app/downloaders/series_sites/`):
|
||||
- Provide TV series catalogs, metadata, and episode listings
|
||||
- Similar to anime sites but for general TV series content
|
||||
- Inherit from `BaseSeriesSite` abstract class
|
||||
- Factory: `get_series_site(url)` in `series_sites/__init__.py`
|
||||
- Implement: `search_anime()`, `get_episodes()`, `get_anime_metadata()`, `get_download_link()`
|
||||
|
||||
**Video Players** (`app/downloaders/video_players/`):
|
||||
- Host actual video files and provide direct download links
|
||||
- Extract URLs from embedded players and handle file downloads
|
||||
- Inherit from `BaseVideoPlayer` abstract class
|
||||
- Factory: `get_video_player(url)` in `video_players/__init__.py`
|
||||
- Implement: `get_download_link(url, target_filename=None)`
|
||||
|
||||
**Three-Tier Factory Pattern:**
|
||||
- `get_downloader(url)` in main `__init__.py` checks: anime sites → series sites → video players
|
||||
- Falls back to `GenericDownloader` if no match
|
||||
- This separation allows anime/series sites to delegate to video players for actual downloads
|
||||
|
||||
**BaseAnimeSite Interface:**
|
||||
- `can_handle(url)` - Check if this anime site can handle the URL
|
||||
- `search_anime(query, lang)` - Search for anime, returns list with title, url, cover_image
|
||||
- `get_episodes(anime_url, lang)` - Get episode list with episode_number, url, title, host
|
||||
- `get_anime_metadata(anime_url)` - Get metadata dict (synopsis, genres, rating, release_year, studio, poster_image, total_episodes, status)
|
||||
- `get_download_link(url)` - Get video player URL from episode page (NOT direct download link)
|
||||
|
||||
**BaseSeriesSite Interface:**
|
||||
- `can_handle(url)` - Check if this series site can handle the URL
|
||||
- `search_anime(query, lang)` - Search for series, returns list with title, url, cover_image, lang
|
||||
- `get_episodes(anime_url, lang)` - Get episode list with episode_number, url, title, host
|
||||
- `get_anime_metadata(anime_url)` - Get metadata dict (title, synopsis, genres, rating, release_year, studio, poster_image, total_episodes, status, languages)
|
||||
- `get_download_link(url)` - Get video player URL from episode page (NOT direct download link)
|
||||
|
||||
**BaseVideoPlayer Interface:**
|
||||
- `can_handle(url)` - Check if this player can handle the URL
|
||||
- `get_download_link(url, target_filename=None)` - Extract direct download link and filename
|
||||
- Note: `target_filename` parameter is optional but MUST be supported for VidMoly/SendVid compatibility
|
||||
- Always use `sanitize_filename()` on extracted filenames!
|
||||
|
||||
**Key Patterns:**
|
||||
- All downloaders use httpx.AsyncClient for HTTP requests
|
||||
- BeautifulSoup with lxml for HTML parsing
|
||||
- Async/await throughout for non-blocking I/O
|
||||
- Fuzzy search using jieba for Chinese text segmentation and typo tolerance
|
||||
- Security: Filename sanitization enforced via `app.utils` functions
|
||||
|
||||
### 3. Provider Configuration (`app/providers.py`)
|
||||
- `ANIME_PROVIDERS` - Anime streaming sites configuration
|
||||
@@ -228,6 +278,7 @@ Ohm_streaming/
|
||||
- `test_anime_sama_seasons.py` - Anime-Sama season handling tests
|
||||
- `test_translate_api.py` - Translation API tests
|
||||
- `test_delete_and_restore.py` - Delete and restore functionality tests
|
||||
- `test_french_manga.py` - French-Manga provider tests
|
||||
|
||||
**Fixtures in conftest.py:**
|
||||
- `temp_dir` - Temporary directory
|
||||
@@ -269,28 +320,31 @@ pytest tests/test_sonarr.py::TestSonarrHandler::test_add_mapping -v
|
||||
|
||||
To add support for a new file hosting service:
|
||||
|
||||
1. Create new file in `app/downloaders/` (e.g., `myhost.py`)
|
||||
2. Inherit from `BaseDownloader`
|
||||
3. Implement required methods
|
||||
4. Add to imports in `app/downloaders/__init__.py`
|
||||
5. Add to `downloaders` list in `get_downloader()`
|
||||
1. Create new file in `app/downloaders/video_players/` (e.g., `myhost.py`)
|
||||
2. Inherit from `BaseVideoPlayer`
|
||||
3. Implement required methods (`can_handle`, `get_download_link`)
|
||||
4. Add to imports in `app/downloaders/video_players/__init__.py`
|
||||
5. Add to `players` list in `get_video_player()`
|
||||
6. Add configuration to `FILE_HOSTS` in `app/providers.py`
|
||||
|
||||
Example:
|
||||
```python
|
||||
from .base import BaseDownloader
|
||||
from .base import BaseVideoPlayer
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
class MyHostDownloader(BaseDownloader):
|
||||
class MyHostDownloader(BaseVideoPlayer):
|
||||
def can_handle(self, url: str) -> bool:
|
||||
return "myhost.com" in url.lower()
|
||||
|
||||
async def get_download_link(self, url: str) -> tuple[str, str]:
|
||||
async def get_download_link(self, url: str, target_filename: Optional[str] = None) -> tuple[str, str]:
|
||||
soup = BeautifulSoup(await self._fetch_page(url), 'lxml')
|
||||
# ... extraction logic ...
|
||||
# IMPORTANT: Always sanitize filenames!
|
||||
from app.utils import sanitize_filename
|
||||
filename = sanitize_filename(extracted_filename)
|
||||
return download_url, filename
|
||||
|
||||
def close(self):
|
||||
async def close(self):
|
||||
# IMPORTANT: Always close the HTTP client
|
||||
await self.client.aclose()
|
||||
```
|
||||
@@ -299,6 +353,23 @@ class MyHostDownloader(BaseDownloader):
|
||||
- Always close the HTTP client in your downloader to avoid resource leaks
|
||||
- Use `sanitize_filename()` from `app.utils` when extracting filenames from URLs
|
||||
- Use `is_safe_filename()` to validate filenames before file operations
|
||||
- The `target_filename` parameter is required for compatibility with anime/series sites
|
||||
|
||||
## Adding New Series Site
|
||||
|
||||
To add a new TV series streaming provider (similar to anime sites but for general TV series):
|
||||
|
||||
1. Create new file in `app/downloaders/series_sites/` (e.g., `mysite.py`)
|
||||
2. Inherit from `BaseSeriesSite`
|
||||
3. Implement series-specific methods:
|
||||
- `search_anime(query, lang)` - Return list of series with title, url, cover_image, lang
|
||||
- `get_episodes(anime_url, lang)` - Return list of episodes
|
||||
- `get_anime_metadata(anime_url)` - Return metadata dict (should include languages field)
|
||||
- `get_download_link(url)` - Return video player URL from episode page
|
||||
4. Add to imports in `app/downloaders/series_sites/__init__.py`
|
||||
5. Add to `sites` list in `get_series_site()`
|
||||
|
||||
BaseSeriesSite is nearly identical to BaseAnimeSite but designed for general TV series content rather than anime-specific content.
|
||||
|
||||
## Sonarr Integration
|
||||
|
||||
@@ -376,14 +447,17 @@ The application includes full Sonarr webhook support for automated anime downloa
|
||||
|
||||
To add a new anime streaming provider:
|
||||
|
||||
1. Create downloader inheriting from `BaseDownloader`
|
||||
2. Implement anime-specific methods:
|
||||
1. Create new file in `app/downloaders/anime_sites/` (e.g., `mysite.py`)
|
||||
2. Inherit from `BaseAnimeSite`
|
||||
3. Implement anime-specific methods:
|
||||
- `search_anime(query, lang)` - Return list of anime with title, url, cover_image
|
||||
- `get_episodes(anime_url, lang)` - Return list of episodes
|
||||
- `get_anime_metadata(anime_url)` - Return metadata dict
|
||||
3. Add to `ANIME_PROVIDERS` in `app/providers.py`
|
||||
4. Add to factory in `app/downloaders/__init__.py`
|
||||
5. Update `main.py` to include in unified search
|
||||
- `get_download_link(url)` - Return video player URL from episode page
|
||||
4. Add to imports in `app/downloaders/anime_sites/__init__.py`
|
||||
5. Add to `sites` list in `get_anime_site()`
|
||||
6. Add to `ANIME_PROVIDERS` in `app/providers.py`
|
||||
7. Update `main.py` to include in unified search
|
||||
|
||||
Metadata should include:
|
||||
- synopsis, genres, rating, release_year, studio, poster_image, total_episodes, status
|
||||
@@ -423,6 +497,7 @@ LOG_LEVEL=INFO # Logging level
|
||||
- `CLAUDE.md` - This file (developer guide)
|
||||
- `docs/SONARR_INTEGRATION.md` - Complete Sonarr setup guide
|
||||
- `docs/SONARR_IMPLEMENTATION.md` - Technical implementation summary
|
||||
- `docs/IMPROVEMENTS_2024-01-24.md` - Recent security and quality improvements
|
||||
|
||||
## Key Implementation Details
|
||||
|
||||
|
||||
Reference in New Issue
Block a user