Sync subtitles

From Rosetta Code
Revision as of 02:06, 16 June 2024 by Jjuanhdez (talk | contribs) (Added C++)
Task
Sync subtitles
You are encouraged to solve this task according to the task description, using any language you may know.

Sync subtitles

Sync subtitles

Sometimes, when you download a movie, the subtitles are out of sync with the audio in this movie. Video players like VLC solve the problem, but it must be done manually.

Make a program that takes the "movie.srt" file, and synchronizes the subtitles "n" seconds.

  • Try to fast-forward the subtitles by 9 seconds.
  • Try rolling back the subtitles by 9 seconds.

Take the excerpt from the following subtitles file as an example:


movie.srt

1
00:01:31,550 --> 00:01:36,347
Four billion years ago,
the first marine life forms.

2
00:01:36,555 --> 00:01:42,019
First came the fish...then slowly
other life forms evolved.

3
00:01:42,144 --> 00:01:43,979
Therefore, our ancestors...

4
00:01:43,979 --> 00:01:45,898
...came from fish.

5
00:01:46,232 --> 00:01:47,608
Everyone, come and see this.

6
00:01:47,733 --> 00:01:50,361
Cretaceous Tyrannosaurus.

7
00:01:50,736 --> 00:01:52,488
Ferocious!

8
00:01:58,035 --> 00:01:58,869
Red,

9
00:01:59,203 --> 00:02:00,079
Pong!

10
00:02:02,540 --> 00:02:03,999
Isn't this a gecko?

11
00:02:04,416 --> 00:02:07,419
How else can I get a 15 ton T-Rex in here?

12
00:02:07,503 --> 00:02:11,048
With our advanced technology, I shrank it down.



Amazing Hopper

#include <basico.h>

algoritmo
    
    fd=0
    abrir para leer ( "movie.srt", fd )
    
    iterar 
         s="", t1=0, t2=0, s1=0, s2=0
         usando '1000', leer línea desde 'fd', mover a 's'
         
         cuando ( "-->", está exactamente en 's' ){
              [1:8] obtener de 's', ---copiar en 's1'---
              convertir a segundos, sumarle '9', convertir a hora, guardar en 't1'
              [18:25] obtener de 's', ---copiar en 's2'--- 
              convertir a segundos, sumarle '9', convertir a hora, guardar en 't2'
              
              transformar(s1,t1,s), guardar en 's'
              transformar(s2,t2,s), guardar en 's'

         }
         imprimir ( s, "\n")
         
    mientras ' no sea fin de archivo (fd ) '
    
    cerrar archivo 'fd'
    
terminar
Output:
$ hopper3 basica/modsrt.bas > movie_corrected.srt
$ cat movie_corrected.srt
1  
00:01:40,550 --> 00:01:45,347
Four billion years ago,
the first marine life forms.

2
00:01:45,555 --> 00:01:51,019
First came the fish...then slowly
other life forms evolved.

3
00:01:51,144 --> 00:01:52,979
Therefore, our ancestors...

4
00:01:52,979 --> 00:01:54,898
...came from fish.

5
00:01:55,232 --> 00:01:56,608
Everyone, come and see this.

6
00:01:56,733 --> 00:01:59,361
Cretaceous Tyrannosaurus.

7
00:01:59,736 --> 00:02:01,488
Ferocious!

8
00:02:07,035 --> 00:02:07,869
Red,

9
00:02:08,203 --> 00:02:09,079
Pong!

10
00:02:11,540 --> 00:02:12,999
Isn't this a gecko?

11
00:02:13,416 --> 00:02:16,419
How else can I get a 15 ton T-Rex in here?

12
00:02:16,503 --> 00:02:20,048
With our advanced technology, I shrank it down.

BASIC

BASIC256

Translation of: FreeBASIC
f = freefile
print "After fast-forwarding 9 seconds:" + chr(10)
call syncSubtitles("movie.srt", "movie_corrected.srt", 9)
open f, "movie_corrected.srt"
while not eof(f)
	linea = readline (f)
	print linea;
end while
close

print chr(10) + chr(10)
print "After rolling-back 9 seconds:" + chr(10)
call syncSubtitles("movie.srt", "movie_corrected2.srt", -9)
open f, "movie_corrected2.srt"
while not eof(f)
	linea = readline (f)
	print linea;
