Compiles, parses Subrip files, segments and generates HLS playlists for them.
This is a sister package to osk/node-webvtt and forked from goatandsheep/node-srt.
For a Subrip file:
1
00:00:00.000 --> 00:00:01.000
Hello world!
2
00:00:30.000 --> 00:00:31.000 align:start line:0%
This is a subtitle
3
00:01:00.000 --> 00:01:01.000
Foo
4
00:01:50.000 --> 00:01:51.000
Bar
We can parse, segment and create HLS playlists, and compile back to Subrip format:
import { parse, compile, hlsSegmentPlaylist, hlsSegment } from 'node-srt-ts';
const segmentDuration = 10; // default to 10
const startOffset = 0; // Starting MPEG TS offset to be used in timestamp map, default 900000
const parsed = parse(input);
const compile = compile(input);
const segmented = parse(input, segmentDuration);
const playlist = hlsSegmentPlaylist(input, segmentDuration);
const segments = hlsSegment(input, segmentDuration, startOffset);
Parses the Subrip file and returns an object with valid === true
if parsed correctly and an array of cues parsed.
Each cue can have:
identifier
- Id, if any of the cuestart
- Start time of cue in secondsend
- End time of cue in secondstext
- Text of the subtitlestyles
- If any of the cue
If the Subrip file is invalid, the parser will throw a ParserError
exception. So for safety, calls to parse
should be in try catch
.
For the above example we'd get:
{
"valid":true,
"cues":[
{
"identifier":"",
"start":0,
"end":1,
"text":"Hello world!",
"styles":""
},
{
"identifier":"",
"start":30,
"end":31,
"text":"This is a subtitle",
"styles":"align:start line:0%"
},
{
"identifier":"",
"start":60,
"end":61,
"text":"Foo",
"styles":""
},
{
"identifier":"",
"start":110,
"end":111,
"text":"Bar",
"styles":""
}
]
}
By default the parser is strict. It will throw errors if:
- If any cue is malformed in any way
Setting the option parameter of strict
to false
will allow files with malformed cues to be parsed. The resulting object will have valid === false
and all errors in an errors
array.
If strict
is set to false
, the parser will also not categorize it as an error if a cue starts and ends at the same time. This might be the correct behaviour but changing would introduce a breaking change in version 1.x.
By passing { meta: true }
to the parse
method, these metadata will be returned as an object called meta
. For example, parsing the above example:
parse(subrip, { meta: true });
would return the following:
{
"valid":true,
"meta":{
"Kind": "captions",
"Language": "en"
},
"cues":[
{
"identifier":"",
"start":0,
"end":1,
"text":"Hello world!",
"styles":""
}
]
}
If no metadata is available, meta
will be set to null
in the result if the option is specified.
Compiles JSON from the above format back into a Subrip string. If a meta
key is in the input,
it will be compiled as well. The meta
value must be an object and each key and value must be a string.
If the object is missing any attributes, the compiler will throw a CompilerError
exception. So
for safety, calls to compile
should be in try catch
.
const input = {
meta: {
Kind: 'captions',
Language: 'en'
},
cues: [{
end: 140,
identifier: '1',
start: 135.001,
text: 'Hello world',
styles: ''
}],
valid: true
};
const result = compile(input);
/*
1
00:02:15.001 --> 00:02:20.000
Hello world
*/
Segments a subtitle according to how it should be segmented for HLS subtitles.
- Does a one pass of the cues for segmenting, this might have been a good idea or bad, only time will tell
- The One and Only Source of Truth is Apple's
mediasubtitlesegmenter
CLI
For the above example:
[
{ duration: 10, cues: [ [Object] ] },
{ duration: 30, cues: [ [Object] ] },
{ duration: 30, cues: [ [Object] ] },
{ duration: 41, cues: [ [Object] ] }
]
Creates a subtitle playlist. For the above:
#EXTM3U
#EXT-X-TARGETDURATION:41
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:10.00000,
0.srt
#EXTINF:30.00000,
1.srt
#EXTINF:30.00000,
2.srt
#EXTINF:41.00000,
3.srt
#EXT-X-ENDLIST
Creates a list of HLS segments for the subtitles, returning an array of them with filename
and content
.
[
{
"filename":"0.srt",
"content":"X-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000\n\n1\n00:00:00.000 --> 00:00:01.000\nHello world!\n"
},
{
"filename":"1.srt",
"content":"X-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000\n\n2\n00:00:30.000 --> 00:00:31.000 align:start line:0%\nThis is a subtitle\n"
},
{
"filename":"2.srt",
"content":"X-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000\n\n3\n00:01:00.000 --> 00:01:01.000\nFoo\n"
},
{
"filename":"3.srt",
"content":"X-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000\n\n4\n00:01:50.000 --> 00:01:51.000\nBar\n"
}
]
This has been written with TDD so we've got a good coverage of the features.
pnpm install
pnpm test