rss logo

Bash Script: Adjust Subtitle Delay in .srt Files

Terminal logo

Subtitle synchronization issues between SRT subtitle files and video files are a frequent annoyance. Often, the SRT file’s timing isn’t perfectly matched to the source video, causing delays ranging from a few milliseconds to several seconds that disrupt your viewing experience.

While media players like VLC, MPV, and MPlayer offer on-the-fly subtitle delay adjustments (see Linux media player commands), these temporary settings revert when you reload the video. A more reliable approach is to edit the subtitle file itself.

This guide introduces a lightweight Bash script designed to adjust subtitle delay in your .srt files, ensuring perfect subtitle synchronization every time.

Usage

Use the following syntax to adjust the timing of an SRT subtitle file:

user@host:~$ ./shebangthe_srt.sh -f [srt file] -t '[+/- time]'
  • Subtract 0.400 seconds from subtitles:
user@host:~$ ./shebangthe_srt.sh -f /home/std/Running.on.Empty.1988.1080p.BluRay.x264.AAC.5.1-POOP.srt -t '- 0.400'
  • Add 1.400 seconds to subtitles:
user@host:~$ ./shebangthe_srt.sh -f /home/std/Running.on.Empty.1988.1080p.BluRay.x264.AAC.5.1-POOP.srt -t '+ 1.400'

SRT File Format

This script is designed to work exclusively with standard SRT subtitle files that follow the format shown below:

[…]
1126
01:55:12,527 --> 01:55:14,461
I love you.

1127
01:55:20,735 --> 01:55:22,669
I really love you.

Bash Script

The following Bash script modifies the timestamps in a standard .srt subtitle file, allowing you to shift the timing forward or backward with millisecond precision.

#! /bin/bash

IFS=$'\n'
option_F_found=0
option_T_found=0

usage()
{
        echo "usage: ./subtitles.sh -f [srt file] -t '[+/- time]'"
        echo "ex : ./subtitles.sh -f /home/std/lecuisinierlevoleursafemmeetsonamant.srt -t '- 18.100'"
        echo "ex : ./subtitles.sh -f /home/std/lecuisinierlevoleursafemmeetsonamant.srt -t '+ 18.100'"
        echo ""
        exit 3
}

while getopts f:t: OPTNAME; do
        case "$OPTNAME" in
        f)
                FILE="$OPTARG"
                option_F_found=1
                ;;

        t)
                TIME="$OPTARG"
                option_T_found=1
                ;;


        *)
                usage
                ;;
        esac
done

if [ "$option_F_found" -eq "0" ] || [ "$option_T_found" -eq "0" ]; then
        usage
fi

FunctionDuration()
{
        duration_temp=$(date -d "1983-12-12 $1" "+%s.%3N")
        duration_diff=$(echo "scale=3; $duration_temp $TIME" | bc -l)
        duration_dest=$(date -d"@$duration_diff" "+%H:%M:%S,%3N")
        echo "$duration_dest"
}


for i in $(grep -E "[0-9]{2}:[0-9]{2}\,[0-9]{3}" "$FILE");
do
        A=$(echo "$i" | sed 's/\([0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}\,[0-9]\{3\}\) --> \([0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}\,[0-9]\{3\}\)/\1/')
        B=$(echo "$i" | sed 's/\([0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}\,[0-9]\{3\}\) --> \([0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}\,[0-9]\{3\}\)/\2/')
        VAL1=$(FunctionDuration "$A")
        VAL2=$(FunctionDuration "$B")
        echo "working on $A --> $B"
        sed -i "s/$i/$VAL1 --> $VAL2/" "$FILE"
done