Skip to content

Instantly share code, notes, and snippets.

@lovasoa
Last active January 4, 2016 13:59
Show Gist options
  • Save lovasoa/8631850 to your computer and use it in GitHub Desktop.
Save lovasoa/8631850 to your computer and use it in GitHub Desktop.
SRTmove: shift all subtitles from an srt file, in order to make them appear earlier or later.
/***** SRTmove ******
Author: Ophir LOJKINE
Licence: LGPLv3
*/
#ifndef SRTMOVE_LIB_H
#define SRTMOVE_LIB_H
#include <iostream>
/** Reads subtitles in srt format from fin, and writes it to fout, with addition
milliseconds added to each subtitles. addition can be a negative number.
Returns the number of subtitles that were processed, or a negative number if anb error occured.
*/
template<typename INTYPE, typename OUTTYPE>
int srtmove (INTYPE &fin, OUTTYPE &fout, int addition);
/** Converts a value like 12:03, 2m3s, or 8s3ms to a number of milliseconds
arg2msec("1h") == 3600000
arg2msec("1h1m1s1ms") == 60*60*1000 + 60*1000 + 1*1000 + 1 == 3661001
arg2msec("-2:03") == 2*60*1000 + 3*1000 == -123000 //Removes 2 minutes and 3 seconds to every subtitles
*/
int arg2msec(const char *arg);
#include "srtmove-lib.tpp"
#endif
/***** SRTmove ******
Author: Ophir LOJKINE
Licence: LGPLv3
Adds or removes time from the subtitles inside an .srt file.
This version is easier to work with on Windows. It takes a list of subtitles as command-line
arguments, and prompts the user for a time, and outputs the resynced subtitles to files in the same
directory as the input files.
You can use Windows' "Open with" functionality with this program.
*/
#include <iostream> // std::cin, std::cout
#include <stdio.h>
#define LINE_LEN 256
using namespace std;
int str2msec (char *line) {
int mul[12] = {36000000, 3600000, 0, 600000, 60000, 0, 10000, 1000, 0, 100, 10, 1},
msec = 0;
for (int i=11; i>=0; i--) {
msec += mul[i] * (int) (line[i]-'0');
}
return msec;
}
void msec2str (int msec, char *out) {
int ms = msec%1000; msec /= 1000;
int s = msec%60; msec /= 60;
int m = msec%60; msec /= 60;
int h = msec;
sprintf(out, "%02d:%02d:%02d,%02d", h,m,s,ms/10);
out[11] = (char) ('0' + ms%10);
}
/**Returns true if s begins with pat, where pat is a string with a simple format 'N' matches a number, any other character matches only itself.*/
bool matchpattern(char *s, char *pat) {
int i;
for (i=0; pat[i] != '\0' && s[i] != '\0'; i++) {
if (pat[i] == 'N' && s[i] <= '9' && s[i] >= '0') continue;
if (pat[i] != s[i]) return false;
}
return (pat[i] == '\0');
}
int arg2msec(const char *arg) { // arg can ba "6" for 6 seconds or "3:10" for 3 minutes
size_t len = char_traits<char>::length(arg);
int mul = 1000;
int res = 0;
int sgn = (arg[0] == '-') ? -1 : 1;
for (int i = len-1; i>=0 && arg[i] != '-' && arg[i] != '+'; i--) {
switch (arg[i]) {
case 's': mul=1000; break;
case ':': mul = mul/10 * 6; break;
case 'm':
if(i<len-1 && arg[i+1] == 's') mul=1;//ms
else mul = 60000;
break;
case 'h': mul = 3600000; break;
default:
if ('0' <= arg[i] && arg[i] <= '9'){
res += mul * int(arg[i] - '0');
mul *= 10;
} else {
cerr << "Malformed argument." << endl;
cerr << "You can type -10m3s for making your subtitles appear 10 minutes and 3 seconds earlier, for instance." <<endl;
return 0;
}
}
}
return sgn*res;
}
template<typename INTYPE, typename OUTTYPE>
int srtmove (INTYPE &fin, OUTTYPE &fout, int addition) {
char pattern[] = "NN:NN:NN,NNN --> NN:NN:NN,NNN";
char line[LINE_LEN];
if (!fin.good() || !fout.good()) return -1;
int subcount = 0;
while (fin.good()) {
fin.getline (line, LINE_LEN);
size_t size = char_traits<char>::length(line);
if (matchpattern(line, pattern)) {
int t1 = str2msec(line),
t2 = str2msec(line + 17);
t1 = (t1 > -addition) ? t1 + addition : 0;
t2 = (t2 > -addition) ? t2 + addition : 0;
msec2str(t1, line);
msec2str(t2, line+17);
subcount++;
}
fout.write(line, size);
if (!fin.fail()) { //A full line was read
fout << endl;
}
}
return subcount;
}

