SRT to TXT
convert / v1.0.0
Convert SRT subtitle files to clean UTF-8 plaintext.
Removes SRT cue numbers and timecodes while preserving subtitle text in a UTF-8 text file. Supports an optional output path, UTF-8 byte-order marks, Windows line endings, and clear command-line error reporting.
Requirements
- Python 3
Platforms
LinuxMacOSWindows
Usage
python3 ./scripts/srt-to-txt.py subtitles.srt
python3 ./scripts/srt-to-txt.py subtitles.srt transcript.txt
python3 ./scripts/srt-to-txt.py "My Subtitles.srt" "output/My Transcript.txt"
Download
Install quickly or copy a command for your shell.
toolbox srt-to-txt
curl -fsSL "https://raw.githubusercontent.com/PiSaucer/toolbox/main/scripts/srt-to-txt.py" -o "srt-to-txt.py"
wget -O "srt-to-txt.py" "https://raw.githubusercontent.com/PiSaucer/toolbox/main/scripts/srt-to-txt.py"
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/PiSaucer/toolbox/main/scripts/srt-to-txt.py" -OutFile "srt-to-txt.py"
python3 -c "import urllib.request; urllib.request.urlretrieve('https://raw.githubusercontent.com/PiSaucer/toolbox/main/scripts/srt-to-txt.py', 'srt-to-txt.py')"
Integrity
SHA256
23fbcb96316cc78ead12382b2985eaceea09aa0e8310d2f0b88e79eeff96c7c4
Copy and Paste Script
Use this when you want to copy the full script directly.
#!/usr/bin/env python3
# srt-to-txt.py
# Copyright (c) 2026 PiSaucer
# Licensed under the MIT License
# Version 1.0.0
# Convert an SRT subtitle file to plain UTF-8 text.
# Usage: python3 srt-to-txt.py INPUT.srt [OUTPUT.txt]
import argparse
import re
import sys
from pathlib import Path
# Match an SRT time range, including optional positioning information.
TIMECODE_RE = re.compile(
r"^\s*\d{1,3}:\d{2}:\d{2}[,.]\d{3}\s*-->\s*"
r"\d{1,3}:\d{2}:\d{2}[,.]\d{3}(?:\s+.*)?$"
)
def extract_subtitle_text(content: str) -> list[str]:
"""Extract visible text lines from SubRip content.
Args:
content: Complete SRT document text, optionally including a byte-order
mark and mixed newline styles.
Returns:
Subtitle lines with cue numbers, timecodes, and blank lines removed.
"""
# utf-8-sig normally removes the BOM, but lstrip also supports direct calls.
normalized = content.lstrip("\ufeff").replace("\r\n", "\n").replace("\r", "\n")
subtitles = []
# SRT cues are separated by one or more blank lines.
for block in re.split(r"\n[ \t]*\n+", normalized):
lines = [line.strip() for line in block.splitlines()]
# A well-formed cue begins with an optional sequence number and time range.
if lines and lines[0].isdigit():
lines.pop(0)
if lines and TIMECODE_RE.match(lines[0]):
lines.pop(0)
# Retain markup such as speaker or emphasis tags; this converter removes
# SRT structure, not formatting embedded in the subtitle text itself.
subtitles.extend(line for line in lines if line)
return subtitles
def convert_srt_to_txt(srt_file: Path, txt_file: Path) -> int:
"""Convert one SRT subtitle file to a UTF-8 plaintext file.
Args:
srt_file: Input subtitle path.
txt_file: Output plaintext path.
Returns:
Number of subtitle text lines written.
Raises:
FileNotFoundError: If ``srt_file`` is not a file.
ValueError: If the input is not an SRT file or the input and output
resolve to the same path.
OSError: If the input cannot be read or the output cannot be written.
UnicodeError: If the input cannot be decoded as UTF-8.
"""
if not srt_file.is_file():
raise FileNotFoundError(f"input file not found: {srt_file}")
if srt_file.suffix.lower() != ".srt":
raise ValueError(f"input file must have a .srt extension: {srt_file}")
if srt_file.resolve() == txt_file.resolve():
raise ValueError("input and output paths must be different")
# utf-8-sig accepts regular UTF-8 and removes a leading byte-order mark.
content = srt_file.read_text(encoding="utf-8-sig")
subtitles = extract_subtitle_text(content)
# Create an explicitly requested output directory when it does not exist.
txt_file.parent.mkdir(parents=True, exist_ok=True)
# Emit one subtitle line per output line and include a conventional final LF.
output = "\n".join(subtitles)
if output:
output += "\n"
txt_file.write_text(output, encoding="utf-8")
return len(subtitles)
def parse_args() -> argparse.Namespace:
"""Parse command-line arguments.
Returns:
Parsed input SRT path and optional output text path.
Raises:
SystemExit: If arguments are invalid or argparse handles an immediate
action such as ``--help``.
"""
parser = argparse.ArgumentParser(
description="Convert an SRT subtitle file to plain UTF-8 text."
)
parser.add_argument("srt_file", type=Path, help="Input .srt subtitle file")
parser.add_argument(
"output_file",
type=Path,
nargs="?",
help="Output .txt file (default: input filename with a .txt extension)",
)
return parser.parse_args()
def main() -> int:
"""Run the command-line subtitle converter.
Returns:
Zero on success or one when validation, decoding, or file I/O fails.
"""
args = parse_args()
srt_file = args.srt_file.expanduser()
txt_file = (
args.output_file.expanduser()
if args.output_file
else srt_file.with_suffix(".txt")
)
try:
line_count = convert_srt_to_txt(srt_file, txt_file)
except (OSError, UnicodeError, ValueError) as error:
print(f"Error: {error}", file=sys.stderr)
return 1
print(f"Converted: {srt_file} -> {txt_file} ({line_count} text lines)")
return 0
if __name__ == "__main__":
raise SystemExit(main())