mirror of
https://github.com/calesthio/OpenMontage.git
synced 2026-08-05 15:20:40 +08:00
fix(subtitle_gen): stop millisecond rounding from overflowing timestamps
_ts_srt/_ts_vtt computed the seconds and millisecond fields independently: `ms = int(round((seconds % 1) * 1000))`. When the fractional part is >= 0.9995 that rounds to 1000, emitting a malformed 4-digit `…,1000` value with no carry into the seconds field (and, at 59.9999/3599.9999, no carry into minutes/hours). For example 0.9999s became `00:00:00,1000` instead of `00:00:01,000`. ASR word and segment end-times routinely land on such fractional boundaries, and the resulting cue is rejected or mistimed by strict SRT/VTT parsers (ffmpeg subtitles filter, VLC, browser WebVTT). Decompose from a single rounded total-milliseconds value so the carry propagates across all fields. Both formatters now share one `_hmsms` helper.
This commit is contained in:
@@ -309,19 +309,27 @@ class SubtitleGen(BaseTool):
|
||||
return "\n".join(lines)
|
||||
|
||||
@staticmethod
|
||||
def _ts_srt(seconds: float) -> str:
|
||||
def _hmsms(seconds: float) -> tuple[int, int, int, int]:
|
||||
"""Decompose seconds into (h, m, s, ms), rounding to whole ms first.
|
||||
|
||||
Rounding to total milliseconds before splitting the fields lets the
|
||||
carry propagate: 0.9995s+ must become the next second (…,000), not a
|
||||
malformed 4-digit …,1000 with the seconds field left unincremented.
|
||||
"""
|
||||
total_ms = int(round(max(0.0, seconds) * 1000))
|
||||
h, rem = divmod(total_ms, 3_600_000)
|
||||
m, rem = divmod(rem, 60_000)
|
||||
s, ms = divmod(rem, 1_000)
|
||||
return h, m, s, ms
|
||||
|
||||
@classmethod
|
||||
def _ts_srt(cls, seconds: float) -> str:
|
||||
"""Format seconds as SRT timestamp: HH:MM:SS,mmm"""
|
||||
h = int(seconds // 3600)
|
||||
m = int((seconds % 3600) // 60)
|
||||
s = int(seconds % 60)
|
||||
ms = int(round((seconds % 1) * 1000))
|
||||
h, m, s, ms = cls._hmsms(seconds)
|
||||
return f"{h:02d}:{m:02d}:{s:02d},{ms:03d}"
|
||||
|
||||
@staticmethod
|
||||
def _ts_vtt(seconds: float) -> str:
|
||||
@classmethod
|
||||
def _ts_vtt(cls, seconds: float) -> str:
|
||||
"""Format seconds as VTT timestamp: HH:MM:SS.mmm"""
|
||||
h = int(seconds // 3600)
|
||||
m = int((seconds % 3600) // 60)
|
||||
s = int(seconds % 60)
|
||||
ms = int(round((seconds % 1) * 1000))
|
||||
h, m, s, ms = cls._hmsms(seconds)
|
||||
return f"{h:02d}:{m:02d}:{s:02d}.{ms:03d}"
|
||||
|
||||
Reference in New Issue
Block a user