feat: Implement download queue API endpoints

- Add comprehensive REST API for download queue management
- Implement GET /api/queue/status endpoint with queue status and statistics
- Implement POST /api/queue/add for adding episodes to queue with priority support
- Implement DELETE /api/queue/{id} and DELETE /api/queue/ for removing items
- Implement POST /api/queue/start and /api/queue/stop for queue control
- Implement POST /api/queue/pause and /api/queue/resume for pause/resume
- Implement POST /api/queue/reorder for queue item reordering
- Implement DELETE /api/queue/completed for clearing completed items
- Implement POST /api/queue/retry for retrying failed downloads
- Add get_download_service and get_anime_service dependencies
- Register download router in FastAPI application
- Add comprehensive test suite for all endpoints
- All endpoints require JWT authentication
- Update infrastructure documentation
- Remove completed task from instructions.md

Follows REST conventions with proper error handling and status codes.
Tests cover success cases, error conditions, and authentication requirements.
This commit is contained in:
2025-10-17 10:29:03 +02:00
parent 028d91283e
commit 577c55f32a
6 changed files with 1105 additions and 16 deletions

View File

@@ -2,8 +2,8 @@
Dependency injection utilities for FastAPI.
This module provides dependency injection functions for the FastAPI
application, including SeriesApp instances, database sessions, and
authentication dependencies.
application, including SeriesApp instances, AnimeService, DownloadService,
database sessions, and authentication dependencies.
"""
from typing import AsyncGenerator, Optional
@@ -26,6 +26,10 @@ security = HTTPBearer()
# Global SeriesApp instance
_series_app: Optional[SeriesApp] = None
# Global service instances
_anime_service: Optional[object] = None
_download_service: Optional[object] = None
def get_series_app() -> SeriesApp:
"""
@@ -193,3 +197,79 @@ async def log_request_dependency():
TODO: Implement request logging logic
"""
pass
def get_anime_service() -> object:
"""
Dependency to get AnimeService instance.
Returns:
AnimeService: The anime service for async operations
Raises:
HTTPException: If anime directory is not configured or
AnimeService initialization fails
"""
global _anime_service
if not settings.anime_directory:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Anime directory not configured. Please complete setup.",
)
if _anime_service is None:
try:
from src.server.services.anime_service import AnimeService
_anime_service = AnimeService(settings.anime_directory)
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to initialize AnimeService: {str(e)}",
) from e
return _anime_service
def get_download_service() -> object:
"""
Dependency to get DownloadService instance.
Returns:
DownloadService: The download queue service
Raises:
HTTPException: If DownloadService initialization fails
"""
global _download_service
if _download_service is None:
try:
from src.server.services.download_service import DownloadService
# Get anime service first (required dependency)
anime_service = get_anime_service()
# Initialize download service with anime service
_download_service = DownloadService(anime_service)
except HTTPException:
raise
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to initialize DownloadService: {str(e)}",
) from e
return _download_service
def reset_anime_service() -> None:
"""Reset global AnimeService instance (for testing/config changes)."""
global _anime_service
_anime_service = None
def reset_download_service() -> None:
"""Reset global DownloadService instance (for testing/config changes)."""
global _download_service
_download_service = None