# routers/search.py from fastapi import APIRouter, Query from fastapi.concurrency import run_in_threadpool from pydantic import BaseModel from ..search.search_client import videos_index router = APIRouter(prefix="/search", tags=["search"]) class VideoHit(BaseModel): id: int title: str filename: str date: str | None channel_id: int channel_name: str playlist_id: int | None playlist_name: str | None preview_path: str _formatted: dict | None = None class SearchResponse(BaseModel): query: str total: int took_ms: int items: list[VideoHit] @router.get("/videos", response_model=SearchResponse) async def search_videos( q: str = Query("", max_length=200, description="Поисковый запрос; пусто = показать всё"), channel_id: int | None = None, playlist_id: int | None = None, date_from: str | None = Query(None, pattern=r"^\d{4}-\d{2}-\d{2}$"), date_to: str | None = Query(None, pattern=r"^\d{4}-\d{2}-\d{2}$"), sort: str | None = Query(None, description="date:desc | date:asc | id:desc"), limit: int = Query(20, le=100), offset: int = Query(0, ge=0), ): filters = [] if channel_id is not None: filters.append(f"channel_id = {channel_id}") if playlist_id is not None: filters.append(f"playlist_id = {playlist_id}") if date_from: filters.append(f'date >= "{date_from}"') if date_to: filters.append(f'date <= "{date_to}"') params = { "limit": limit, "offset": offset, "attributesToHighlight": ["title", "filename"], "highlightPreTag": "", "highlightPostTag": "", } if filters: params["filter"] = " AND ".join(filters) if sort: params["sort"] = [sort] result = await run_in_threadpool(videos_index().search, q, params) return { "query": q, "total": result["estimatedTotalHits"], "took_ms": result["processingTimeMs"], "items": result["hits"], }