Skip to main content
SubtitleMatrix

SRT to JSON

Format conversionSubRip (SRT)
Or paste subtitle text

What this conversion changes

Nothing is lost in this direction — every feature of the source format has somewhere to go in the target format.

This list comes from the capability matrix for these two formats, not from the particular file you loaded. A specific file may lose more if it uses features the format allows but the matrix does not model.

This page turns a subtitle file into structured data: a JSON document listing each cue with its start and end time, and its text. The schema is this site's own, and it is deliberately small — a version number and a cues array, with times as whole milliseconds rather than as timecodes. Nothing in it depends on a particular library, and nothing about it needs to be guessed at.

Milliseconds are used because they need no parsing to be useful. The finest resolution any subtitle format here stores is one millisecond, and an integer cannot be misread because of a comma or a dot convention. A line with no formatting is a plain string; a line that carries italics, bold or a colour becomes an object holding the text plus the tags that apply to it, each one recording what it is and which characters it covers.

The result is a file you can load into a script, diff, or check into version control, and converting it back gives you the subtitles again. As with every tool here, the work happens in your browser.

Examples

A typical SRT file, converted to JSON

Input

1
00:00:01,000 --> 00:00:03,500
Hello there.

2
00:00:03,500 --> 00:00:06,000
<i>Whispering</i> now.
And a second line.

3
00:00:06,000 --> 00:00:09,250
<b>Bold</b> statement.

Output

{
  "version": 1,
  "cues": [
    {
      "id": "1",
      "start": 1000,
      "end": 3500,
      "lines": [
        "Hello there."
      ]
    },
    {
      "id": "2",
      "start": 3500,
      "end": 6000,
      "lines": [
        {
          "text": "Whispering now.",
          "tags": [
            {
              "kind": "italic",
              "start": 0,
              "end": 10
            }
          ]
        },
        "And a second line."
      ]
    },
    {
      "id": "3",
      "start": 6000,
      "end": 9250,
      "lines": [
        {
          "text": "Bold statement.",
          "tags": [
            {
              "kind": "bold",
              "start": 0,
              "end": 4
            }
          ]
        }
      ]
    }
  ]
}

Nothing is dropped here: compare the two sides line for line.

The same conversion on an awkward input

Input

1
0:00:01,00 --> 0:00:03,500
<B>Bold</B> and <I>italic</I>.


2
00:00:03,500 --> 00:00:06,000


3
00:00:08,000 --> 00:00:09,000
Last one.

Output

{
  "version": 1,
  "cues": [
    {
      "id": "1",
      "start": 1000,
      "end": 3500,
      "lines": [
        {
          "text": "Bold and italic.",
          "tags": [
            {
              "kind": "bold",
              "start": 0,
              "end": 4
            },
            {
              "kind": "italic",
              "start": 9,
              "end": 15
            }
          ]
        }
      ]
    },
    {
      "id": "2",
      "start": 3500,
      "end": 6000,
      "lines": []
    },
    {
      "id": "3",
      "start": 8000,
      "end": 9000,
      "lines": [
        "Last one."
      ]
    }
  ]
}

This is the kind of damage real files have — mixed line endings, stray whitespace, fields left empty. Compare it with the tidy example above to see what the parser forgives.

Frequently asked questions

What schema does the output follow?

This site's own, and it is documented by example in the panel above: a version number, then an array of cues. Each cue has an id, a start and an end in milliseconds, and a list of lines. There is no hidden metadata and no dependency on a third-party format.

Why milliseconds instead of timecodes?

So the file can be used without being parsed first. Adding two timings, comparing them or sorting by them are all ordinary number operations on an integer, where a string like 00:00:01,000 has to be decoded first and can be decoded wrongly.

How is formatting represented?

A plain line stays a plain string. A line that carries formatting becomes an object with the text and a tags array, and each tag says what kind it is and where it starts and ends inside that text. Convert the JSON back and the formatting is written out again.

Is it safe to edit by hand?

Yes, and converting back is the check. If the file parses, the conversion will reproduce the cues with the timings you gave them — so a round trip through the converter is a quick way to find a typo.

Can I load it in a script?

That is what it is for. Read the cues array, take start and end as numbers, and join the lines — a line is either a string or an object whose text field holds the words.

Related tools