123 lines
4.0 KiB
Python
123 lines
4.0 KiB
Python
"""API galerie admin — impression et suppression de photos."""
|
|
|
|
import logging
|
|
from fastapi import APIRouter, Request, Query
|
|
from fastapi.responses import JSONResponse, RedirectResponse
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/admin/api/gallery/photos")
|
|
async def admin_get_photos(
|
|
request: Request,
|
|
page: int = Query(default=1, ge=1),
|
|
limit: int = Query(default=24, ge=1, le=100),
|
|
):
|
|
"""Liste des photos pour la galerie admin."""
|
|
if not request.session.get("authenticated"):
|
|
return JSONResponse({"error": "Non authentifié"}, status_code=401)
|
|
|
|
pb = request.app.state.photobooth_service
|
|
all_photos = await pb.get_media_collection(limit=500)
|
|
photos = [p for p in all_photos if _is_image(p)]
|
|
|
|
total = len(photos)
|
|
start = (page - 1) * limit
|
|
page_photos = photos[start:start + limit]
|
|
|
|
for p in page_photos:
|
|
pid = _get_id(p)
|
|
p["full_url"] = pb.media_url(pid)
|
|
p["thumb_url"] = pb.thumbnail_url(pid)
|
|
|
|
return {"photos": page_photos, "total": total, "page": page,
|
|
"pages": max(1, (total + limit - 1) // limit)}
|
|
|
|
|
|
@router.post("/admin/api/gallery/print/{photo_id}")
|
|
async def admin_print_photo(
|
|
request: Request,
|
|
photo_id: str,
|
|
copies: int = Query(default=1, ge=1, le=3),
|
|
):
|
|
"""Impression directe depuis la galerie admin."""
|
|
if not request.session.get("authenticated"):
|
|
return JSONResponse({"error": "Non authentifié"}, status_code=401)
|
|
|
|
pb = request.app.state.photobooth_service
|
|
printer_svc = request.app.state.printer_service
|
|
led = request.app.state.led_service
|
|
ws = request.app.state.ws_manager
|
|
|
|
# Reconstruit le chemin du fichier depuis l'ID
|
|
from pathlib import Path
|
|
import re
|
|
cfg = request.app.state.config
|
|
|
|
# photobooth-app identifiant → chemin fichier
|
|
media_dir = cfg.photobooth.media_dir
|
|
# Cherche le fichier correspondant
|
|
filename = _find_file(media_dir, photo_id)
|
|
if not filename:
|
|
return JSONResponse({"error": f"Fichier introuvable pour {photo_id}"}, status_code=404)
|
|
|
|
thumb_url = pb.thumbnail_url(photo_id)
|
|
entry = await printer_svc.add_request(str(filename), thumb_url, copies)
|
|
|
|
if cfg.print.mode == "direct":
|
|
led.play("printing")
|
|
result = await printer_svc.execute_print(entry["id"], copies)
|
|
await ws.broadcast({"type": "print_result", "result": result})
|
|
if result["success"]:
|
|
led.play("finished")
|
|
else:
|
|
led.play("error")
|
|
return result
|
|
|
|
await ws.broadcast({"type": "print_request", "entry": entry})
|
|
return {"ok": True, "entry": entry, "mode": cfg.print.mode}
|
|
|
|
|
|
@router.delete("/admin/api/gallery/{photo_id}")
|
|
async def admin_delete_photo(request: Request, photo_id: str):
|
|
"""Supprime une photo via l'API photobooth-app."""
|
|
if not request.session.get("authenticated"):
|
|
return JSONResponse({"error": "Non authentifié"}, status_code=401)
|
|
|
|
pb = request.app.state.photobooth_service
|
|
ws = request.app.state.ws_manager
|
|
|
|
ok = await pb.delete_media(photo_id)
|
|
if ok:
|
|
await ws.broadcast({"type": "photo_deleted", "photo_id": photo_id})
|
|
return {"ok": ok, "photo_id": photo_id}
|
|
|
|
|
|
def _is_image(item: dict) -> bool:
|
|
t = item.get("type", item.get("mediaitem_type", "image"))
|
|
return str(t).lower() in ("image", "still", "photo")
|
|
|
|
|
|
def _get_id(item: dict) -> str:
|
|
return str(item.get("id", item.get("filename", item.get("uid", ""))))
|
|
|
|
|
|
def _find_file(media_dir: str, photo_id: str):
|
|
"""Cherche un fichier image correspondant à l'identifiant dans le répertoire media."""
|
|
from pathlib import Path
|
|
base = Path(media_dir)
|
|
if not base.exists():
|
|
return None
|
|
|
|
# L'ID peut être le stem du filename
|
|
for ext in (".jpg", ".jpeg", ".png"):
|
|
f = base / f"{photo_id}{ext}"
|
|
if f.exists():
|
|
return f
|
|
# Cherche dans les sous-dossiers
|
|
matches = list(base.rglob(f"{photo_id}{ext}"))
|
|
if matches:
|
|
return matches[0]
|
|
return None
|