# Architecture Documentation ## Document Purpose This document describes the system architecture of the Aniworld anime download manager. --- ## 1. System Overview Aniworld is a web-based anime download manager built with Python, FastAPI, and SQLite. It provides a REST API and WebSocket interface for managing anime libraries, downloading episodes, and tracking progress. ### High-Level Architecture ``` +------------------+ +------------------+ +------------------+ | Web Browser | | CLI Client | | External | | (Frontend) | | (Main.py) | | Providers | +--------+---------+ +--------+---------+ +--------+---------+ | | | | HTTP/WebSocket | Direct | HTTP | | | +--------v---------+ +--------v---------+ +--------v---------+ | | | | | | | FastAPI <-----> Core Layer <-----> Provider | | Server Layer | | (SeriesApp) | | Adapters | | | | | | | +--------+---------+ +--------+---------+ +------------------+ | | | | +--------v---------+ +--------v---------+ | | | | | SQLite DB | | File System | | (aniworld.db) | | (data/*.json) | | | | | +------------------+ +------------------+ ``` Source: [src/server/fastapi_app.py](../src/server/fastapi_app.py#L1-L252) --- ## 2. Architectural Layers ### 2.1 CLI Layer (`src/cli/`) Legacy command-line interface for direct interaction with the core layer. | Component | File | Purpose | | --------- | ----------------------------- | --------------- | | Main | [Main.py](../src/cli/Main.py) | CLI entry point | ### 2.2 Server Layer (`src/server/`) FastAPI-based REST API and WebSocket server. ``` src/server/ +-- fastapi_app.py # Application entry point, lifespan management +-- api/ # API route handlers | +-- anime.py # /api/anime/* endpoints | +-- auth.py # /api/auth/* endpoints | +-- config.py # /api/config/* endpoints | +-- download.py # /api/queue/* endpoints | +-- scheduler.py # /api/scheduler/* endpoints | +-- websocket.py # /ws/* WebSocket handlers | +-- health.py # /health/* endpoints +-- controllers/ # Page controllers for HTML rendering | +-- page_controller.py # UI page routes | +-- health_controller.py# Health check route | +-- error_controller.py # Error pages (404, 500) +-- services/ # Business logic | +-- anime_service.py # Anime operations | +-- auth_service.py # Authentication | +-- config_service.py # Configuration management | +-- download_service.py # Download queue management | +-- progress_service.py # Progress tracking | +-- websocket_service.py# WebSocket broadcasting | +-- queue_repository.py # Database persistence +-- models/ # Pydantic models | +-- auth.py # Auth request/response models | +-- config.py # Configuration models | +-- download.py # Download queue models | +-- websocket.py # WebSocket message models +-- middleware/ # Request processing | +-- auth.py # JWT validation, rate limiting | +-- error_handler.py # Exception handlers | +-- setup_redirect.py # Setup flow redirect +-- database/ # SQLAlchemy ORM | +-- connection.py # Database connection | +-- models.py # ORM models | +-- service.py # Database service +-- web/ # Static files and templates +-- static/ # CSS, JS, images +-- templates/ # Jinja2 templates ``` Source: [src/server/](../src/server/) ### 2.3 Core Layer (`src/core/`) Domain logic for anime series management. ``` src/core/ +-- SeriesApp.py # Main application facade +-- SerieScanner.py # Directory scanning +-- entities/ # Domain entities | +-- series.py # Serie class | +-- SerieList.py # SerieList collection +-- providers/ # External provider adapters | +-- base_provider.py # Loader interface | +-- provider_factory.py # Provider registry +-- interfaces/ # Abstract interfaces | +-- callbacks.py # Progress callback system +-- exceptions/ # Domain exceptions +-- Exceptions.py # Custom exceptions ``` Source: [src/core/](../src/core/) ### 2.4 Infrastructure Layer (`src/infrastructure/`) Cross-cutting concerns. ``` src/infrastructure/ +-- logging/ # Structured logging setup +-- security/ # Security utilities ``` ### 2.5 Configuration Layer (`src/config/`) Application settings management. | Component | File | Purpose | | --------- | ---------------------------------------- | ------------------------------- | | Settings | [settings.py](../src/config/settings.py) | Environment-based configuration | Source: [src/config/settings.py](../src/config/settings.py#L1-L96) --- ## 3. Component Interactions ### 3.1 Request Flow (REST API) ``` 1. Client sends HTTP request 2. AuthMiddleware validates JWT token (if required) 3. Rate limiter checks request frequency 4. FastAPI router dispatches to endpoint handler 5. Endpoint calls service layer 6. Service layer uses core layer or database 7. Response returned as JSON ``` Source: [src/server/middleware/auth.py](../src/server/middleware/auth.py#L1-L209) ### 3.2 Download Flow ``` 1. POST /api/queue/add +-- DownloadService.add_to_queue() +-- QueueRepository.save_item() -> SQLite 2. POST /api/queue/start +-- DownloadService.start_queue_processing() +-- Process pending items sequentially +-- ProgressService emits events +-- WebSocketService broadcasts to clients 3. During download: +-- ProgressService.emit("progress_updated") +-- WebSocketService.broadcast_to_room() +-- Client receives WebSocket message ``` Source: [src/server/services/download_service.py](../src/server/services/download_service.py#L1-L150) ### 3.3 WebSocket Event Flow ``` 1. Client connects to /ws/connect 2. Server sends "connected" message 3. Client joins room: {"action": "join", "data": {"room": "downloads"}} 4. ProgressService emits events 5. WebSocketService broadcasts to room subscribers 6. Client receives real-time updates ``` Source: [src/server/api/websocket.py](../src/server/api/websocket.py#L1-L260) --- ## 4. Design Patterns ### 4.1 Repository Pattern Database access is abstracted through repository classes. ```python # QueueRepository provides CRUD for download items class QueueRepository: async def save_item(self, item: DownloadItem) -> None: ... async def get_all_items(self) -> List[DownloadItem]: ... async def delete_item(self, item_id: str) -> bool: ... ``` Source: [src/server/services/queue_repository.py](../src/server/services/queue_repository.py) ### 4.2 Dependency Injection FastAPI's `Depends()` provides constructor injection. ```python @router.get("/status") async def get_status( download_service: DownloadService = Depends(get_download_service), ): ... ``` Source: [src/server/utils/dependencies.py](../src/server/utils/dependencies.py) ### 4.3 Event-Driven Architecture Progress updates use an event subscription model. ```python # ProgressService publishes events progress_service.emit("progress_updated", event) # WebSocketService subscribes progress_service.subscribe("progress_updated", ws_handler) ``` Source: [src/server/fastapi_app.py](../src/server/fastapi_app.py#L98-L108) ### 4.4 Singleton Pattern Services use module-level singletons for shared state. ```python # In download_service.py _download_service_instance: Optional[DownloadService] = None def get_download_service() -> DownloadService: global _download_service_instance if _download_service_instance is None: _download_service_instance = DownloadService(...) return _download_service_instance ``` Source: [src/server/services/download_service.py](../src/server/services/download_service.py) --- ## 5. Data Flow ### 5.1 Series Identifier Convention The system uses two identifier fields: | Field | Type | Purpose | Example | | -------- | -------- | -------------------------------------- | -------------------------- | | `key` | Primary | Provider-assigned, URL-safe identifier | `"attack-on-titan"` | | `folder` | Metadata | Filesystem folder name (display only) | `"Attack on Titan (2013)"` | All API operations use `key`. The `folder` is for filesystem operations only. Source: [src/server/database/models.py](../src/server/database/models.py#L26-L50) ### 5.2 Database Schema ``` +----------------+ +----------------+ +--------------------+ | anime_series | | episodes | | download_queue_item| +----------------+ +----------------+ +--------------------+ | id (PK) |<--+ | id (PK) | +-->| id (PK) | | key (unique) | | | series_id (FK) |---+ | series_id (FK) | | name | +---| season | | status | | site | | episode_number | | priority | | folder | | title | | progress_percent | | created_at | | is_downloaded | | added_at | | updated_at | | file_path | | started_at | +----------------+ +----------------+ +--------------------+ ``` Source: [src/server/database/models.py](../src/server/database/models.py#L1-L200) ### 5.3 Configuration Storage Configuration is stored in `data/config.json`: ```json { "name": "Aniworld", "data_dir": "data", "scheduler": { "enabled": true, "interval_minutes": 60 }, "logging": { "level": "INFO" }, "backup": { "enabled": false, "path": "data/backups" }, "other": { "master_password_hash": "$pbkdf2-sha256$...", "anime_directory": "/path/to/anime" } } ``` Source: [data/config.json](../data/config.json) --- ## 6. Technology Stack | Layer | Technology | Version | Purpose | | ------------- | ------------------- | ------- | ---------------------- | | Web Framework | FastAPI | 0.104.1 | REST API, WebSocket | | ASGI Server | Uvicorn | 0.24.0 | HTTP server | | Database | SQLite + SQLAlchemy | 2.0.35 | Persistence | | Auth | python-jose | 3.3.0 | JWT tokens | | Password | passlib | 1.7.4 | bcrypt hashing | | Validation | Pydantic | 2.5.0 | Data models | | Templates | Jinja2 | 3.1.2 | HTML rendering | | Logging | structlog | 24.1.0 | Structured logging | | Testing | pytest | 7.4.3 | Unit/integration tests | Source: [requirements.txt](../requirements.txt) --- ## 7. Scalability Considerations ### Current Limitations 1. **Single-process deployment**: In-memory rate limiting and session state are not shared across processes. 2. **SQLite database**: Not suitable for high concurrency. Consider PostgreSQL for production. 3. **Sequential downloads**: Only one download processes at a time by design. ### Recommended Improvements for Scale | Concern | Current | Recommended | | -------------- | --------------- | ----------------- | | Rate limiting | In-memory dict | Redis | | Session store | In-memory | Redis or database | | Database | SQLite | PostgreSQL | | Task queue | In-memory deque | Celery + Redis | | Load balancing | None | Nginx/HAProxy | --- ## 8. Integration Points ### 8.1 External Providers The system integrates with anime streaming providers via the Loader interface. ```python class Loader(ABC): @abstractmethod def search(self, query: str) -> List[Serie]: ... @abstractmethod def get_episodes(self, serie: Serie) -> Dict[int, List[int]]: ... ``` Source: [src/core/providers/base_provider.py](../src/core/providers/base_provider.py) ### 8.2 Filesystem Integration The scanner reads anime directories to detect downloaded episodes. ```python SerieScanner( basePath="/path/to/anime", # Anime library directory loader=provider, # Provider for metadata db_session=session # Optional database ) ``` Source: [src/core/SerieScanner.py](../src/core/SerieScanner.py#L59-L96) --- ## 9. Security Architecture ### 9.1 Authentication Flow ``` 1. User sets master password via POST /api/auth/setup 2. Password hashed with pbkdf2_sha256 (via passlib) 3. Hash stored in config.json 4. Login validates password, returns JWT token 5. JWT contains: session_id, user, created_at, expires_at 6. Subsequent requests include: Authorization: Bearer ``` Source: [src/server/services/auth_service.py](../src/server/services/auth_service.py#L1-L150) ### 9.2 Password Requirements - Minimum 8 characters - Mixed case (upper and lower) - At least one number - At least one special character Source: [src/server/services/auth_service.py](../src/server/services/auth_service.py#L97-L125) ### 9.3 Rate Limiting | Endpoint | Limit | Window | | ----------------- | ----------- | ---------- | | `/api/auth/login` | 5 requests | 60 seconds | | `/api/auth/setup` | 5 requests | 60 seconds | | All origins | 60 requests | 60 seconds | Source: [src/server/middleware/auth.py](../src/server/middleware/auth.py#L54-L68) --- ## 10. Deployment Modes ### 10.1 Development ```bash # Run with hot reload python -m uvicorn src.server.fastapi_app:app --reload ``` ### 10.2 Production ```bash # Via conda environment conda run -n AniWorld python -m uvicorn src.server.fastapi_app:app \ --host 127.0.0.1 --port 8000 ``` ### 10.3 Configuration Environment variables (via `.env` or shell): | Variable | Default | Description | | ----------------- | ------------------------------ | ---------------------- | | `JWT_SECRET_KEY` | Random | Secret for JWT signing | | `DATABASE_URL` | `sqlite:///./data/aniworld.db` | Database connection | | `ANIME_DIRECTORY` | (empty) | Path to anime library | | `LOG_LEVEL` | `INFO` | Logging level | | `CORS_ORIGINS` | `localhost:3000,8000` | Allowed CORS origins | Source: [src/config/settings.py](../src/config/settings.py#L1-L96)