end while
close
end

function addSeconds (timestring, secs)
	hh = int(mid(timestring, 1, 2))
	mm = int(mid(timestring, 4, 2))
	ss = int(mid(timestring, 7, 2)) + secs
	ttt = int(mid(timestring, 10, 3))

	while ss < 0
		ss = ss + 60
		mm = mm - 1
	end while
	while mm < 0
		mm = mm + 60
		hh = hh - 1
	end while
	while hh < 0
		hh = hh + 24
	end while

	mm = mm + ss \ 60
	hh = hh + mm \ 60
	ss = ss mod 60
	mm = mm mod 60
	hh = hh mod 24
	return right("0" + string(hh), 2) + ":" + right("0" + string(mm), 2) + ":" + right("0" + string(ss), 2) + "," + right("000" + string(ttt), 3)
end function

subroutine syncSubtitles (fileIn, fileOut, secs)
	fmt = "hh:MM:ss,ttt"
	f1 = freefile
	open f1, fileOut
	f2 = freefile
	open f2, fileIn
	while not eof(f2)
		linea = readline (f2)
		if instr(linea, "-->") > 0 then
			pio = mid(linea, 1, 12)
			pio = addSeconds(pio, secs)
			fin = mid(linea, 18, 12)
			fin = addSeconds(fin, secs)
			write f1, pio; " --> "; fin + chr(10)
		else
			write f1, linea
		end if
	end while
	close
end subroutine

Chipmunk Basic

Translation of: FreeBASIC
Works with: Chipmunk Basic version 3.6.4
100 cls
110 print "After fast-forwarding 9 seconds:";chr$(10)
120 syncsubtitles("movie.srt","movie_corrected.srt",9)
130 open "movie_corrected.srt" for input as #1
140 while not eof(1)
150   line input #1,linea$
160   print linea$
170 wend
180 close #1
190 print
200 print "After rolling-back 9 seconds:";chr$(10)
210 syncsubtitles("movie.srt","movie_corrected2.srt",-9)
220 open "movie_corrected2.srt" for input as #1
230 while not eof(1)
240   line input #1,linea$
250   print linea$
260 wend
270 close #1
280 end
290 sub addseconds$(timestr$,secs)
300   hh = val(mid$(timestr$,1,2))
310   mm = val(mid$(timestr$,4,2))
320   ss = val(mid$(timestr$,7,2))+secs
330   ttt = val(mid$(timestr$,10,3))
340   while ss < 0
350     ss = ss+60
360     mm = mm-1
370   wend
380   while mm < 0
390     mm = mm+60
400     hh = hh-1
410   wend
420   while hh < 0
430     hh = hh+24
440   wend
450   mm = mm+int(ss/60)
460   hh = hh+int(mm/60)
470   ss = ss mod 60
480   mm = mm mod 60
490   hh = hh mod 24
500   addseconds$ = right$("0"+str$(hh),2)+":"+right$("0"+str$(mm),2)+":"+right$("0"+str$(ss),2)+","+right$("000"+str$(ttt),3)
510 end sub
520 sub syncsubtitles(filein$,fileout$,secs)
530   fmt$ = "hh:MM:ss,ttt"
540   open fileout$ for output as #1
550   open filein$ for input as #2
560   while not eof(2)
570     line input #2,linea$
580     if instr(linea$,"-->") > 0 then
590       pio$ = mid$(linea$,1,12)
600       pio$ = addseconds$(pio$,secs)
610       fin$ = mid$(linea$,18,12)
620       fin$ = addseconds$(fin$,secs)
630       print #1,pio$;" --> ";fin$
640     else
650       print #1,linea$
660     endif
670   wend
680   close #2
690   close #1
700 end sub

FreeBASIC

Translation of: Wren
Function addSeconds(timeStr As String, secs As Integer) As String
    Dim As Integer hh, mm, ss, ttt
    hh = Val(Mid(timeStr, 1, 2))
    mm = Val(Mid(timeStr, 4, 2))
    ss = Val(Mid(timeStr, 7, 2)) + secs
    ttt = Val(Mid(timeStr, 10, 3))
    
    While ss < 0
        ss += 60
        mm -= 1
    Wend
    While mm < 0
        mm += 60
        hh -= 1
    Wend
    While hh < 0
        hh += 24
    Wend
    
    mm += ss \ 60
    hh += mm \ 60
    ss Mod= 60
    mm Mod= 60
    hh Mod= 24
    Return Right("0" & Str(hh), 2) & ":" & Right("0" & Str(mm), 2) & ":" & _
    Right("0" & Str(ss), 2) & "," & Right("000" & Str(ttt), 3)
