Skip to content

caption.js: missing data-d next to a non-increasing data-m yields negative durations → inverted cues that the timing safeguard skips instead of repairing #411

Description

@maboa

Summary

(As of v0.8.1.) When a word has no data-d, its duration is derived from the next span's data-m with only a positive cap applied (caption.js:132-141):

thisDuration = (parseInt(words[i + 1].getAttribute('data-m') - 1, 10) / 1000) - thisStart;
if (thisDuration > maxWordDuration) { thisDuration = maxWordDuration; }

If the next span's data-m is ≤ its own — duplicate timestamps on split/glued tokens (cf. the space:false convention) or out-of-order times after manual edits — thisDuration goes negative. Then segmentStop = lastWord.start + lastWord.duration (:198) < segment.start → a cue with stop < start. applyTimingSafeguards deliberately steps over exactly these (:380: if (isNaN(start) || isNaN(stop) || stop <= start) continue;), so the inverted cue is serialized — browsers drop it from the VTT track, and several SRT consumers reject the whole file. If the arithmetic goes below zero, formatSeconds (:11, Date-based) wraps the negative to "23:59:59.xxx" — a cue apparently ending at 24 h.

Fix

Clamp thisDuration = Math.max(0, ...) at :134, and make the safeguard repair stop <= start cues (set stop = start + minCaptionDuration, capped at next start) instead of skipping them.

Found reviewing the vendored copy in the GliderMac app (2026-07-11).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions