Loading...
Loading...
02-reusable-code-python/utils/subtitle_formatter.py
"""
자막 포맷터 — SRT/VTT 생성 유틸리티
@source: 260313 voice-to-text-v2
@extracted: 2026-03-14
@description: 타임스탬프 세그먼트 데이터를 SRT/VTT 자막 포맷으로 변환.
범용 자막 생성에 사용 가능 (음성 인식, 영상 편집 등).
의존성: 없음 (순수 Python)
사용법:
from utils.subtitle_formatter import SubtitleFormatter
segments = [
{"start": 0.0, "end": 2.5, "text": "안녕하세요"},
{"start": 2.5, "end": 5.0, "text": "반갑습니다"},
]
# SRT 생성
srt_text = SubtitleFormatter.to_srt(segments)
# VTT 생성
vtt_text = SubtitleFormatter.to_vtt(segments)
# 타임코드 변환 (단독 사용)
srt_time = SubtitleFormatter.format_srt_time(65.123) # "00:01:05,123"
vtt_time = SubtitleFormatter.format_vtt_time(65.123) # "00:01:05.123"
"""
from typing import TypedDict
class SubtitleSegment(TypedDict, total=False):
"""자막 세그먼트 타입."""
start: float
end: float
text: str
class SubtitleFormatter:
"""
자막 포맷 변환기.
지원 포맷:
- SRT (SubRip): 가장 널리 사용되는 자막 포맷
- VTT (WebVTT): 웹 표준 자막 포맷 (HTML5 <track> 호환)
"""
@staticmethod
def format_srt_time(seconds: float) -> str:
"""
초 단위를 SRT 타임코드로 변환.
Args:
seconds: 시간 (초 단위, 소수점 밀리초)
Returns:
SRT 타임코드 문자열 (HH:MM:SS,mmm)
Examples:
>>> SubtitleFormatter.format_srt_time(65.123)
'00:01:05,123'
>>> SubtitleFormatter.format_srt_time(3661.5)
'01:01:01,500'
"""
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
secs = int(seconds % 60)
millis = int((seconds % 1) * 1000)
return f"{hours:02d}:{minutes:02d}:{secs:02d},{millis:03d}"
@staticmethod
def format_vtt_time(seconds: float) -> str:
"""
초 단위를 VTT 타임코드로 변환.
Args:
seconds: 시간 (초 단위, 소수점 밀리초)
Returns:
VTT 타임코드 문자열 (HH:MM:SS.mmm)
Examples:
>>> SubtitleFormatter.format_vtt_time(65.123)
'00:01:05.123'
>>> SubtitleFormatter.format_vtt_time(3661.5)
'01:01:01.500'
"""
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
secs = int(seconds % 60)
millis = int((seconds % 1) * 1000)
return f"{hours:02d}:{minutes:02d}:{secs:02d}.{millis:03d}"
@classmethod
def to_srt(cls, segments: list[SubtitleSegment]) -> str:
"""
세그먼트 리스트를 SRT 포맷 문자열로 변환.
Args:
segments: 자막 세그먼트 리스트
각 세그먼트: {"start": float, "end": float, "text": str}
Returns:
SRT 포맷 문자열
Raises:
ValueError: segments가 비어있을 때
"""
if not segments:
raise ValueError("segments가 비어있습니다.")
lines: list[str] = []
for i, seg in enumerate(segments, 1):
start = cls.format_srt_time(seg.get("start", 0))
end = cls.format_srt_time(seg.get("end", 0))
text = seg.get("text", "").strip()
lines.append(f"{i}")
lines.append(f"{start} --> {end}")
lines.append(text)
lines.append("")
return "\n".join(lines)
@classmethod
def to_vtt(cls, segments: list[SubtitleSegment]) -> str:
"""
세그먼트 리스트를 WebVTT 포맷 문자열로 변환.
Args:
segments: 자막 세그먼트 리스트
각 세그먼트: {"start": float, "end": float, "text": str}
Returns:
WebVTT 포맷 문자열 (WEBVTT 헤더 포함)
Raises:
ValueError: segments가 비어있을 때
"""
if not segments:
raise ValueError("segments가 비어있습니다.")
lines: list[str] = ["WEBVTT", ""]
for seg in segments:
start = cls.format_vtt_time(seg.get("start", 0))
end = cls.format_vtt_time(seg.get("end", 0))
text = seg.get("text", "").strip()
lines.append(f"{start} --> {end}")
lines.append(text)
lines.append("")
return "\n".join(lines)