Goon — self-hosted aggregator for adult-content scene metadata. Indexes scenes from TPDB, StashDB, and 30+ public adult tube sites. Cross-source deduplication via perceptual hash + Levenshtein distance. FastAPI backend + APScheduler worker + React Native (Expo) mobile client. FOSS, ad-free, donation-funded. See README for details.
83 lines
2.4 KiB
Python
83 lines
2.4 KiB
Python
"""Scene favorites — ulubione sceny (single-user, równolegle do /favorites/performers).
|
|
|
|
Endpointy:
|
|
GET /scene-favorites — lista ulubionych scen (pełen SceneOut)
|
|
POST /scene-favorites/{scene_id} — dodaj (idempotent)
|
|
DELETE /scene-favorites/{scene_id} — usuń
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import uuid
|
|
from typing import Annotated
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from pydantic import BaseModel
|
|
from sqlalchemy import select
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.api.scenes import _build_scene_out
|
|
from app.api.schemas import SceneOut
|
|
from app.auth import require_api_key
|
|
from app.db import get_session
|
|
from app.models.favorite_scene import FavoriteScene
|
|
from app.models.scene import Scene
|
|
|
|
router = APIRouter(
|
|
prefix="/scene-favorites",
|
|
tags=["scene-favorites"],
|
|
dependencies=[Depends(require_api_key)],
|
|
)
|
|
|
|
|
|
class SceneFavoriteListOut(BaseModel):
|
|
items: list[SceneOut]
|
|
total: int
|
|
|
|
|
|
class SceneFavoriteToggleOut(BaseModel):
|
|
scene_id: uuid.UUID
|
|
favorited: bool
|
|
|
|
|
|
@router.get("", response_model=SceneFavoriteListOut)
|
|
def list_scene_favorites(
|
|
session: Annotated[Session, Depends(get_session)],
|
|
) -> SceneFavoriteListOut:
|
|
rows = (
|
|
session.execute(
|
|
select(Scene, FavoriteScene)
|
|
.join(FavoriteScene, FavoriteScene.scene_id == Scene.id)
|
|
.order_by(FavoriteScene.created_at.desc())
|
|
)
|
|
.all()
|
|
)
|
|
items = [_build_scene_out(session, scene) for scene, _ in rows]
|
|
return SceneFavoriteListOut(items=items, total=len(items))
|
|
|
|
|
|
@router.post(
|
|
"/{scene_id}",
|
|
response_model=SceneFavoriteToggleOut,
|
|
status_code=status.HTTP_201_CREATED,
|
|
)
|
|
def add_scene_favorite(
|
|
scene_id: uuid.UUID,
|
|
session: Annotated[Session, Depends(get_session)],
|
|
) -> SceneFavoriteToggleOut:
|
|
scene = session.get(Scene, scene_id)
|
|
if scene is None:
|
|
raise HTTPException(status_code=404, detail="scene not found")
|
|
existing = session.get(FavoriteScene, scene_id)
|
|
if existing is None:
|
|
session.add(FavoriteScene(scene_id=scene_id))
|
|
return SceneFavoriteToggleOut(scene_id=scene_id, favorited=True)
|
|
|
|
|
|
@router.delete("/{scene_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
def remove_scene_favorite(
|
|
scene_id: uuid.UUID,
|
|
session: Annotated[Session, Depends(get_session)],
|
|
) -> None:
|
|
fav = session.get(FavoriteScene, scene_id)
|
|
if fav is not None:
|
|
session.delete(fav)
|