10 KiB
10 KiB
AGENTS.md - Agentic Coding Guidelines
This file provides guidance for AI agents working in this repository.
Quick Start
# Setup
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt
# Run dev server
uvicorn main:app --reload --host 0.0.0.0 --port 3000
Build, Lint & Test Commands
Running Tests
# All tests
pytest
# With coverage (HTML report in htmlcov/)
pytest --cov=app --cov-report=html
# Unit only (fast)
pytest -m "unit"
# Integration tests only
pytest -m "integration"
# Exclude slow tests
pytest -m "not slow"
# Exclude network tests (mocked only)
pytest -m "not network"
# Verbose with print debugging
pytest -v -s
# Generate HTML report
pytest --html=report.html --self-contained-html
# Timeout per test (seconds)
pytest --timeout=30
Running Single Tests
# Specific file
pytest tests/test_sonarr.py -v
# Specific class
pytest tests/test_sonarr.py::TestSonarrHandler -v
# Specific test
pytest tests/test_sonarr.py::TestSonarrHandler::test_add_mapping -v
# Pattern match
pytest -k "test_download" -v
Code Style
Imports (PEP 8 order)
- Standard library (
os,json,asyncio) - Third-party (
httpx,beautifulsoup4,fastapi) - Local app (
app.config,app.utils)
import os
import asyncio
from typing import Optional
import httpx
from fastapi import APIRouter, HTTPException
from app.config import get_settings
from app.models import DownloadTask, DownloadStatus
Formatting
- Line length: 120 chars max
- Indentation: 4 spaces
- Blank lines: 2 between top-level, 1 between inline
Type Annotations
- Use explicit types
- Use
Optional[X]notX | None - Use
list[X],dict[X, Y]
# Good
async def get_download_link(url: str, target_filename: Optional[str] = None) -> tuple[str, str]:
results: list[dict[str, str]] = []
# Avoid
async def get_download_link(url, target_filename=None):
results = []
Naming Conventions
| Element | Convention | Example |
|---|---|---|
| Modules | snake_case | download_manager.py |
| Classes | PascalCase | DownloadManager |
| Functions | snake_case | get_download_link() |
| Constants | UPPER_SNAKE | MAX_PARALLEL_DOWNLOADS |
| Variables | snake_case | download_task |
| Enums | PascalCase | DownloadStatus |
| Enum values | UPPER_SNAKE | DownloadStatus.PENDING |
Async/Await
- Always use for I/O operations
- Close clients properly to avoid leaks
async def close(self):
await self.client.aclose()
Error Handling
- Use try/except for recoverable errors
- Raise specific exceptions (
HTTPException,ValueError) - Never use empty except blocks
- Log errors appropriately
try:
result = await client.get(url)
except httpx.TimeoutException:
logger.warning(f"Request timeout for {url}")
raise HTTPException(status_code=504, detail="Request timeout")
File Operations
- Always sanitize filenames:
app.utils.sanitize_filename() - Validate paths:
app.utils.is_safe_filename()
Testing
- Use pytest with pytest-asyncio
- Mark tests:
@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.slow,@pytest.mark.network - Tests in
test_api.pyare auto-marked as integration, others as unit - Use fixtures from
tests/conftest.py
@pytest.mark.unit
@pytest.mark.asyncio
async def test_download_manager():
manager = DownloadManager(max_parallel=3)
assert manager.max_parallel == 3
# Mark slow tests
@pytest.mark.slow
async def test_full_download_flow():
...
# Mark tests requiring network
@pytest.mark.network
async def test_external_api():
...
Security
- Never hardcode secrets - use environment variables
- Validate all inputs (URLs, filenames)
- Use HMAC for webhook verification when configured
- Limit CORS origins - never use
*in production
Architecture Patterns
Three-Tier Downloader Architecture
The project uses a three-tier downloader system:
-
Anime Catalogs (
app/downloaders/anime_sites/)animesama.py- Anime-Sama (primary)animeultime.py- Anime-Ultimenekosama.py- Neko-Samavostfree.py- Vostfreefrenchmanga.py- French-Manga
-
Series Catalogs (
app/downloaders/series_sites/)fs7.py- French Stream
-
Video Players (
app/downloaders/video_players/)sibnet.py,doodstream.py,vidmoly.py,uqload.pyuptobox.py,unfichier.py,rapidfile.pysendvid.py,lpayer.py,vidzy.py,luluv.pyoneupload.py,smoothpre.py
Each tier has a base class and factory pattern. When adding providers:
- Inherit from appropriate base class (
base.py) - Implement required methods (
search_anime,get_episodes,get_download_link) - Register in
app/providers.py - Add URL detection patterns
URL Convention: Pipe-separated format preserves metadata:
video_url|anime_page_url|episode_title
Core Modules
| Module | Purpose |
|---|---|
app/watchlist.py |
Episode tracking & auto-download |
app/auto_download_scheduler.py |
APScheduler for periodic checks |
app/episode_checker.py |
New episode detection |
app/sonarr_handler.py |
Sonarr webhook integration |
app/recommendation_engine.py |
Personalized anime recommendations |
app/favorites.py |
User favorites management |
app/auth.py |
JWT authentication |
app/download_manager.py |
Download queue management |
Key Files
| File | Purpose |
|---|---|
main.py |
FastAPI app, all API endpoints |
app/config.py |
Pydantic Settings configuration |
app/download_manager.py |
Download queue & task management |
app/utils.py |
sanitize_filename, is_safe_filename |
app/auth.py |
JWT auth, user management |
app/providers.py |
Provider definitions & URL detection |
app/models/__init__.py |
Core Pydantic models |
app/models/watchlist.py |
Watchlist models |
app/models/sonarr.py |
Sonarr integration models |
app/models/auth.py |
Authentication models |
Frontend Architecture
JavaScript Modules (static/js/)
| Module | Purpose |
|---|---|
main.js |
Application entry point |
api.js |
API client functions |
auth.js |
Authentication handling |
tabs.js |
Tab navigation |
anime.js |
Anime search & display |
anime-details.js |
Anime detail views |
watchlist.js |
Watchlist API calls |
watchlist-ui.js |
Watchlist UI rendering |
downloads.js |
Download management UI |
recommendations.js |
Recommendations display |
series-search.js |
TV series search |
utils.js |
Utility functions |
Templates (templates/)
| Template | Purpose |
|---|---|
base.html |
Base layout with CSS/JS imports |
index.html |
Main SPA interface |
login.html |
Login/register page |
watchlist.html |
Watchlist management page |
player.html |
Video player page |
components/ |
Reusable HTML components |
Configuration
- Use
.envfrom.env.example JWT_SECRET_KEYmust change in production- Config files stored in
config/:users.json- User databasewatchlist.json- Watchlist datawatchlist_settings.json- Auto-download settingssonarr.json- Sonarr integration configsonarr_mappings.json- Series to anime mappings
API Endpoints Overview
Authentication
POST /api/auth/register- Register new userPOST /api/auth/login- Login, get JWT tokenGET /api/auth/me- Get current user infoPOST /api/auth/logout- Logout (client-side)
Downloads
POST /api/download- Create download taskGET /api/downloads- List all downloadsGET /api/download/{task_id}- Get download statusPOST /api/download/{task_id}/pause- Pause downloadPOST /api/download/{task_id}/resume- Resume downloadDELETE /api/download/{task_id}- Cancel/delete downloadGET /api/download/{task_id}/file- Download completed file
Anime Search & Metadata
GET /api/anime/search- Search across all anime providersGET /api/series/search- Search TV series providersGET /api/anime/metadata- Get detailed anime metadataGET /api/anime/episodes- Get episode listGET /api/anime/seasons- Get available seasonsPOST /api/anime/download-season- Download all episodes
Watchlist
GET /api/watchlist- List watchlist itemsPOST /api/watchlist- Add to watchlistPUT /api/watchlist/{item_id}- Update watchlist itemDELETE /api/watchlist/{item_id}- Remove from watchlistGET /api/watchlist/settings- Get auto-download settingsPUT /api/watchlist/settings- Update settingsPOST /api/watchlist/check- Trigger manual episode check
Favorites
GET /api/favorites- List favoritesPOST /api/favorites- Add to favoritesDELETE /api/favorites/{anime_id}- Remove from favoritesPOST /api/favorites/toggle- Toggle favorite status
Recommendations
GET /api/recommendations- Get personalized recommendationsGET /api/releases/latest- Get latest releasesGET /api/releases/seasonal- Get seasonal anime
Sonarr Integration
POST /api/sonarr/webhook- Receive Sonarr webhooksGET /api/sonarr/mappings- List Sonarr mappingsPOST /api/sonarr/mappings- Create mappingDELETE /api/sonarr/mappings/{series_id}- Delete mapping
Dependencies
Core
fastapi- Web frameworkuvicorn- ASGI serverhttpx- Async HTTP clientaiohttp- Alternative HTTP clientpydantic/pydantic-settings- Data validation & settings
Scraping & Parsing
beautifulsoup4- HTML parsinglxml- XML/HTML parserjieba- Chinese text segmentation
Authentication
python-jose- JWT handlingpasslib[bcrypt]- Password hashing
Scheduler
apscheduler- Job scheduling for auto-downloads
Cryptography
pycryptodome- AES decryption for video players
Testing
pytest+pytest-asyncio- Async test supportpytest-cov- Coverage reportingpytest-mock- Mocking utilitiespytest-timeout- Test timeout protectionpytest-html- HTML test reports