fix _time_add bug
[srtscroll.git] / srtscroll.pl
blob4ce8cddcf299efd2778be57811717889e1289384
1 #!/usr/bin/env perl
3 # Copyright (c) 2009 Abel Abraham Camarillo Ojeda <acamari@the00z.org>
5 # Permission to use, copy, modify, and distribute this software for any
6 # purpose with or without fee is hereby granted, provided that the above
7 # copyright notice and this permission notice appear in all copies.
9 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 # srtscroll.pl: "scrolls" the time and ids of an srt file by some initial values
18 # it means: it adds to the time and id (of each entry) some values
20 # example:
22 # cat file.srt | ./srtscroll '20' '01:02:03,800'
24 # scrolls file.srt changing each id (adding to it '20') and adding to each
25 # timestamp one hour, two minutes, three seconds and 800 milliseconds
27 # you can get timestamps in milliseconds in mplayer using:
29 # while sleep '.1'; do echo "get_time_pos"; done | mplayer -quiet -slave movie.avi
31 # or try using the x and z keys to delay the subs where you like them
33 # sets debug mode
34 #my $debug = "yes";
36 # a doble line terminator delimits a paragraph (srt entry);
37 # "\r\n" for DOS files, "\n" for everyone else files. (*.srt are commonly DOS
38 # files)
39 my $line_terminator = "\r\n";
41 # id scroll: we are going to add this value to the ids of all entries (can be
42 # negative)
43 my $id_scroll;
44 $id_scroll = shift @ARGV;
46 # time scroll: we are going to add this value to the time of all entries (can be
47 # negative)
49 # this value is specified in the form: hours:minutes:seconds,milliseconds
50 # the value can have leading 0's (zeroes), if any they will be stripped on
51 # before conversion.
53 # limits: hours = 99
54 # minutes = 59
55 # seconds = 59
56 # milliseconds = 999
57 my $time_scroll;
58 $time_scroll = shift @ARGV;
60 # read by "paragraphs"
61 $/ = ($line_terminator x 2);
63 while (<>) {
64 # gets the old srt entry
65 my ($id, $time, @text);
67 ($id, $time, @text) = split $line_terminator;
69 my ($time_start, $time_end);
71 ($time_start, $time_end) = split /\s*-+>\s*/, $time;
73 if (debug("yes") eq "yes") {
74 print '-', $id, $line_terminator,
75 '-', $time, $line_terminator,
76 '-', join ($line_terminator.'-', @text), ($line_terminator);
78 # gets the new srt entry
79 my ($new_id, $new_time);
81 $new_id = $id + $id_scroll;
83 my ($new_time_start, $new_time_end);
85 # if the scroll is negative
86 if ($time_scroll =~ /^-/) {
87 # removes all minus signs
88 my $t = join '', split '-', $time_scroll;
89 $new_time_start = time_min($time_start, $t);
90 $new_time_end = time_min($time_end, $t);
91 } else {
92 my $t = join '', split '-', $time_scroll;
93 $new_time_start = time_add($time_start, $t);
94 $new_time_end = time_add($time_end, $t);
97 $new_time = $new_time_start . " --> " . $new_time_end;
99 print debug('+'), $new_id, $line_terminator,
100 debug('+'), $new_time, $line_terminator,
101 debug('+'), join ($line_terminator.debug('+'), @text),
102 ($line_terminator x 2);
104 #print "a + b: ",
105 # join(' ', time_fold(add_zeroes(time_add([qw(0 59 15 300)], [qw(1 1 1
106 # 1)])))) ,
107 # "\n";
111 debug
113 if (wantarray) {
114 return ($debug =~ /yes/i ? @_ : ());
115 } else {
116 return ($debug =~ /yes/i ? join('',@_) : undef);
120 # high level function...
122 time_add
124 return time_fold(add_zeroes(_time_add(
125 [rm_zeroes(time_unfold($_[0]))],
126 [rm_zeroes(time_unfold($_[1]))])
131 time_min
133 return time_fold(add_zeroes(_time_min(
134 [rm_zeroes(time_unfold($_[0]))],
135 [rm_zeroes(time_unfold($_[1]))])
139 # removes the leading zeroes of a time array
140 # example: rm_zeroes(time_unfold('00:00:00,000')) = (0,0,0,0)
142 rm_zeroes
144 return map {s/^0+//g; $_} @_;
147 # example: add_zeroes('0','2','3','99') = ('00','02','03','099')
149 add_zeroes
151 my @tmp = @_;
153 # adds leading zeroes to hours, minutes and seconds
154 # two zeroes
155 for (@tmp[0,1,2]) {
156 s/^/00/;
157 s/^.*(..)$/$1/;
160 # adds three leading zeroes
161 for (@tmp[3]) {
162 s/^/000/;
163 s/^.*(...)$/$1/;
166 return @tmp;
169 # unfolds a time value, split it by its fields, deleting leading 0's in each
170 # field
171 # example: time_unfold("00:00:00,300") = ('00', '00', '00', '300')
173 time_unfold
175 my ($_) = @_;
176 return (/^([[:digit:]]+):([[:digit:]]+):([[:digit:]]+),([[:digit:]]+)$/);
179 # joins a time value (splitted in a list)
180 # for adding leading zeroes see add_zeroes()
181 # example: time_fold("0:0:0,300") = "0:0:0,300"
183 time_fold
185 return (join ':', @_[0,1,2]) . "," . $_[3];
188 # low level function
189 # adds two times (expressed in two arrays ...)
190 # time_add([$hour1, $minute1, $second1, $millisecond1],
191 # [$hour2, $minute2, $second2, $millisecond2]) =
192 # ($hour1 + $hour2, $minute1 + $minute2, $second1 + $second2,
193 # $millisecond1 + $millisecond2)
195 _time_add
197 my ($time_one, $time_two) = @_;
199 my @time_one;
200 my @time_two;
201 my @time_new; # the result
203 @time_one = @$time_one;
204 @time_two = @$time_two;
206 # proceed in a little endian order...
207 # milliseconds
208 $time_new[3] = ($time_one[3] + $time_two[3]) % 1000;
209 $time_one[2]+= 1 if ($time_one[3] + $time_two[3]) > 1000;
211 # seconds
212 $time_new[2] = ($time_one[2] + $time_two[2]) % 60;
213 $time_one[1]+= 1 if ($time_one[2] + $time_two[2]) > 60;
215 # minutes
216 $time_new[1] = ($time_one[1] + $time_two[1]) % 60;
217 $time_one[0]+= 1 if ($time_one[1] + $time_two[1]) > 60;
218 # hours
219 $time_new[0] = $time_one[0] + $time_two[0];
220 # we don't round hours...
222 # returns hours, minute, seconds, milliseconds
223 return (@time_new[0,1,2,3]);
227 _time_min
229 my ($time_one, $time_two) = @_;
231 my @time_one;
232 my @time_two;
233 my @time_new; # the result
235 @time_one = @$time_one;
236 @time_two = @$time_two;
238 # proceed in a little endian order...
239 # milliseconds
240 $time_one[2]-= 1 if ($time_one[3] - $time_two[3]) < 0;
241 $time_new[3] = ($time_one[3] - $time_two[3] + 1000) % 1000;
243 # seconds
244 $time_one[1]-= 1 if ($time_one[2] - $time_two[2]) < 0;
245 $time_new[2] = ($time_one[2] - $time_two[2] + 60) % 60;
247 # minutes
248 $time_one[0]-= 1 if ($time_one[1] - $time_two[1]) < 0;
249 $time_new[1] = ($time_one[1] - $time_two[1] + 60) % 60;
251 # hours
252 $time_new[0] = $time_one[0] - $time_two[0];
253 # we don't round hours...
255 # returns hours, minute, seconds, milliseconds
256 return (@time_new[0,1,2,3]);