Test files › Subtitles and captions › valid.srt

Sample SRT file (valid)

A valid SubRip file: four cues, 1-based numbering, comma decimal separator, blank line between cues.

↓ Download valid.srt
Filenamevalid.srt
FormatSRT
Size316 bytes (316 bytes)
MIME typeapplication/x-subrip; charset=utf-8
SHA-2569bd108406fd1c6924494a87a90ff6c9e577aa8bec6f697ec3960a63bf3f8af5b
What this file catchesBaseline subtitle parsing. SRT times use a COMMA before the milliseconds (00:00:01,000), which is the detail parsers written against WebVTT get wrong.

Handle it in code

Each snippet below was run against this exact file with Python 3.14.4 and Node 24.15.0 when this page was built, and the output shown is what it printed.

Python

SRT puts a comma before the milliseconds and WebVTT a full stop, and WebVTT files must start with WEBVTT. Players differ on the rest: overlapping cues are legal in WebVTT, but many SRT players show only one of them.

import re

TIME = r"(?:(\d+):)?(\d{2}):(\d{2})([.,])(\d{3})"
CUE = re.compile(TIME + r"\s+-->\s+" + TIME)

def ms(h, m, s, sep, frac):
    return ((int(h or 0) * 60 + int(m)) * 60 + int(s)) * 1000 + int(frac)

name = "valid.srt"
vtt = name.lower().endswith(".vtt")
with open(name, encoding="utf-8-sig") as f:
    text = f.read()
problems, cues = [], []
if vtt and not text.startswith("WEBVTT"):
    problems.append("line 1: no WEBVTT signature")
for n, line in enumerate(text.splitlines(), 1):
    m = CUE.search(line)
    if not m:
        continue
    g = m.groups()
    right = "." if vtt else ","
    if g[3] != right or g[8] != right:
        problems.append(f"line {n}: {'WebVTT' if vtt else 'SRT'} needs {right!r} before the milliseconds")
    start, end = ms(*g[:5]), ms(*g[5:])
    if end < start:
        problems.append(f"line {n}: the cue ends before it starts")
    elif end == start:
        problems.append(f"line {n}: zero length, so it never shows")
    if cues:
        prev_start, prev_end = cues[-1]
        if start < prev_start:
            problems.append(f"line {n}: starts before the previous cue (out of order)")
        overlap = min(end, prev_end) - max(start, prev_start)
        if overlap > 0:
            problems.append(f"line {n}: overlaps the previous cue by {overlap} ms")
    cues.append((start, end))
print(f"{len(cues)} cues:", "valid" if not problems else f"{len(problems)} problem{'s' * (len(problems) != 1)}")
for p in problems:
    print("  " + p)

Run against this file, it prints: 4 cues: valid

Related guides and tools

Character encodingsVerify its SHA-256

Download & verify

curl -fsSL -o "valid.srt" "https://files.hexaqa.com/subtitle/valid.srt"
curl -fsSL "https://files.hexaqa.com/subtitle/valid.srt" | sha256sum # expect: 9bd108406fd1c6924494a87a90ff6c9e577aa8bec6f697ec3960a63bf3f8af5b

More subtitles and captions test files

comma-separator.vttmissing-signature.vttoverlapping-cues.srtvalid.vtt

← All Subtitles and captions files