.smi 자막 파일을 .srt로 변환하기
1분
Handbrake같은 인코딩 도구를 사용하여 동영상을 인코딩할 때 자막을 영상에 포함하는 옵션이 있는데, 이 때 사용할 수 있는 자막 포맷은 .SRT 형식이다. 국내에서 유통되는 대부분의 자막 포맷은 .SMI 파일이라서, 이를 SRT로 컨버팅할 수 있는 도구를 작성했다. 예전에 해외 커뮤니티에서 돌아다니던 C 소스를 가져와서 수정해서 사용하다가, 아예 파이썬으로 새로 작성함.
import re
import sys
from pathlib import Path
pat_sync = re.compile(r"^.*sync start=\"?(\d+)", re.IGNORECASE)
pat_br = re.compile(r"(?:<br/?>/s*)+")
pat_tag = re.compile(r"<[^>]+>|&\S+;")
def remove_tags(line: str) -> str:
temp = pat_br.sub("\n", line).splitlines()
return "\n".join(re.sub(r"\S+", " ", pat_tag.sub("", x)) for x in temp)
def convert(t: int) -> str:
q1, r = divmod(t, 3600_000)
q2, r = divmod(r, 60000)
q3, r = divmod(r, 1000)
return f"{q1:02d}:{q2:02d}:{q3:02d}.{r:03d}"
def make_output(buf: list[str], line_n: int, start_t: int, end_t: int) -> str:
temp = remove_tags("\n".join(buf))
if re.search(r"\S", temp):
return f"{line_n}\n{convert(start_t)} --> {convert(end_t)}\n{temp}\n"
return ""
def process(content: str) -> str:
buf: list[str] = []
res: list[str] = []
line_n = 1
start_t, end_t = 0, 0
flag = False
for line in content.splitlines():
m = pat_sync.search(line)
match (m, flag):
case (None, True):
buf.append(line)
case (mat, False) if mat is not None:
start_t = int(mat.group(1))
buf.append(line)
flag = True
case (mat, True) if mat is not None:
end_t = int(mat.group(1))
out = make_output(buf, line_n, start_t, end_t)
if out:
res.append(out)
start_t, line_n = end_t, line_n + 1
buf[:] = [line]
case _:
continue
return "\n".join(res)
def main():
if len(sys.argv) > 1:
fname = Path(sys.argv[1])
res = process(fname.read_text())
if res:
with fname.with_suffix(".srt").open("w") as f:
f.write(res)
else:
print("Usage: smi2srt.py filename.smi")
if __name__ == "__main__":
main()