- Updated DownloadRequest and DownloadItem models with comprehensive docstrings explaining serie_id (key as primary identifier) vs serie_folder (filesystem metadata) - Updated add_to_queue() endpoint docstring to document request parameters - Updated all test files to include required serie_folder field: - tests/api/test_download_endpoints.py - tests/api/test_queue_features.py - tests/frontend/test_existing_ui_integration.py - tests/integration/test_download_flow.py - Updated infrastructure.md with Download Queue request/response models - All 869 tests pass This is part of the Series Identifier Standardization effort (Phase 4.2) to ensure key is used as the primary identifier throughout the codebase.
191 lines
6.7 KiB
Markdown
191 lines
6.7 KiB
Markdown
# Aniworld Web Application Infrastructure
|
|
|
|
```bash
|
|
conda activate AniWorld
|
|
```
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
src/
|
|
├── core/ # Core application logic
|
|
│ ├── SeriesApp.py # Main application class
|
|
│ ├── SerieScanner.py # Directory scanner
|
|
│ ├── entities/ # Domain entities (series.py, SerieList.py)
|
|
│ ├── interfaces/ # Abstract interfaces (providers.py, callbacks.py)
|
|
│ ├── providers/ # Content providers (aniworld, streaming)
|
|
│ └── exceptions/ # Custom exceptions
|
|
├── server/ # FastAPI web application
|
|
│ ├── fastapi_app.py # Main FastAPI application
|
|
│ ├── controllers/ # Route controllers (health, page, error)
|
|
│ ├── api/ # API routes (auth, config, anime, download, websocket)
|
|
│ ├── models/ # Pydantic models
|
|
│ ├── services/ # Business logic services
|
|
│ ├── database/ # SQLAlchemy ORM layer
|
|
│ ├── utils/ # Utilities (dependencies, templates, security)
|
|
│ └── web/ # Frontend (templates, static assets)
|
|
├── cli/ # CLI application
|
|
data/ # Config, database, queue state
|
|
logs/ # Application logs
|
|
tests/ # Test suites
|
|
```
|
|
|
|
## Technology Stack
|
|
|
|
| Layer | Technology |
|
|
| --------- | ---------------------------------------------- |
|
|
| Backend | FastAPI, Uvicorn, SQLAlchemy, SQLite, Pydantic |
|
|
| Frontend | HTML5, CSS3, Vanilla JS, Bootstrap 5, HTMX |
|
|
| Security | JWT (python-jose), bcrypt (passlib) |
|
|
| Real-time | Native WebSocket |
|
|
|
|
## Series Identifier Convention
|
|
|
|
Throughout the codebase, two identifiers are used for anime series:
|
|
|
|
- **`key`**: Primary identifier (provider-assigned, URL-safe, e.g., `"attack-on-titan"`)
|
|
- **`folder`**: Display/filesystem metadata only (e.g., `"Attack on Titan (2013)"`)
|
|
|
|
All lookups, events, and API operations use `key`. The `folder` is metadata for display purposes.
|
|
|
|
## API Endpoints
|
|
|
|
### Authentication (`/api/auth`)
|
|
|
|
- `POST /login` - Master password authentication (returns JWT)
|
|
- `POST /logout` - Invalidate session
|
|
- `GET /status` - Check authentication status
|
|
|
|
### Configuration (`/api/config`)
|
|
|
|
- `GET /` - Get configuration
|
|
- `PUT /` - Update configuration
|
|
- `POST /validate` - Validate without applying
|
|
- `GET /backups` - List backups
|
|
- `POST /backups/{name}/restore` - Restore backup
|
|
|
|
### Anime (`/api/anime`)
|
|
|
|
- `GET /` - List anime with missing episodes (returns `key` as identifier)
|
|
- `GET /{anime_id}` - Get anime details (accepts `key` or `folder` for backward compatibility)
|
|
- `POST /search` - Search for anime (returns `key` as identifier)
|
|
- `POST /add` - Add new series (extracts `key` from link URL)
|
|
- `POST /rescan` - Trigger library rescan
|
|
|
|
**Response Models:**
|
|
|
|
- `AnimeSummary`: `key` (primary identifier), `name`, `site`, `folder` (metadata), `missing_episodes`, `link`
|
|
- `AnimeDetail`: `key` (primary identifier), `title`, `folder` (metadata), `episodes`, `description`
|
|
|
|
### Download Queue (`/api/queue`)
|
|
|
|
- `GET /status` - Queue status and statistics
|
|
- `POST /add` - Add episodes to queue
|
|
- `DELETE /{item_id}` - Remove item
|
|
- `POST /start` | `/stop` | `/pause` | `/resume` - Queue control
|
|
- `POST /retry` - Retry failed downloads
|
|
- `DELETE /completed` - Clear completed items
|
|
|
|
**Request Models:**
|
|
|
|
- `DownloadRequest`: `serie_id` (key, primary identifier), `serie_folder` (filesystem path), `serie_name` (display), `episodes`, `priority`
|
|
|
|
**Response Models:**
|
|
|
|
- `DownloadItem`: `id`, `serie_id` (key), `serie_folder` (metadata), `serie_name`, `episode`, `status`, `progress`
|
|
- `QueueStatus`: `is_running`, `is_paused`, `active_downloads`, `pending_queue`, `completed_downloads`, `failed_downloads`
|
|
|
|
### WebSocket (`/ws/connect`)
|
|
|
|
Real-time updates for downloads, scans, and queue operations.
|
|
|
|
**Rooms**: `downloads`, `download_progress`, `scan_progress`
|
|
|
|
**Message Types**: `download_progress`, `download_complete`, `download_failed`, `queue_status`, `scan_progress`, `scan_complete`, `scan_failed`
|
|
|
|
## Database Models
|
|
|
|
| Model | Purpose |
|
|
| ----------------- | ---------------------------------------- |
|
|
| AnimeSeries | Series metadata (key, name, folder, etc) |
|
|
| Episode | Episodes linked to series |
|
|
| DownloadQueueItem | Queue items with status and progress |
|
|
| UserSession | JWT sessions with expiry |
|
|
|
|
**Mixins**: `TimestampMixin` (created_at, updated_at), `SoftDeleteMixin`
|
|
|
|
## Core Services
|
|
|
|
### SeriesApp (`src/core/SeriesApp.py`)
|
|
|
|
Main engine for anime series management with async support, progress callbacks, and cancellation.
|
|
|
|
### Callback System (`src/core/interfaces/callbacks.py`)
|
|
|
|
- `ProgressCallback`, `ErrorCallback`, `CompletionCallback`
|
|
- Context classes include `key` + optional `folder` fields
|
|
- Thread-safe `CallbackManager` for multiple callback registration
|
|
|
|
### Services (`src/server/services/`)
|
|
|
|
| Service | Purpose |
|
|
| ---------------- | ----------------------------------------- |
|
|
| AnimeService | Series management, scans (uses SeriesApp) |
|
|
| DownloadService | Queue management, download execution |
|
|
| ScanService | Library scan operations with callbacks |
|
|
| ProgressService | Centralized progress tracking + WebSocket |
|
|
| WebSocketService | Real-time connection management |
|
|
| AuthService | JWT authentication, rate limiting |
|
|
| ConfigService | Configuration persistence with backups |
|
|
|
|
## Frontend
|
|
|
|
### Static Files
|
|
|
|
- CSS: `styles.css` (Fluent UI design), `ux_features.css` (accessibility)
|
|
- JS: `app.js`, `queue.js`, `websocket_client.js`, accessibility modules
|
|
|
|
### WebSocket Client
|
|
|
|
Native WebSocket wrapper with Socket.IO-compatible API:
|
|
|
|
```javascript
|
|
const socket = io();
|
|
socket.join("download_progress");
|
|
socket.on("download_progress", (data) => {
|
|
/* ... */
|
|
});
|
|
```
|
|
|
|
### Authentication
|
|
|
|
JWT tokens stored in localStorage, included as `Authorization: Bearer <token>`.
|
|
|
|
## Testing
|
|
|
|
```bash
|
|
# All tests
|
|
conda run -n AniWorld python -m pytest tests/ -v
|
|
|
|
# Unit tests only
|
|
conda run -n AniWorld python -m pytest tests/unit/ -v
|
|
|
|
# API tests
|
|
conda run -n AniWorld python -m pytest tests/api/ -v
|
|
```
|
|
|
|
## Production Notes
|
|
|
|
### Current (Single-Process)
|
|
|
|
- SQLite with WAL mode
|
|
- In-memory WebSocket connections
|
|
- File-based config and queue persistence
|
|
|
|
### Multi-Process Deployment
|
|
|
|
- Switch to PostgreSQL/MySQL
|
|
- Move WebSocket registry to Redis
|
|
- Use distributed locking for queue operations
|
|
- Consider Redis for session/cache storage
|