Search code examples
delphishiftsubtitle

How to correct / shift subtitle time in SRT (SubRip) files?


How to correct/shift subtitle time forward and backward? Subtitle time format looks like this: 00:00:52,656 --> 00:00:56,326

If subtitle and audio aren't synchronized, for example, subtitle shows up before voice/audio, then all times of subtitle lines (time format: 00:00:52,656 --> 00:00:56,326) should be corrected.

So, if time of all subtitle lines must be changed/shifted for 2 sec. forward, then, this time for subtitle line: 00:00:52,656 --> 00:00:56,326 should be changed to: 00:00:54,656 --> 00:00:58,326.

And this refers to all times in the subtitle file, not just one line of text/one time.


Example of how SubRip (.srt) file looks like:

1
00:00:52,656 --> 00:00:56,326
Kanalska Zona: Panama

2
00:00:56,335 --> 00:00:59,755
Francuzi su pokušali da izgrade
kanal pre Amerikanaca.

Solution

  • Providing that the format of each line in your input is always 00:00:00,000 --> 00:00:00,000, then this routine will convert the string times to TDateTime, add or subtract the shift, and rewrite the line:

    procedure ShiftSubtitleTimes(Lines: TStrings; Diff: TTime);
    var
      FS: TFormatSettings;
      I: Integer;
      T1: TDateTime;
      T2: TDateTime;
    begin
      // Ensure using the correct time separator
      FS.TimeSeparator := ':';
      // Parse each line separately
      for I := 0 to Lines.Count - 1 do
      begin
        // Convert the two time strings to time values
        if not TryStrToTime(Copy(Lines[I], 1, 8), T1, FS) then
          // But skip line in case of wrong format
          Continue;
        T1 := T1 + StrToInt(Copy(Lines[I], 10, 3)) / MSecsPerDay;
        T2 := StrToTime(Copy(Lines[I], 18, 8), FS);
        T2 := T2 + StrToInt(Copy(Lines[I], 27, 3)) / MSecsPerDay;
        // Add the shift
        T1 := T1 + Diff;
        T2 := T2 + Diff;
        // Rewrite the line
        Lines[I] := FormatDateTime('hh:nn:ss,zzz --> ', T1, FS) +
          FormatDateTime('hh:nn:ss,zzz', T2, FS);
      end;
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      List: TStringList;
    begin
      List := TStringList.Create;
      try
        List.LoadFromFile('Filename.dat');
        Memo1.Lines.Add('Input:');
        Memo1.Lines.AddStrings(List);
        Memo1.Lines.Add('');
        // Shift 3,5 seconds backwards:
        ShiftSubtitleTimes(List, -3.5 / SecsPerDay);  
        Memo1.Lines.Add('Output:');
        Memo1.Lines.AddStrings(List);
      finally
        List.Free;
      end;
    end;
    

    enter image description here

    Edit:

    Due to your edit, now input may contain 'wrong' lines that need no conversion too.