콘텐츠로 건너뛰기
Home » [c/c++] SMI를 SRT로 컨버팅하기

[c/c++] SMI를 SRT로 컨버팅하기

Handbrake같은 인코딩 도구를 사용하여 동영상을 인코딩할 때 자막을 영상에 포함하는 옵션이 있는데, 이 때 사용할 수 있는 자막 포맷은 .SRT 형식이다. 국내에서 유통되는 대부분의 자막 포맷은 .SMI 파일이라서, 이를 SRT로 컨버팅할 수 있는 도구가 있으면 좋다. 예전에 맥에서 사용하려고 뒤져봤던 코드가 있었는데, (해당 코드는 다음 페이지에 있다.) 하도 오래전이라 조금 보기 편하게 하려고 수정을 했는데…. 생각보다 너무 오래전 스타일로 작성되어 있더라.(원 글이 작성된 11년 전 기준으로도 되게 오래된 코드였음) 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()
Pages: 1 2
태그: