NoDataFile #1
@ -4,11 +4,14 @@ from typing import Any, List, Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from pydantic import BaseModel, Field
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from src.core.entities.series import Serie
|
||||
from src.server.database.service import AnimeSeriesService
|
||||
from src.server.services.anime_service import AnimeService, AnimeServiceError
|
||||
from src.server.utils.dependencies import (
|
||||
get_anime_service,
|
||||
get_optional_database_session,
|
||||
get_series_app,
|
||||
require_auth,
|
||||
)
|
||||
@ -582,6 +585,7 @@ async def add_series(
|
||||
request: AddSeriesRequest,
|
||||
_auth: dict = Depends(require_auth),
|
||||
series_app: Any = Depends(get_series_app),
|
||||
db: Optional[AsyncSession] = Depends(get_optional_database_session),
|
||||
) -> dict:
|
||||
"""Add a new series to the library.
|
||||
|
||||
@ -589,6 +593,9 @@ async def add_series(
|
||||
The `key` is the URL-safe identifier used for all lookups.
|
||||
The `name` is stored as display metadata along with a
|
||||
filesystem-friendly `folder` name derived from the name.
|
||||
|
||||
Series are saved to the database using AnimeSeriesService when
|
||||
database is available, falling back to in-memory storage otherwise.
|
||||
|
||||
Args:
|
||||
request: Request containing the series link and name.
|
||||
@ -596,9 +603,10 @@ async def add_series(
|
||||
- name: Display name for the series
|
||||
_auth: Ensures the caller is authenticated (value unused)
|
||||
series_app: Core `SeriesApp` instance provided via dependency
|
||||
db: Optional database session for async operations
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Status payload with success message and key
|
||||
Dict[str, Any]: Status payload with success message, key, and db_id
|
||||
|
||||
Raises:
|
||||
HTTPException: If adding the series fails or link is invalid
|
||||
@ -617,13 +625,6 @@ async def add_series(
|
||||
detail="Series name cannot be empty",
|
||||
)
|
||||
|
||||
# Check if series_app has the list attribute
|
||||
if not hasattr(series_app, "list"):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_501_NOT_IMPLEMENTED,
|
||||
detail="Series list functionality not available",
|
||||
)
|
||||
|
||||
# Extract key from link URL
|
||||
# Expected format: https://aniworld.to/anime/stream/{key}
|
||||
link = request.link.strip()
|
||||
@ -646,36 +647,69 @@ async def add_series(
|
||||
|
||||
# Create folder from name (filesystem-friendly)
|
||||
folder = request.name.strip()
|
||||
db_id = None
|
||||
|
||||
# Create a new Serie object
|
||||
# key: unique identifier extracted from link
|
||||
# name: display name from request
|
||||
# folder: filesystem folder name (derived from name)
|
||||
# episodeDict: empty for new series
|
||||
serie = Serie(
|
||||
key=key,
|
||||
name=request.name.strip(),
|
||||
site="aniworld.to",
|
||||
folder=folder,
|
||||
episodeDict={}
|
||||
)
|
||||
# Try to save to database if available
|
||||
if db is not None:
|
||||
# Check if series already exists in database
|
||||
existing = await AnimeSeriesService.get_by_key(db, key)
|
||||
if existing:
|
||||
return {
|
||||
"status": "exists",
|
||||
"message": f"Series already exists: {request.name}",
|
||||
"key": key,
|
||||
"folder": existing.folder,
|
||||
"db_id": existing.id
|
||||
}
|
||||
|
||||
# Save to database using AnimeSeriesService
|
||||
anime_series = await AnimeSeriesService.create(
|
||||
db=db,
|
||||
key=key,
|
||||
name=request.name.strip(),
|
||||
site="aniworld.to",
|
||||
folder=folder,
|
||||
episode_dict={}, # Empty for new series
|
||||
)
|
||||
db_id = anime_series.id
|
||||
|
||||
logger.info(
|
||||
"Added series to database: %s (key=%s, db_id=%d)",
|
||||
request.name,
|
||||
key,
|
||||
db_id
|
||||
)
|
||||
|
||||
# Add the series to the list
|
||||
series_app.list.add(serie)
|
||||
|
||||
# Refresh the series list to update the cache
|
||||
if hasattr(series_app, "refresh_series_list"):
|
||||
series_app.refresh_series_list()
|
||||
# Also add to in-memory cache if series_app has the list attribute
|
||||
if series_app and hasattr(series_app, "list"):
|
||||
serie = Serie(
|
||||
key=key,
|
||||
name=request.name.strip(),
|
||||
site="aniworld.to",
|
||||
folder=folder,
|
||||
episodeDict={}
|
||||
)
|
||||
# Add to in-memory cache
|
||||
if hasattr(series_app.list, 'keyDict'):
|
||||
# Direct update without file saving
|
||||
series_app.list.keyDict[key] = serie
|
||||
elif hasattr(series_app.list, 'add'):
|
||||
# Legacy: use add method (may create file with deprecation warning)
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore", DeprecationWarning)
|
||||
series_app.list.add(serie)
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"message": f"Successfully added series: {request.name}",
|
||||
"key": key,
|
||||
"folder": folder
|
||||
"folder": folder,
|
||||
"db_id": db_id
|
||||
}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as exc:
|
||||
logger.error("Failed to add series: %s", exc, exc_info=True)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to add series: {str(exc)}",
|
||||
|
||||
@ -134,6 +134,38 @@ async def get_database_session() -> AsyncGenerator:
|
||||
)
|
||||
|
||||
|
||||
async def get_optional_database_session() -> AsyncGenerator:
|
||||
"""
|
||||
Dependency to get optional database session.
|
||||
|
||||
Unlike get_database_session(), this returns None if the database
|
||||
is not available, allowing endpoints to fall back to other storage.
|
||||
|
||||
Yields:
|
||||
AsyncSession or None: Database session if available, None otherwise
|
||||
|
||||
Example:
|
||||
@app.post("/anime/add")
|
||||
async def add_anime(
|
||||
db: Optional[AsyncSession] = Depends(get_optional_database_session)
|
||||
):
|
||||
if db:
|
||||
# Use database
|
||||
await AnimeSeriesService.create(db, ...)
|
||||
else:
|
||||
# Fall back to file-based storage
|
||||
series_app.list.add(serie)
|
||||
"""
|
||||
try:
|
||||
from src.server.database import get_db_session
|
||||
|
||||
async with get_db_session() as session:
|
||||
yield session
|
||||
except (ImportError, RuntimeError):
|
||||
# Database not available - yield None
|
||||
yield None
|
||||
|
||||
|
||||
def get_current_user(
|
||||
credentials: Optional[HTTPAuthorizationCredentials] = Depends(
|
||||
http_bearer_security
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user