If you've ever tried to hand a .srt file to someone who doesn't work with video, you know the look. It's the same look you get when you send a .parquet file to a product manager. The content is in there — dialogue, timestamps, speaker cues — but the container is wrong for the audience.
I've been building tooling around media workflows for a few years now, and subtitle conversion keeps coming back as a small, annoying, recurring problem. Not because it's hard, but because most people solve it badly the first time and then copy that solution forever.
Here's what I've learned about doing it properly.
What's actually inside an SRT file
An SRT is deceptively simple. Each block looks like this:
1
00:00:04,120 --> 00:00:07,880
So the first thing we need to check
is whether the token is still valid.
2
00:00:08,010 --> 00:00:10,440
If it isn't, we bail out early.
Three parts: an index, a timing line, and one or more lines of text. That's it. No styling, no positioning, no speaker metadata unless someone smuggled it into the text itself.
The simplicity is why it's everywhere. YouTube exports it. OBS writes it. Whisper generates it. Every transcription service on the planet will hand you an SRT before they hand you anything else.
The simplicity is also why it's a bad format for anything that isn't a video player.
Where the pipeline breaks
The failure mode I see most often is a naive conversion: strip the timestamps, concatenate the text, paste into Word. It works for a five-minute clip. It falls apart the moment you have real content.
Three specific problems show up:
Line breaks become meaningless. In an SRT, a line break is a display constraint — it exists because the subtitle box is narrow. In a document, a line break is a paragraph. If you keep them, you get a document where every sentence is its own paragraph. If you drop them all, you lose real paragraph boundaries that the transcriber may have encoded with blank lines or double breaks.
Timestamps carry information you might want. For a transcript you're editing for publication, you probably don't want 00:00:04,120 --> 00:00:07,880 in the body. But for a review copy, a legal record, or an accessibility audit, you absolutely do. The right answer depends on the destination, not the source.
Encoding is a minefield. SRT files in the wild are a mix of UTF-8, UTF-8 with BOM, Windows-1252, and occasionally something stranger. If you're reading them in Python with the default open(), you'll get a UnicodeDecodeError on the first curly apostrophe. Always specify the encoding, and be ready to fall back.
A conversion approach that holds up
If you're writing this yourself — and for a one-off, you should — the shape of the solution is:
- Read the file with an explicit encoding, falling back to
latin-1if you have to. - Split on blank lines to get blocks.
- For each block, drop the index line, parse the timing line with a regex, and join the remaining lines.
- Decide what to do with the text: keep it as a single paragraph, or merge consecutive blocks that belong to the same speaker.
- Write out to a
.docxusingpython-docx, or to Markdown if the destination is a docs site.
The interesting decision is step 4. Merging is where quality lives. A good merge heuristic: if the gap between block N's end and block N+1's start is under ~500ms and the previous block doesn't end with sentence-terminating punctuation, join them with a space. That single rule cleans up 90% of the choppiness in auto-generated transcripts.
Here's a minimal version:
import re
from docx import Document
TIMING = re.compile(
r"(\d{2}):(\d{2}):(\d{2}),(\d{3}) --> "
r"(\d{2}):(\d{2}):(\d{2}),(\d{3})"
)
def parse_srt(text):
blocks = re.split(r"\n\s*\n", text.strip())
cues = []
for block in blocks:
lines = block.splitlines()
if len(lines) < 2:
continue
match = TIMING.match(lines[1])
if not match:
continue
body = " ".join(lines[2:]).strip()
cues.append((match.groups(), body))
return cues
From there, merging and writing to docx is a dozen more lines. The whole thing fits in a single file and takes an afternoon.
When not to write it yourself
There's a category of task where rolling your own is the right call: you do it often, you have specific requirements, and you want it in your build. There's another category where it isn't: you need one file converted, right now, and you don't want to install Python and python-docx on a machine you don't control.
For that second case, I keep a browser-based converter bookmarked. I've been using SRT to Word for the quick jobs — it takes an SRT, produces an editable .docx, and doesn't require an account or an upload to a service I don't know. It's the kind of tool that exists because the manual version is tedious and the scripted version is overkill for a single file.
The tradeoff is real: you're handing a file to someone else's server. For a public YouTube transcript, that's fine. For an internal meeting recording, run the script locally. Know which one you're doing.
The general lesson
Subtitle conversion is a small instance of a pattern that shows up everywhere in developer tooling: the format that's convenient for machines is rarely the format that's convenient for people. SRT is optimized for a player that needs to know when to draw text on a screen. Word is optimized for a human who needs to read, edit, and comment.
The conversion between them isn't a format change. It's a change in what the structure means. Line breaks stop being display hints and start being paragraphs. Timestamps stop being playback instructions and start being either noise or evidence, depending on who's reading.
Get that mapping right, and the code is trivial. Get it wrong, and you get a document that technically contains the words but is miserable to actually use.
Top comments (0)