feat(api): scene hide + merge-duplicate endpoints for long-press actions
POST /scenes/{id}/hide — marks all playback_sources dead so the scene drops out
of has_playback lists (reversible via dead_at; row kept for dedup/refs).
POST /scenes/{keep_id}/merge/{drop_id} — merges drop into keep via scene_merge
(moves refs/performers/tags/fingerprints/playback). Backs the new tile long-press
menu (hide / mark-duplicate) replacing the dead animated-preview gesture.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
abddd27856
commit
e98ef6577e
1 changed files with 61 additions and 0 deletions
|
|
@ -831,6 +831,67 @@ def remove_performer_from_scene(
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
class SceneHideOut(BaseModel):
|
||||||
|
scene_id: uuid.UUID
|
||||||
|
playback_marked_dead: int
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/{scene_id}/hide", response_model=SceneHideOut)
|
||||||
|
def hide_scene(
|
||||||
|
scene_id: uuid.UUID,
|
||||||
|
session: Annotated[Session, Depends(get_session)],
|
||||||
|
) -> SceneHideOut:
|
||||||
|
"""Ukryj scenę (user long-press → „usuń"). Oznacza wszystkie playback_sources
|
||||||
|
jako dead → scena wypada z list (has_playback=false). Odwracalne w DB (dead_at).
|
||||||
|
Nie kasujemy wiersza sceny — zachowujemy refs/dedup, tylko znika z UI."""
|
||||||
|
from datetime import UTC, datetime
|
||||||
|
|
||||||
|
from app.models.playback_source import PlaybackSource
|
||||||
|
|
||||||
|
if session.get(Scene, scene_id) is None:
|
||||||
|
raise HTTPException(status_code=404, detail="scene not found")
|
||||||
|
rows = session.execute(
|
||||||
|
select(PlaybackSource).where(
|
||||||
|
PlaybackSource.scene_id == scene_id,
|
||||||
|
PlaybackSource.dead_at.is_(None),
|
||||||
|
)
|
||||||
|
).scalars().all()
|
||||||
|
now = datetime.now(UTC)
|
||||||
|
for p in rows:
|
||||||
|
p.dead_at = now
|
||||||
|
p.dead_reason = "user hid scene (long-press)"
|
||||||
|
session.commit()
|
||||||
|
return SceneHideOut(scene_id=scene_id, playback_marked_dead=len(rows))
|
||||||
|
|
||||||
|
|
||||||
|
class SceneMergeOut(BaseModel):
|
||||||
|
keep_id: uuid.UUID
|
||||||
|
dropped_id: uuid.UUID
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/{keep_id}/merge/{drop_id}", response_model=SceneMergeOut)
|
||||||
|
def merge_duplicate_scene(
|
||||||
|
keep_id: uuid.UUID,
|
||||||
|
drop_id: uuid.UUID,
|
||||||
|
session: Annotated[Session, Depends(get_session)],
|
||||||
|
) -> SceneMergeOut:
|
||||||
|
"""Scal `drop_id` w `keep_id` (user long-press → „oznacz duplikat" → wybór drugiej
|
||||||
|
sceny). Przenosi refs/performers/tags/fingerprints/playback (scene_merge), kasuje
|
||||||
|
`drop`. keep = scena na której user trzyma (zostaje), drop = wskazany duplikat."""
|
||||||
|
from app.resolve.scene_merge import MergeError, merge_scenes
|
||||||
|
|
||||||
|
if keep_id == drop_id:
|
||||||
|
raise HTTPException(status_code=400, detail="keep_id == drop_id")
|
||||||
|
if session.get(Scene, keep_id) is None or session.get(Scene, drop_id) is None:
|
||||||
|
raise HTTPException(status_code=404, detail="scene not found")
|
||||||
|
try:
|
||||||
|
merge_scenes(session, keep_id=keep_id, drop_id=drop_id, resolved_by="user_long_press_duplicate")
|
||||||
|
except MergeError as e:
|
||||||
|
raise HTTPException(status_code=400, detail=str(e)) from e
|
||||||
|
session.commit()
|
||||||
|
return SceneMergeOut(keep_id=keep_id, dropped_id=drop_id)
|
||||||
|
|
||||||
|
|
||||||
class EnrichTagsOut(BaseModel):
|
class EnrichTagsOut(BaseModel):
|
||||||
scene_id: uuid.UUID
|
scene_id: uuid.UUID
|
||||||
added: int
|
added: int
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue