Fix trim bar handles not visible

Bug from screenshot: trim bar visible but red handles not showing.

Causes:
1. video_duration in job is None for old jobs (was not saved on initial
   processing). Without it, fallback was endInit+60 which placed handles
   off-screen.

2. videoDuration was const, couldn't be updated when video metadata loads.

3. Handle offset was 9px but handles are now 24px wide (need 12px offset).

Fixes:
- Backend /api/transcript: fallback to last segment end time if
  video_duration missing in job
- Frontend: videoDuration is let, updated on loadedmetadata
- Handle offset 9px → 12px for 24px wide handles
- Re-render trim after metadata loads to pick up actual video.duration
This commit is contained in:
Sebastjan Artič 2026-04-30 11:21:43 +00:00
parent 446769b68f
commit a3550a444a
2 changed files with 19 additions and 10 deletions

View File

@ -1262,11 +1262,15 @@ async def get_transcript(job_id: str, user: str = Depends(check_auth)):
analysis = json.loads(analysis_path.read_text())
transcript = analysis.get("transcript", {})
clip_range = analysis.get("clip_range", {})
# video_duration: probaj iz analysis, sicer iz zadnjega segmenta, sicer 0
video_dur = analysis.get("video_duration") or job.get("video_duration") or 0
if not video_dur and transcript.get("segments"):
video_dur = max((s.get("end", 0) for s in transcript["segments"]), default=0)
return {
"segments": transcript.get("segments", []),
"language": transcript.get("language", "?"),
"clip_range": clip_range,
"video_duration": job.get("video_duration", 0),
"video_duration": video_dur,
}
except Exception as e:
raise HTTPException(500, f"Napaka pri branju: {e}")

View File

@ -1011,7 +1011,7 @@
const startInit = data.clip_range?.start || 0;
const endInit = data.clip_range?.end || (startInit + 30);
const videoDuration = data.video_duration || endInit + 60;
let videoDuration = data.video_duration || endInit + 60;
const segments = data.segments || [];
const overlay = document.createElement("div");
@ -1127,8 +1127,9 @@
const rPct = pctOf(trimEnd);
trimRegion.style.left = lPct + '%';
trimRegion.style.right = (100 - rPct) + '%';
handleL.style.left = `calc(${lPct}% - 9px)`;
handleR.style.left = `calc(${rPct}% - 9px)`;
// Handle 24px width → offset 12px
handleL.style.left = `calc(${lPct}% - 12px)`;
handleR.style.left = `calc(${rPct}% - 12px)`;
startVal.textContent = formatTime(trimStart);
endVal.textContent = formatTime(trimEnd);
durVal.textContent = (trimEnd - trimStart).toFixed(1) + "s";
@ -1187,16 +1188,20 @@
if (video) video.currentTime = t;
});
// Update playhead during playback
// Update playhead during playback + re-render če videoDuration manjkalo
if (video) {
video.addEventListener("timeupdate", renderPlayhead);
video.addEventListener("loadedmetadata", () => {
// Če videoDuration ni bilo podanih, vzemi iz videa
if (!data.video_duration && video.duration) {
// Recalculate render
renderTrim();
renderPlayhead();
// Če videoDuration ni bilo podanih iz API, vzemi iz video elementa
if ((!videoDuration || videoDuration < 1) && video.duration) {
videoDuration = video.duration;
}
// Refresh end label
const endLabel = document.getElementById("trim-end-label");
if (endLabel) endLabel.textContent = formatTime(videoDuration);
// Re-render handles z pravilnim videoDuration
renderTrim();
renderPlayhead();
});
}