fix: third-pass review bugs

- Switch DELETE /export to query param (path param strips leading /)
- Add CropKeyframe Pydantic model for typed keyframe validation
- Convert keyframes to tuples before passing to apply_keyframes_to_jobs
- Remove dead QFrame import from main.py

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-16 14:20:20 +02:00
parent 5b7a55a05d
commit b09ba3fa9e
2 changed files with 18 additions and 6 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ from pathlib import Path
from PyQt6.QtWidgets import ( from PyQt6.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QPushButton, QLineEdit, QFileDialog, QFrame, QLabel, QPushButton, QLineEdit, QFileDialog,
QListWidget, QListWidgetItem, QAbstractItemView, QSplitter, QToolTip, QListWidget, QListWidgetItem, QAbstractItemView, QSplitter, QToolTip,
QComboBox, QCheckBox, QSpinBox, QDoubleSpinBox, QComboBox, QCheckBox, QSpinBox, QDoubleSpinBox,
QMessageBox, QInputDialog, QMessageBox, QInputDialog,
+17 -5
View File
@@ -3,7 +3,7 @@ import re
import shutil import shutil
import uuid import uuid
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException, Query
from pydantic import BaseModel from pydantic import BaseModel
from core.export import ExportRunner from core.export import ExportRunner
@@ -19,6 +19,14 @@ _jobs: dict[str, dict] = {}
_VALID_ENCODERS = {"libx264", "h264_nvenc", "h264_vaapi", "h264_qsv", "h264_amf", "h264_videotoolbox"} _VALID_ENCODERS = {"libx264", "h264_nvenc", "h264_vaapi", "h264_qsv", "h264_amf", "h264_videotoolbox"}
class CropKeyframe(BaseModel):
time: float
center: float
ratio: str | None = None
rand_portrait: bool = False
rand_square: bool = False
class ExportRequest(BaseModel): class ExportRequest(BaseModel):
input_path: str input_path: str
cursor: float cursor: float
@@ -33,7 +41,7 @@ class ExportRequest(BaseModel):
category: str = "" category: str = ""
profile: str = "default" profile: str = "default"
folder_suffix: str = "" folder_suffix: str = ""
crop_keyframes: list | None = None crop_keyframes: list[CropKeyframe] | None = None
rand_portrait: bool = False rand_portrait: bool = False
rand_square: bool = False rand_square: bool = False
encoder: str = "libx264" encoder: str = "libx264"
@@ -101,8 +109,12 @@ def start_export(req: ExportRequest):
# Apply keyframes if provided — returns 6-tuples, strip back to 4 # Apply keyframes if provided — returns 6-tuples, strip back to 4
if req.crop_keyframes: if req.crop_keyframes:
kf_tuples = [
(kf.time, kf.center, kf.ratio, kf.rand_portrait, kf.rand_square)
for kf in req.crop_keyframes
]
widened = apply_keyframes_to_jobs( widened = apply_keyframes_to_jobs(
jobs, req.crop_keyframes, jobs, kf_tuples,
req.crop_center, req.portrait_ratio, req.crop_center, req.portrait_ratio,
req.rand_portrait, req.rand_square, req.rand_portrait, req.rand_square,
) )
@@ -176,8 +188,8 @@ def get_export_status(job_id: str):
} }
@router.delete("/export/{output_path:path}") @router.delete("/export")
def delete_export(output_path: str): def delete_export(output_path: str = Query(...)):
from ..app import db from ..app import db
# Validate path is under EXPORT_DIR # Validate path is under EXPORT_DIR
real = os.path.realpath(output_path) real = os.path.realpath(output_path)