Files
manage/backend/src/media_library_viewer_api/routers/media.py
T
alex 51b10438a9 Restructure into backend/ and frontend/ subprojects
- backend/ uses proper Python src layout (src/media_library_viewer_api/)
  with pyproject.toml, hatchling build, and PYTHONPATH=src convention
- frontend/ is a Vite + React + TypeScript SPA
- archive/ preserves the original Streamlit prototype for reference
- Cleaned up root to only contain docs, license, and subproject dirs
- Updated README for the new dual-subproject architecture
2026-04-30 21:48:46 +02:00

85 lines
2.9 KiB
Python

"""Media router — index status, build, and query."""
from __future__ import annotations
from typing import Any
from fastapi import APIRouter, Depends, Query
from media_library_viewer_api.dependencies import get_jellyfin_client, get_user_id
from media_library_viewer_api.clients.jellyfin import JellyfinClient
from media_library_viewer_api.services.media_index import MediaIndex, build_media_index
router = APIRouter(prefix="/api/media", tags=["media"])
def get_media_index() -> MediaIndex:
return MediaIndex()
@router.get("/status")
def get_index_status(index: MediaIndex = Depends(get_media_index)) -> dict[str, Any]:
"""Return media index status (exists, count, last updated, build duration)."""
status = index.status()
return {
"exists": status.exists,
"item_count": status.item_count,
"updated_at": status.updated_at,
"updated_at_label": status.updated_at_label,
"build_duration_seconds": status.build_duration_seconds,
}
@router.post("/build")
def post_build_index(
client: JellyfinClient = Depends(get_jellyfin_client),
user_id: str = Depends(get_user_id),
index: MediaIndex = Depends(get_media_index),
) -> dict[str, Any]:
"""Rebuild the media index from Jellyfin."""
libraries = client.libraries(user_id)
count = build_media_index(client, user_id, libraries, index)
return {"indexed_items": count}
@router.get("/query")
def query_media(
libraries: str = Query("", description="Comma-separated library IDs"),
types: str = Query("Movie,Episode", description="Comma-separated media types"),
search: str = Query("", description="Search term"),
hdr_filter: str = Query("All", description="All, HDR only, SDR/unknown only"),
sort_key: str = Query("title", description="Sort field"),
sort_order: str = Query("Ascending", description="Ascending or Descending"),
limit: int = Query(100, ge=1, le=1000),
offset: int = Query(0, ge=0),
client: JellyfinClient = Depends(get_jellyfin_client),
user_id: str = Depends(get_user_id),
index: MediaIndex = Depends(get_media_index),
) -> dict[str, Any]:
"""Query the media index with filters, sorting, and pagination."""
# If no library IDs provided, use all libraries
library_ids = [lid.strip() for lid in libraries.split(",") if lid.strip()] if libraries else None
if not library_ids:
all_libs = client.libraries(user_id)
library_ids = [lib["Id"] for lib in all_libs]
media_types = [t.strip() for t in types.split(",") if t.strip()]
rows, total = index.query(
library_ids=library_ids,
media_types=media_types,
search=search,
hdr_filter=hdr_filter,
sort_key=sort_key,
sort_order=sort_order,
limit=limit,
offset=offset,
)
return {
"items": rows,
"total": total,
"limit": limit,
"offset": offset,
}