End Function

Sub syncSubtitles(fileIn As String, fileOut As String, secs As Integer)
    Dim As String linea, pio, fin, fmt
    Dim As Ubyte f1, f2
    
    fmt = "hh:MM:ss,ttt"
    f1 = Freefile
    Open fileOut For Output As #f1
    f2 = Freefile
    Open fileIn For Input As #f2
    While Not Eof(f2)
        Line Input #f2, linea
        If Instr(linea, "-->") > 0 Then
            pio = Mid(linea, 1, 12)
            pio = addSeconds(pio, secs)
            fin = Mid(linea, 18, 12)
            fin = addSeconds(fin, secs)
            Print #f1, pio; " --> "; fin
        Else
            Print #f1, linea
        End If
    Wend
    Close #f2, #f1
End Sub

Dim As String linea
Dim As Ubyte f = Freefile

Print !"After fast-forwarding 9 seconds:\n"
syncSubtitles("movie.srt", "movie_corrected.srt", 9)
Open "movie_corrected.srt" For Input As #f
While Not Eof(f)
    Line Input #f, linea
    Print linea
Wend
Close #f

Print !"\n\nAfter rolling-back 9 seconds:\n"
syncSubtitles("movie.srt", "movie_corrected2.srt", -9)
Open "movie_corrected2.srt" For Input As #f
While Not Eof(f)
    Line Input #f, linea
    Print linea
Wend
Close #f

Sleep
Output:
Same as Wren entry.

QB64

Dim As String linea
f = FreeFile

Print "After fast-forwarding 9 seconds:"; Chr$(10)
Call syncSubtitles("movie.srt", "movie_corrected.srt", 9)
Open "movie_corrected.srt" For Input As #f
While Not EOF(f)
    Line Input #f, linea
    Print linea
Wend
Close #f

Print Chr$(10); Chr$(10); "After rolling-back 9 seconds:"; Chr$(10)
Call syncSubtitles("movie.srt", "movie_corrected2.srt", -9)
Open "movie_corrected2.srt" For Input As #f
While Not EOF(f)
    Line Input #f, linea
    Print linea
Wend
Close #f

Function addSeconds$ (timeStr As String, secs As Integer)
    Dim As Integer hh, mm, ss, ttt
    hh = Val(Mid$(timeStr, 1, 2))
    mm = Val(Mid$(timeStr, 4, 2))
    ss = Val(Mid$(timeStr, 7, 2)) + secs
    ttt = Val(Mid$(timeStr, 10, 3))

    While ss < 0
        ss = ss + 60
        mm = mm - 1
    Wend
    While mm < 0
        mm = mm + 60
        hh = hh - 1
    Wend
    While hh < 0
        hh = hh + 24
    Wend

    mm = mm + ss \ 60
    hh = hh + mm \ 60
    ss = ss Mod 60
    mm = mm Mod 60
    hh = hh Mod 24
    addSeconds$ = Right$("0" + Str$(hh), 2) + ":" + Right$("0" + Str$(mm), 2) + ":" + Right$("0" + Str$(ss), 2) + "," + Right$("000" + Str$(ttt), 3)
End Function

Sub syncSubtitles (fileIn As String, fileOut As String, secs As Integer)
    Dim As String linea, pio, fin, fmt
    Dim As Integer f1, f2

    fmt = "hh:MM:ss,ttt"
    f1 = FreeFile
    Open fileOut For Output As #f1
    f2 = FreeFile
    Open fileIn For Input As #f2
    While Not EOF(f2)
        Line Input #f2, linea
        If InStr(linea, "-->") > 0 Then
            pio = Mid$(linea, 1, 12)
            pio = addSeconds$(pio, secs)
            fin = Mid$(linea, 18, 12)
            fin = addSeconds$(fin, secs)
            Print #f1, pio; " --> "; fin
        Else
            Print #f1, linea
        End If
    Wend
    Close #f2, #f1
End Sub

C++

Translation of: FreeBASIC
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <ctime>

using namespace std;

string addSeconds(string timeStr, int secs) {
	int hours, minutes, seconds, milliseconds;
	sscanf(timeStr.c_str(), "%d:%d:%d,%d", &hours, &minutes, &seconds, &milliseconds);
	int total_seconds = hours * 3600 + minutes * 60 + seconds + secs;
	hours = total_seconds / 3600;
	total_seconds %= 3600;
	minutes = total_seconds / 60;
	seconds = total_seconds % 60;
	char buffer[13];
	sprintf(buffer, "%02d:%02d:%02d,%03d", hours, minutes, seconds, milliseconds);
	return string(buffer);
}

void syncSubtitles(string fileIn, string fileOut, int secs) {
	ifstream fin(fileIn);
	ofstream fout(fileOut);
	string line;
	while (getline(fin, line)) {
		if (line.find("-->") != string::npos) {
			string start = line.substr(0, 12);
			string end = line.substr(17, 12);
			start = addSeconds(start, secs);
			end = addSeconds(end, secs);
			fout << start << " --> " << end << "\n";
		} else {
			fout << line << "\n";
		}
	}
	fin.close();
	fout.close();
}

int main() {
	cout << "After fast-forwarding 9 seconds:\n\n";
	syncSubtitles("movie.srt", "movie_corrected.srt", 9);
	ifstream f("movie_corrected.srt");
	string line;
	while (getline(f, line)) {
		cout << line << "\n";
	}
	f.close();
	
	cout << "\n\nAfter rolling-back 9 seconds:\n\n";
	syncSubtitles("movie.srt", "movie_corrected2.srt", -9);
	ifstream f2("movie_corrected2.srt");
	while (getline(f2, line)) {
		cout << line << "\n";
	}
	f2.close();
	
	return 0;
}
Output:
Same as FreeBASIC entry.

Phix

Needed a bugfix to adjust_timedate() for time-only handling, in that a y,m,d of 0,0,0 pre-dates the introduction of the Gregorian calendar. There was also a floor(milliseconds) which should have been/is now round(milliseconds). Fixes can be grabbed from github if needed.

requires("1.0.6") -- (a time-only handling bugfix in adjust_timedate)

constant movie_srt = `
1
00:01:31,550 --> 00:01:36,347
Four billion years ago,
00:01:36,555 --> 00:01:42,019
00:01:42,144 --> 00:01:43,979
00:01:43,979 --> 00:01:45,898
00:01:46,232 --> 00:01:47,608
00:01:47,733 --> 00:01:50,361
00:01:50,736 --> 00:01:52,488
00:01:58,035 --> 00:01:58,869
00:01:59,203 --> 00:02:00,079
00:02:02,540 --> 00:02:03,999
00:02:04,416 --> 00:02:07,419
00:02:07,503 --> 00:02:11,048
With our advanced technology, I shrank it down.
`,
sep = ` --> `,
fmt = `hh:mm:ss,ms`
include timedate.e

for line in split(movie_srt,'\n') do
    if match(sep,line) then
        line = split(line,sep)
        for i,t in line do
            timedate td = parse_date_string(t,{fmt}) 
            line[i] = format_timedate(adjust_timedate(td,9),fmt)
        end for
        line = join(line,sep)
    end if
    printf(1,"%s\n",line)
end for
Output:
1
00:01:40,550 --> 00:01:45,347
Four billion years ago,
00:01:45,555 --> 00:01:51,019
00:01:51,144 --> 00:01:52,979
00:01:52,979 --> 00:01:54,898
00:01:55,232 --> 00:01:56,608
00:01:56,733 --> 00:01:59,361
00:01:59,736 --> 00:02:01,488
00:02:07,035 --> 00:02:07,869
00:02:08,203 --> 00:02:09,079
00:02:11,540 --> 00:02:12,999
00:02:13,416 --> 00:02:16,419
00:02:16,503 --> 00:02:20,048
With our advanced technology, I shrank it down.

Python

Library: datetime
Works with: Python version 3.x
Translation of: FreeBASIC
#! /usr/bin/env python3

import datetime

def add_seconds(time_str, secs):
    time_format = "%H:%M:%S,%f"
    time_obj = datetime.datetime.strptime(time_str, time_format)
    delta = datetime.timedelta(seconds=secs)
    new_time_obj = time_obj + delta
    new_time_str = new_time_obj.strftime(time_format)[:-3]  # remove the last 3 digits of microseconds
    return new_time_str

