Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Subtitles Cheatsheet

Preequisites

A lot of the commands in this cheatsheet are based on you having installed the mkvtoolnix package. Luckily, you should be able to install it with:

sudo apt install mkvtoolnix

Listing Tracks

The easiest way to list the subtitle tracks is by running:

mkvmerge -i myFile.mkv

Example output:

File 'S01e01.mkv': container: Matroska
Track ID 0: video (MPEG-4p10/AVC/H.264)
Track ID 1: audio (AC-3)
Track ID 2: subtitles (SubStationAlpha)
Track ID 3: subtitles (SubStationAlpha)
Global tags: 1 entry
Tags for track ID 0: 1 entry
Tags for track ID 1: 1 entry
Tags for track ID 2: 1 entry
Tags for track ID 3: 1 entry

For more detailed information in JSON format (which you could use programmatically), you can use:

mkvmerge \
  --identification-format json \
  --identify input.mkv

Extraction

Mkv files often come with subtitles "buried" within them which are not "hard subbed" (built into the image). These can be extracted with:

mkvextract tracks input.mkv \
  [track number]:subtitles.txt

This will not remove the subtitles from the mkv file.

This may extract an ass or srt file. Read about the differences here, but the TLDR; is that .srt is the most basic, whereas .ass based subtitles allow formatting. E.g different font-colors, positioning etc.

Remove Specific Tracks

If you want to remove a subtitle track, you need to recreate the mkv file and copy across the tracks that you want to keep. The command below will keep tracks 1 and 3, so we are "removing" track 2 (it won't be in the output file).

mkvmerge -o output.mkv \
  --subtitle-tracks 1,3 \
  input.mkv

Remove All Subtitles

The command below will create an output.mkv file from input.mkv, but with no subtitles within it.

mkvmerge -o output.mkv \
  --no-subtitles \
  input.mkv

If you just want to replace subtitles, skip this step and use the -S parameter when merging your own subtitles file.

Merging

If you have two separate files, one MKV video file, and one srt subtitles file, you can merge them easily with:

You can easily add/append a subtitle file to your video file with:

mkvmerge \
  -o output.mkv \
  input.mkv \
  --language "0:eng" \
  --track-name "0:Forced" \
  --forced-track "0:yes" \
  --default-track "0:yes" \
  subtitles.srt

In this case I am adding a "forced" subtitles track to add english subtitles when the characters switch out of speaking english and into another language. E.g. people are speaking english 90% of the time, but occasionally a character will speak in Chinese or Norweigan.</note

If you have an mp4 file instead of an mkv, you can losslessly convert it to an MKV file before performing the step above.

Replace Subtitles

If you wish to replace all of the subtitles in a file with the subtitles file you have, just use the -S parameter like so:

mkvmerge \
  -o output.mkv \
  -S \
  input.mkv \
  --language "0:eng" \
  --track-name "0:Forced" \
  --forced-track "0:yes" \
  --default-track "0:yes" \
  subtitles.srt

Conversion

You can convert from ass to srt with this tool. However, I found that it would insert ? characters wherever it found characters it didn't understand. For example there is a special character for three dots ... which is really common.

Synchronization

VLC media player can use g and h to adjust times to see how much of a delay you need

You can shift srt subtitles (even by fractions of a second) with this online tool

... or this BASH script:

#!/bin/bash

set -o errexit -o noclobber -o nounset -o pipefail

date_offset="$1"

shift_date() {
    date --date="$1 $date_offset" +%T,%N | cut -c 1-12
}

while read -r line
do
    if [[ $line =~ ^[0-9][0-9]:[0-9][0-9]:[0-9][0-9],[0-9][0-9][0-9]\ --\>\ [0-9][0-9]:[0-9][0-9]:[0-9][0-9],[0-9][0-9][0-9]$ ]]
    then
        read -r start_date separator end_date <<<"$line"
        new_start_date="$(shift_date "$start_date")"
        new_end_date="$(shift_date "$end_date")"
        printf "%s %s %s\n" "$new_start_date" "$separator" "$new_end_date"
        echo "New date"
    else
        printf "%s\n" "$line"
    fi
done

Example usage:

./shifter.sh "+3.5 seconds" < input.srt > output.srt

References

Last updated: 15th October 2023
First published: 16th August 2018