feat: add Settings tab with provider management and language preferences
- Implemented AppSettings model and table using SQLModel. - Created Settings router with endpoints for preferences and provider toggling. - Added Settings tab to the UI with real-time health status of providers. - Integrated language and provider filtering into anime and series search logic. - Updated templates to respect user-defined settings.
This commit is contained in:
@@ -11,7 +11,12 @@ import hashlib
|
||||
|
||||
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Request, Response
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from app.database import get_session
|
||||
from app.models.settings import AppSettingsTable
|
||||
from app.routers.router_auth import get_current_user_from_token
|
||||
from app.models.auth import User
|
||||
from app.download_manager import DownloadManager
|
||||
from app.downloaders import (
|
||||
AnimeSamaDownloader,
|
||||
@@ -67,6 +72,8 @@ async def search_anime_unified(
|
||||
lang: str = "vostfr",
|
||||
include_metadata: bool = False,
|
||||
html: bool = Query(False),
|
||||
current_user: User = Depends(get_current_user_from_token),
|
||||
session: Session = Depends(get_session)
|
||||
):
|
||||
"""
|
||||
Search across all anime providers.
|
||||
@@ -75,6 +82,11 @@ async def search_anime_unified(
|
||||
print(f"\n[SEARCH] Starting search for '{q}'. html={html}")
|
||||
start_time = time.time()
|
||||
|
||||
# Get user settings for disabled providers
|
||||
statement = select(AppSettingsTable).where(AppSettingsTable.user_id == current_user.id)
|
||||
settings_obj = session.exec(statement).first()
|
||||
disabled_providers = settings_obj.disabled_providers if settings_obj else []
|
||||
|
||||
results = {}
|
||||
|
||||
# 1. Prepare search tasks (Generic + Legacy)
|
||||
@@ -84,8 +96,9 @@ async def search_anime_unified(
|
||||
# Generic YAML providers
|
||||
active_generic = providers_manager.get_active_providers()
|
||||
for provider in active_generic:
|
||||
search_tasks.append(provider.search(q))
|
||||
task_metadata.append({"id": provider.id, "type": "generic"})
|
||||
if provider.id not in disabled_providers:
|
||||
search_tasks.append(provider.search(q))
|
||||
task_metadata.append({"id": provider.id, "type": "generic"})
|
||||
|
||||
# Legacy providers
|
||||
legacy_downloaders = {
|
||||
@@ -94,8 +107,9 @@ async def search_anime_unified(
|
||||
"vostfree": VostfreeDownloader(),
|
||||
}
|
||||
for pid, dl in legacy_downloaders.items():
|
||||
search_tasks.append(dl.search_anime(q, lang, include_metadata=False))
|
||||
task_metadata.append({"id": pid, "type": "legacy"})
|
||||
if pid not in disabled_providers:
|
||||
search_tasks.append(dl.search_anime(q, lang, include_metadata=False))
|
||||
task_metadata.append({"id": pid, "type": "legacy"})
|
||||
|
||||
# 2. Run searches in parallel
|
||||
all_raw_results = await asyncio.gather(*search_tasks, return_exceptions=True)
|
||||
@@ -163,7 +177,11 @@ async def search_anime_unified(
|
||||
print("[SEARCH] Returning HTML response")
|
||||
return templates.TemplateResponse(
|
||||
"components/anime_search_results.html",
|
||||
{"request": request, "results": results}
|
||||
{
|
||||
"request": request,
|
||||
"results": results,
|
||||
"settings": settings_obj
|
||||
}
|
||||
)
|
||||
|
||||
print("[SEARCH] Returning JSON response")
|
||||
@@ -181,6 +199,8 @@ async def search_series_unified(
|
||||
q: str,
|
||||
lang: str = "vf",
|
||||
html: bool = Query(False),
|
||||
current_user: User = Depends(get_current_user_from_token),
|
||||
session: Session = Depends(get_session)
|
||||
):
|
||||
"""
|
||||
Search across all TV series providers (FS7, etc.)
|
||||
@@ -191,6 +211,12 @@ async def search_series_unified(
|
||||
|
||||
print(f"\n[SERIES SEARCH] Starting search for '{q}' in {lang}. html={html}")
|
||||
start_time = time.time()
|
||||
|
||||
# Get user settings for disabled providers
|
||||
statement = select(AppSettingsTable).where(AppSettingsTable.user_id == current_user.id)
|
||||
settings_obj = session.exec(statement).first()
|
||||
disabled_providers = settings_obj.disabled_providers if settings_obj else []
|
||||
|
||||
results = {}
|
||||
series_downloaders = {
|
||||
"fs7": FS7Downloader(),
|
||||
@@ -200,7 +226,7 @@ async def search_series_unified(
|
||||
provider_ids = []
|
||||
|
||||
for provider_id, provider in get_series_providers().items():
|
||||
if provider_id in series_downloaders:
|
||||
if provider_id in series_downloaders and provider_id not in disabled_providers:
|
||||
downloader = series_downloaders[provider_id]
|
||||
search_tasks.append(downloader.search_anime(q, lang))
|
||||
provider_ids.append(provider_id)
|
||||
@@ -221,7 +247,11 @@ async def search_series_unified(
|
||||
if html or request.headers.get("HX-Request"):
|
||||
return templates.TemplateResponse(
|
||||
"components/series_search_results.html",
|
||||
{"request": request, "results": results}
|
||||
{
|
||||
"request": request,
|
||||
"results": results,
|
||||
"settings": settings_obj
|
||||
}
|
||||
)
|
||||
|
||||
return {"query": q, "lang": lang, "results": results}
|
||||
|
||||
Reference in New Issue
Block a user