def sync_subtitles(file_in, file_out, secs):
    with open(file_in, 'r') as fin, open(file_out, 'w') as fout:
        for line in fin:
            if '-->' in line:
                start_time, end_time = line.strip().split(' --> ')
                start_time = add_seconds(start_time, secs)
                end_time = add_seconds(end_time, secs)
                fout.write(f"{start_time} --> {end_time}\n")
            else:
                fout.write(line)

print("After fast-forwarding 9 seconds:\n")
sync_subtitles("movie.srt", "movie_corrected.srt", 9)
with open("movie_corrected.srt", 'r') as f:
    print(f.read())

print("\n\nAfter rolling-back 9 seconds:\n")
sync_subtitles("movie.srt", "movie_corrected2.srt", -9)
with open("movie_corrected2.srt", 'r') as f:
    print(f.read())
Output:
Same as FreeBASIC entry.

Wren

Library: Wren-date
Library: Wren-ioutil
import "./date" for Date
import "./ioutil" for File, FileUtil

var syncSubtitles = Fn.new { |fileIn, fileOut, secs|
    var nl = FileUtil.lineBreak
    var fmt = "hh|:|MM|:|ss|,|ttt"
    var f = File.create(fileOut)
    for (line in FileUtil.readLines(fileIn)) {
        if (line.contains("-->")) {
            var start = line[0..11]
            var startDate = Date.parse(start, fmt).addSeconds(secs)
            start = startDate.format(fmt)
            var end = line[17..28]
            var endDate = Date.parse(end, fmt).addSeconds(secs)
            end = endDate.format(fmt)
            f.writeBytes(start + " --> " + end + nl)
         } else {
            f.writeBytes(line + nl)
         }
    }
    f.close()
}

System.print("After fast-forwarding 9 seconds:\n")
syncSubtitles.call("movie.srt", "movie_corrected.srt", 9)
System.print(File.read("movie_corrected.srt"))
System.print("After rolling-back 9 seconds:\n")
syncSubtitles.call("movie.srt", "movie_corrected2.srt", -9)
System.print(File.read("movie_corrected2.srt"))
Output:
After fast-forwarding 9 seconds:

1
00:01:40,550 --> 00:01:45,347
Four billion years ago,
the first marine life forms.

2
00:01:45,555 --> 00:01:51,019
First came the fish...then slowly
other life forms evolved.

3
00:01:51,144 --> 00:01:52,979
Therefore, our ancestors...

4
00:01:52,979 --> 00:01:54,898
...came from fish.

5
00:01:55,232 --> 00:01:56,608
Everyone, come and see this.

6
00:01:56,733 --> 00:01:59,361
Cretaceous Tyrannosaurus.

7
00:01:59,736 --> 00:02:01,488
Ferocious!

8
00:02:07,035 --> 00:02:07,869
Red,

9
00:02:08,203 --> 00:02:09,079
Pong!

10
00:02:11,540 --> 00:02:12,999
Isn't this a gecko?

11
00:02:13,416 --> 00:02:16,419
How else can I get a 15 ton T-Rex in here?

12
00:02:16,503 --> 00:02:20,048
With our advanced technology, I shrank it down.


After rolling-back 9 seconds:

1
00:01:22,550 --> 00:01:27,347
Four billion years ago,
the first marine life forms.

2
00:01:27,555 --> 00:01:33,019
First came the fish...then slowly
other life forms evolved.

3
00:01:33,144 --> 00:01:34,979
Therefore, our ancestors...

4
00:01:34,979 --> 00:01:36,898
...came from fish.

5
00:01:37,232 --> 00:01:38,608
Everyone, come and see this.

6
00:01:38,733 --> 00:01:41,361
Cretaceous Tyrannosaurus.

7
00:01:41,736 --> 00:01:43,488
Ferocious!

8
00:01:49,035 --> 00:01:49,869
Red,

9
00:01:50,203 --> 00:01:51,079
Pong!

10
00:01:53,540 --> 00:01:54,999
Isn't this a gecko?

11
00:01:55,416 --> 00:01:58,419
How else can I get a 15 ton T-Rex in here?

12
00:01:58,503 --> 00:02:02,048
With our advanced technology, I shrank it down.