NoDataFile #1
@ -17,7 +17,7 @@
|
||||
"keep_days": 30
|
||||
},
|
||||
"other": {
|
||||
"master_password_hash": "$pbkdf2-sha256$29000$4Ny7tzZGaG2ttVaKsRZiLA$29mSesYMcIC0u0JfpP3SM7c.fEiE82.VYh9q2vZEBRw"
|
||||
"master_password_hash": "$pbkdf2-sha256$29000$R0hpDWEspRSidA4BoPTemw$NL4pP6ch.3sRxe6gjQ1tM3VPntwZMoZUFAI9sTQuHPE"
|
||||
},
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "Aniworld",
|
||||
"data_dir": "data",
|
||||
"scheduler": {
|
||||
"enabled": true,
|
||||
"interval_minutes": 60
|
||||
},
|
||||
"logging": {
|
||||
"level": "INFO",
|
||||
"file": null,
|
||||
"max_bytes": null,
|
||||
"backup_count": 3
|
||||
},
|
||||
"backup": {
|
||||
"enabled": false,
|
||||
"path": "data/backups",
|
||||
"keep_days": 30
|
||||
},
|
||||
"other": {
|
||||
"master_password_hash": "$pbkdf2-sha256$29000$EUKI8d67d86ZE.K8VypF6A$4mqRLeh3WL2AsHFXNET.1D9T.weMNIE5Ffw6cIgA4ho"
|
||||
},
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "Aniworld",
|
||||
"data_dir": "data",
|
||||
"scheduler": {
|
||||
"enabled": true,
|
||||
"interval_minutes": 60
|
||||
},
|
||||
"logging": {
|
||||
"level": "INFO",
|
||||
"file": null,
|
||||
"max_bytes": null,
|
||||
"backup_count": 3
|
||||
},
|
||||
"backup": {
|
||||
"enabled": false,
|
||||
"path": "data/backups",
|
||||
"keep_days": 30
|
||||
},
|
||||
"other": {
|
||||
"master_password_hash": "$pbkdf2-sha256$29000$VooRQui9t/beGwMAgNAaQw$idnI9fpdgl0hAd7susBuX6rpux/L/k4PJ1QMQfjwpvo"
|
||||
},
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "Aniworld",
|
||||
"data_dir": "data",
|
||||
"scheduler": {
|
||||
"enabled": true,
|
||||
"interval_minutes": 60
|
||||
},
|
||||
"logging": {
|
||||
"level": "INFO",
|
||||
"file": null,
|
||||
"max_bytes": null,
|
||||
"backup_count": 3
|
||||
},
|
||||
"backup": {
|
||||
"enabled": false,
|
||||
"path": "data/backups",
|
||||
"keep_days": 30
|
||||
},
|
||||
"other": {
|
||||
"master_password_hash": "$pbkdf2-sha256$29000$/x8jxFgLofQegzAm5DzHeA$kO44/L.4b3sEDOCuzJkunefAZ9ap5jsFZP/JDaRIUt0"
|
||||
},
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "Aniworld",
|
||||
"data_dir": "data",
|
||||
"scheduler": {
|
||||
"enabled": true,
|
||||
"interval_minutes": 60
|
||||
},
|
||||
"logging": {
|
||||
"level": "INFO",
|
||||
"file": null,
|
||||
"max_bytes": null,
|
||||
"backup_count": 3
|
||||
},
|
||||
"backup": {
|
||||
"enabled": false,
|
||||
"path": "data/backups",
|
||||
"keep_days": 30
|
||||
},
|
||||
"other": {
|
||||
"master_password_hash": "$pbkdf2-sha256$29000$htA6x1jrHYPwvre2FkJoTQ$37rrE4hOMgdowfzS9XaaH/EjPDZZFSlc0RL1blcXEVU"
|
||||
},
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "Aniworld",
|
||||
"data_dir": "data",
|
||||
"scheduler": {
|
||||
"enabled": true,
|
||||
"interval_minutes": 60
|
||||
},
|
||||
"logging": {
|
||||
"level": "INFO",
|
||||
"file": null,
|
||||
"max_bytes": null,
|
||||
"backup_count": 3
|
||||
},
|
||||
"backup": {
|
||||
"enabled": false,
|
||||
"path": "data/backups",
|
||||
"keep_days": 30
|
||||
},
|
||||
"other": {
|
||||
"master_password_hash": "$pbkdf2-sha256$29000$.t.bk1IKQah1bg0BoNS6tw$TbbOVxdX4U7xhiRPPyJM6cXl5EnVzlM/3YMZF714Aoc"
|
||||
},
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@ -17,7 +17,7 @@
|
||||
"keep_days": 30
|
||||
},
|
||||
"other": {
|
||||
"master_password_hash": "$pbkdf2-sha256$29000$F0JIKQWAEEJoba3VGuOckw$ae64QkQc0QkMiSiO3H3Bg8mZE5nOQ8hrN5gl9LQLjnw"
|
||||
"master_password_hash": "$pbkdf2-sha256$29000$JWTsXWstZYyxNiYEQAihFA$K9QPNr2J9biZEX/7SFKU94dnynvyCICrGjKtZcEu6t8"
|
||||
},
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@ -166,22 +166,22 @@ All series-related WebSocket events include `key` as the primary identifier in t
|
||||
|
||||
### DownloadQueueItem Fields
|
||||
|
||||
| Field | Type | Purpose |
|
||||
| -------------- | ----------- | --------------------------------------------- |
|
||||
| `id` | String (PK) | UUID for the queue item |
|
||||
| `serie_id` | String | Series key for identification |
|
||||
| `serie_folder` | String | Filesystem folder path |
|
||||
| `serie_name` | String | Display name for the series |
|
||||
| `season` | Integer | Season number |
|
||||
| `episode` | Integer | Episode number |
|
||||
| `status` | Enum | pending, downloading, completed, failed |
|
||||
| `priority` | Enum | low, normal, high |
|
||||
| `progress` | Float | Download progress percentage (0.0-100.0) |
|
||||
| `error` | String | Error message if failed |
|
||||
| `retry_count` | Integer | Number of retry attempts |
|
||||
| `added_at` | DateTime | When item was added to queue |
|
||||
| `started_at` | DateTime | When download started (nullable) |
|
||||
| `completed_at` | DateTime | When download completed/failed (nullable) |
|
||||
| Field | Type | Purpose |
|
||||
| -------------- | ----------- | ----------------------------------------- |
|
||||
| `id` | String (PK) | UUID for the queue item |
|
||||
| `serie_id` | String | Series key for identification |
|
||||
| `serie_folder` | String | Filesystem folder path |
|
||||
| `serie_name` | String | Display name for the series |
|
||||
| `season` | Integer | Season number |
|
||||
| `episode` | Integer | Episode number |
|
||||
| `status` | Enum | pending, downloading, completed, failed |
|
||||
| `priority` | Enum | low, normal, high |
|
||||
| `progress` | Float | Download progress percentage (0.0-100.0) |
|
||||
| `error` | String | Error message if failed |
|
||||
| `retry_count` | Integer | Number of retry attempts |
|
||||
| `added_at` | DateTime | When item was added to queue |
|
||||
| `started_at` | DateTime | When download started (nullable) |
|
||||
| `completed_at` | DateTime | When download completed/failed (nullable) |
|
||||
|
||||
## Data Storage
|
||||
|
||||
@ -189,13 +189,13 @@ All series-related WebSocket events include `key` as the primary identifier in t
|
||||
|
||||
The application uses **SQLite database** as the primary storage for all application data.
|
||||
|
||||
| Data Type | Storage Location | Service |
|
||||
| --------------- | ------------------ | ---------------------------- |
|
||||
| Anime Series | `data/aniworld.db` | `AnimeSeriesService` |
|
||||
| Episodes | `data/aniworld.db` | `AnimeSeriesService` |
|
||||
| Download Queue | `data/aniworld.db` | `DownloadService` via `QueueRepository` |
|
||||
| User Sessions | `data/aniworld.db` | `AuthService` |
|
||||
| Configuration | `data/config.json` | `ConfigService` |
|
||||
| Data Type | Storage Location | Service |
|
||||
| -------------- | ------------------ | --------------------------------------- |
|
||||
| Anime Series | `data/aniworld.db` | `AnimeSeriesService` |
|
||||
| Episodes | `data/aniworld.db` | `AnimeSeriesService` |
|
||||
| Download Queue | `data/aniworld.db` | `DownloadService` via `QueueRepository` |
|
||||
| User Sessions | `data/aniworld.db` | `AuthService` |
|
||||
| Configuration | `data/config.json` | `ConfigService` |
|
||||
|
||||
### Download Queue Storage
|
||||
|
||||
@ -219,11 +219,12 @@ await repository.update_progress(item_id, progress=45.5, downloaded=450, total=1
|
||||
```
|
||||
|
||||
**Queue Persistence Features:**
|
||||
- Queue state survives server restarts
|
||||
- Items in `downloading` status are reset to `pending` on startup
|
||||
- Failed items within retry limit are automatically re-queued
|
||||
- Completed and failed history is preserved (with limits)
|
||||
- Real-time progress updates are persisted to database
|
||||
|
||||
- Queue state survives server restarts
|
||||
- Items in `downloading` status are reset to `pending` on startup
|
||||
- Failed items within retry limit are automatically re-queued
|
||||
- Completed and failed history is preserved (with limits)
|
||||
- Real-time progress updates are persisted to database
|
||||
|
||||
### Anime Series Database Storage
|
||||
|
||||
|
||||
@ -125,20 +125,21 @@ For each task completed:
|
||||
|
||||
The download queue has been successfully migrated from JSON file to SQLite database:
|
||||
|
||||
| Component | Status | Description |
|
||||
| ---------------------- | --------- | ------------------------------------------------ |
|
||||
| QueueRepository | ✅ Done | `src/server/services/queue_repository.py` |
|
||||
| DownloadService | ✅ Done | Refactored to use repository pattern |
|
||||
| Application Startup | ✅ Done | Queue restored from database on startup |
|
||||
| API Endpoints | ✅ Done | All endpoints work with database-backed queue |
|
||||
| Tests Updated | ✅ Done | All 1104 tests passing with MockQueueRepository |
|
||||
| Documentation Updated | ✅ Done | `infrastructure.md` updated with new architecture|
|
||||
| Component | Status | Description |
|
||||
| --------------------- | ------- | ------------------------------------------------- |
|
||||
| QueueRepository | ✅ Done | `src/server/services/queue_repository.py` |
|
||||
| DownloadService | ✅ Done | Refactored to use repository pattern |
|
||||
| Application Startup | ✅ Done | Queue restored from database on startup |
|
||||
| API Endpoints | ✅ Done | All endpoints work with database-backed queue |
|
||||
| Tests Updated | ✅ Done | All 1104 tests passing with MockQueueRepository |
|
||||
| Documentation Updated | ✅ Done | `infrastructure.md` updated with new architecture |
|
||||
|
||||
**Key Changes:**
|
||||
- `DownloadService` no longer uses `persistence_path` parameter
|
||||
- Queue state is persisted to SQLite via `QueueRepository`
|
||||
- In-memory cache maintained for performance
|
||||
- All tests use `MockQueueRepository` fixture
|
||||
|
||||
- `DownloadService` no longer uses `persistence_path` parameter
|
||||
- Queue state is persisted to SQLite via `QueueRepository`
|
||||
- In-memory cache maintained for performance
|
||||
- All tests use `MockQueueRepository` fixture
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -113,11 +113,21 @@ async def lifespan(app: FastAPI):
|
||||
progress_service.subscribe("progress_updated", progress_event_handler)
|
||||
|
||||
# Initialize download service and restore queue from database
|
||||
# Only if anime directory is configured
|
||||
try:
|
||||
from src.server.config.settings import settings
|
||||
|
||||
from src.server.utils.dependencies import get_download_service
|
||||
download_service = get_download_service()
|
||||
await download_service.initialize()
|
||||
logger.info("Download service initialized and queue restored")
|
||||
|
||||
if settings.anime_directory:
|
||||
download_service = get_download_service()
|
||||
await download_service.initialize()
|
||||
logger.info("Download service initialized and queue restored")
|
||||
else:
|
||||
logger.info(
|
||||
"Download service initialization skipped - "
|
||||
"anime directory not configured"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to initialize download service: %s", e)
|
||||
# Continue startup - download service can be initialized later
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user