Srt-merge is a small node.js project in one hundred lines.
It can merge two srt files into one with some optional options.
It can shift one srt file at given time to match the video file.
It can place one subtitle at the top of screen and another one at bottom that is very useful for language learners.
You can use this tool in Nodejs or in Bash scripts.
First, npm install or yarn to install dependencies.
Examples are in example.js. Read and run it for a clear understanding.
This project contains one file merge.js, one function merge().
srtPrimary and srtSecondary accept srt-string, or srt-object in the format of npm-module subtitle. They will not be modified by this function.
attr accepts one of the following values, or an array of them. They describe transformations performed on srtSecondary before it is merge into srtPrimary. The action priority will always be "top-bottom", "move", then "nearest-cue".
Attribute inputs and corresponding effects:
-
<empty string> or <undefined> or "simple"
Simply merge two files.
-
top-bottom
Place srtPrimary at video bottom, srtSecondary at video top, using ass-file-format tag {\an8} in srt-file output. This feature is supported by many video players including VLC, MPC-HC.
-
nearest-cue-<threshold>[-no-append]
Cues in srtSecondary will be appended to corresponding cues in srtPrimary if the difference of their start time is no larger than the given threshold. If srtSecondary has multiple cues within the threshold, srtPrimary will append the earliest one.
no-append means srtSecondary will only be aligned with srtPrimary within a start time threshold. Whose start time are aligned, whose end time will also be aligned if they are within the threshold.
-
move-<time shifted>
srtSecondary will be shifted (can be forward or backward) and merged into srtPrimary.
noString takes true or false, if it's true, output the srt-object, otherwise output srt text.
If you only want to edit one file, leave the srtPrimary(not srtSecondary) with an empty string.
These JS Scripts read options from command line and output to stdout by default. They are helpful in writing bash scripts. Use 'yarn build' to build them, which requires 'yarn global add browserify'.
This can only accept one attr, not an array of them. When -o <out-file> is not specified, it will output to stdout. -f option means overwrite existing file without prompt. Both input srt files must be text files encoded in utf-8. Piping is under construction.
./srt-merge.js <srt-file-1> [<srt-file-2>] [<one-attr>] [-o [-f(force)] <output Filepath>]
This example is for Windows.
Suppose you want to show subtitles of two languages at the same time, and now both of them are embedded in an MKV video file. You want to extract them out and combine into one.
First, use ffmpeg to check which track is the subtitle you want.
ffmpeg -i <your_mkv_file>
You will see something like:
Stream #0:10(eng): Subtitle: subrip
Metadata:
title : English [Forced]
That means subtitle English[Forced] is on track 0:10. -map option is used to extract it.
ffmpeg -stats -v error -i <your_mkv_file> -map <track(here is 0:10)> <output_file(eng.srt)>
In the same way you can extract JPN subtitles.
ffmpeg -stats -v error -i "xxx.mkv" -map 0:12 "xxx jpn.srt"
Then use this project to merge them.
./srt-merge.js "xxx eng.srt" "xxx jpn.srt" top-bottom -o "xxx merged.srt"
Now, combine these processes into one script.
// Powershell
Get-ChildItem ./ *.mkv | ForEach-Object {
$srt1 = $_.BaseName + ' eng.srt'
$srt2 = $_.BaseName + ' jpn.srt'
ffmpeg -stats -v error -i $_.Name -map 0:10 $srt1
ffmpeg -stats -v error -i $_.Name -map 0:12 $srt2
$srt3 = $_.BaseName + ' eng_jpn.srt'
node /path/to/srt-merge.js $srt1 $srt2 top-bottom -o $srt3
}
Get-ChildItem ./ '* eng.srt' | Remove-Item
Get-ChildItem ./ '* jpn.srt' | Remove-Item
This example is for Linux.
Suppose now you have following subtitle files and videos in one folder.
- xx01xx.mkv, xx02xx.mkv, xx03xx.mkv
- yy01yy_en.srt, yy01yy_jp.srt
- yy02yy_en.srt, yy02yy_jp.srt
- yy03yy_en.srt, yy03yy_jp.srt
You want to shift these srt files a few seconds and rename it to match MKV filename.
First, You can use Debian package 'subtitleeditor' - it's a GUI subtitle editor - to check how many seconds to shift.