SRTmove

Compilation

g++ -o srtmove srtmove.cpp

This small programm uses no library.

Usage

./srtmove time < input_file.srt > shifted_file.srt

Where time can be of the format XmYs with X the number of minutes and Y the number of seconds to add to the time of each subtitle. If only a number is provided, it will be interpreted as a number of seconds. time can also contain a number of hours and a number of milliseconds: XhYmZsMms

For instance, if you want to remove 2 minutes ans 30 seconds to all subtitles in the file film.srt and save the result in the file film.corrected.srt, you can run:

./srtmove -2m30s < film.srt > film.corrected.srt
/* SRTmove
by Ophir LOJKINE
Adds or removes time from the subtitles inside an .srt file.
This version is UNIX friendly it reads a subtitle file from it's standard input,
takes it's parameter as a command-line argument, and outputs the new subtitles to it's standard output.
*/
#include <iostream>
#include "srtmove-lib.h"
int main (int argc, char **argv) {
if (argc != 2) {
cerr << "Wrong argument count.\n\tUsage: srtmove time\n\t(where time can be in format -3m2s for substracting 3 minutes and 2 seconds to all subtitles)" << endl;
return 1;
}
int addition = arg2msec(argv[1]);
int num = srtmove(std::cin, std::cout, addition);
return (num > 0) ? 0 : 2;
}
/* SRTmove
by Ophir LOJKINE
Adds or removes time from the subtitles inside an .srt file.
This version is easier to work with on Windows. It takes a list of subtitles as command-line
arguments, and prompts the user for a time, and outputs the resynced subtitles to files in the same
directory as the input files.
You can use Windows' "Open with" functionality with this program.
*/
#include "srtmove-lib.h"
#include <fstream> // std::ifstream, std::ofstream
#include <vector>
#include <string>
using namespace std;
struct t_outfile {
string name;
int subcount;
};
int main (int argc, char **argv) {
if (argc < 2) {
cerr << "No file to handle..." << endl;
return 1;
}
string addstr;
int addition=0;
while (addition == 0) {
cout << "Time to add (MM:SS): ";
cin >> addstr;
if (addstr.find("exit") == 0 || addstr.find("quit") == 0) return 1;
addition = arg2msec(addstr.c_str());
};
vector <t_outfile*> outfiles;
for (int numfile=1; numfile < argc; numfile++) {
char *finname = argv[numfile];
string foutname (finname);
size_t pos = foutname.rfind(".srt");
if (pos == string::npos) pos = foutname.size()-1;
foutname.replace(pos, 4, "-resync.srt");
ifstream fin (finname);
if (!fin.good()) {
cerr << "Unable to open input file: " << finname << endl;
continue;
}
ofstream fout (foutname.c_str());
if (!fout.good()) {
cerr << "Unable to open output file: " << foutname << endl;
continue;
}
int subcount = srtmove (fin, fout, addition);
if (subcount < 0) {
cerr << "Sorry, an error occured in srtmove." << endl;
continue;
} else if (subcount == 0) {
cerr << "No subtitles found in file: " << finname << endl;
continue;
} else { //Everything went well
t_outfile* outfile = new t_outfile;
outfiles.push_back(outfile);
outfile->name = foutname;
outfile->subcount = subcount;
}
}
cerr << "End of program. Files created:" << endl;
for (int i=0; i<outfiles.size(); i++) {
cerr << " - " << outfiles[i]->name;
cerr << " (" << outfiles[i]->subcount << " subtitles)" <<endl;
delete outfiles[i];
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment