feat: frontend modernization with HTMX, Alpine.js and Plyr (Phase 3)
- Integrated HTMX for server-driven UI updates and fragments - Adopted Alpine.js for global reactive state and tab management - Replaced legacy player with Plyr.io for premium streaming experience - Implemented real-time download polling via HTMX - Added server-sent Toast notification system - Fixed navigation and authentication scoping issues
This commit is contained in:
+19
-21
@@ -1,20 +1,5 @@
|
||||
"""
|
||||
Anime and series search routes for Ohm Stream Downloader API.
|
||||
|
||||
Endpoints:
|
||||
- GET /api/anime/search - Search across all anime providers (Modernized with Kitsu)
|
||||
- GET /api/series/search - Search across all TV series providers
|
||||
- GET /api/anime/metadata - Get detailed metadata for a specific anime
|
||||
- GET /api/anime/episodes - Get list of episodes for an anime
|
||||
- GET /api/anime/providers - Get list of anime providers
|
||||
- GET /api/providers/health - Get provider health status
|
||||
- POST /api/providers/health/check - Trigger health check
|
||||
- POST /api/anime/download - Download an anime episode
|
||||
- POST /api/anime/download-season - Download all episodes of a season
|
||||
- GET /api/anime/seasons - Get list of seasons for an anime
|
||||
- GET /api/anime/mal/search - Search for anime on MyAnimeList
|
||||
- GET /api/anime/mal/{mal_id} - Get full details by MyAnimeList ID
|
||||
- POST /api/translate - Translate text from English to French
|
||||
"""
|
||||
|
||||
import json
|
||||
@@ -22,8 +7,10 @@ import re
|
||||
import time
|
||||
import logging
|
||||
import asyncio
|
||||
import hashlib
|
||||
|
||||
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Request
|
||||
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Request, Response
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
from app.download_manager import DownloadManager
|
||||
from app.downloaders import (
|
||||
@@ -40,6 +27,13 @@ from app.metadata_enrichment import get_metadata_enricher
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/api", tags=["anime"])
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
# Add custom filters to Jinja2
|
||||
def hash_filter(s):
|
||||
return hashlib.md5(s.encode()).hexdigest()[:10]
|
||||
|
||||
templates.env.filters["hash"] = hash_filter
|
||||
|
||||
|
||||
@router.get("/providers/health")
|
||||
@@ -67,6 +61,7 @@ def get_download_manager() -> DownloadManager:
|
||||
|
||||
@router.get("/anime/search")
|
||||
async def search_anime_unified(
|
||||
request: Request,
|
||||
q: str,
|
||||
lang: str = "vostfr",
|
||||
include_metadata: bool = False,
|
||||
@@ -74,6 +69,7 @@ async def search_anime_unified(
|
||||
"""
|
||||
Search across all anime providers using MetadataEnricher and health checks.
|
||||
Results are grouped by provider for legacy UI compatibility.
|
||||
Returns HTML for HTMX requests.
|
||||
"""
|
||||
print(f"\n[SEARCH] Starting modern unified search for '{q}' in {lang}")
|
||||
start_time = time.time()
|
||||
@@ -87,7 +83,6 @@ async def search_anime_unified(
|
||||
# Generic YAML providers
|
||||
active_generic = providers_manager.get_active_providers()
|
||||
for provider in active_generic:
|
||||
print(f"[SEARCH] Queueing generic provider: {provider.name}")
|
||||
search_tasks.append(provider.search(q))
|
||||
task_metadata.append({"id": provider.id, "type": "generic"})
|
||||
|
||||
@@ -98,20 +93,16 @@ async def search_anime_unified(
|
||||
"vostfree": VostfreeDownloader(),
|
||||
}
|
||||
for pid, dl in legacy_downloaders.items():
|
||||
print(f"[SEARCH] Queueing legacy provider: {pid}")
|
||||
search_tasks.append(dl.search_anime(q, lang, include_metadata=False))
|
||||
task_metadata.append({"id": pid, "type": "legacy"})
|
||||
|
||||
# 2. Run searches in parallel
|
||||
print(f"[SEARCH] Waiting for {len(search_tasks)} provider results...")
|
||||
all_raw_results = await asyncio.gather(*search_tasks, return_exceptions=True)
|
||||
|
||||
# 3. Organize results by provider
|
||||
seen_urls = set()
|
||||
enricher = await get_metadata_enricher()
|
||||
enrichment_tasks = []
|
||||
|
||||
# Map task indices to result slots for re-injection after enrichment
|
||||
enrichment_mapping = [] # List of (provider_id, index_in_provider_results)
|
||||
|
||||
for i, raw_result in enumerate(all_raw_results):
|
||||
@@ -180,6 +171,13 @@ async def search_anime_unified(
|
||||
total_found = sum(len(r) for r in results.values())
|
||||
print(f"[SEARCH] Finished in {elapsed:.2f}s. Found {total_found} unique results across {len(results)} providers.")
|
||||
|
||||
# 6. Return HTML for HTMX or JSON for API
|
||||
if request.headers.get("HX-Request"):
|
||||
return templates.TemplateResponse(
|
||||
"components/anime_search_results.html",
|
||||
{"request": request, "results": results}
|
||||
)
|
||||
|
||||
return {
|
||||
"query": q,
|
||||
"lang": lang,
|
||||
|
||||
Reference in New Issue
Block a user