srt 0.0.5 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/spec/file_spec.rb ADDED
@@ -0,0 +1,446 @@
1
+ # encoding: UTF-8
2
+ require 'spec_helper'
3
+ require 'srt'
4
+
5
+ describe SRT::File do
6
+ describe '#parse' do
7
+ context "parsing with debug true" do
8
+ it "should be verbose when failing" do
9
+ expect($stderr).to receive(:puts).once
10
+ expect(SRT::File.parse(File.open("./spec/fixtures/invalid.srt"), debug: true).errors).not_to be_empty
11
+ end
12
+ end
13
+ context "parsing with debug false" do
14
+ it "should raise exception silently" do
15
+ expect($stderr).not_to receive(:puts)
16
+ expect(SRT::File.parse(File.open("./spec/fixtures/invalid.srt")).errors).not_to be_empty
17
+ end
18
+ end
19
+ end
20
+
21
+ shared_examples_for "an SRT file" do
22
+ context "when parsing a properly formatted BSG SRT file" do
23
+ it "should return an SRT::File" do
24
+ expect(subject.class).to eq(SRT::File)
25
+ end
26
+
27
+ it "should have 600 lines" do
28
+ expect(subject.lines.size).to eq(600)
29
+ end
30
+
31
+ it "should have no errors" do
32
+ expect(subject.errors).to be_empty
33
+ end
34
+
35
+ it "should have the expected sequence number on the first subtitle" do
36
+ expect(subject.lines.first.sequence).to eq(1)
37
+ end
38
+
39
+ it "should have the expected timecodes on the first subtitle" do
40
+ expect(subject.lines.first.time_str).to eq("00:00:02,110 --> 00:00:04,578")
41
+ end
42
+
43
+ it "should have the expected text on the first subtitle" do
44
+ expect(subject.lines.first.text).to eq(["<i>(male narrator) Previously", "on Battlestar Galactica.</i>"])
45
+ end
46
+
47
+ it "should have the expected sequence number on the last subtitle" do
48
+ expect(subject.lines.last.sequence).to eq(600)
49
+ end
50
+
51
+ it "should have the expected timecodes on the last subtitle" do
52
+ expect(subject.lines.last.time_str).to eq("00:43:26,808 --> 00:43:28,139")
53
+ end
54
+
55
+ it "should have the expected text on the last subtitle" do
56
+ expect(subject.lines.last.text).to eq(["Thank you."])
57
+ end
58
+ end
59
+ end
60
+
61
+ describe ".parse with uncommon formats" do
62
+ context "when parsing a spanish language WOTW SRT file with unknown encoding" do
63
+ let(:file) { SRT::File.parse(File.open("./spec/fixtures/wotw-dubious.srt")) }
64
+
65
+ it "should parse" do
66
+ expect(file.class).to eq(SRT::File)
67
+ end
68
+
69
+ it "should have 1123 lines" do
70
+ expect(file.lines.size).to eq(1123)
71
+ end
72
+
73
+ it "should have no errors" do
74
+ expect(file.errors).to be_empty
75
+ end
76
+
77
+ it "should convert some dubious UTF-8 encodings" do
78
+ first_line = file.lines.first.text.join(" ")
79
+ expect(first_line).to eq("<i>Nadie habría creído en los primeros años del siglo 21...</i>")
80
+ end
81
+ end
82
+
83
+ context "when parsing a dummy SRT file containing display coordinates" do
84
+ let(:file) { SRT::File.parse(File.open("./spec/fixtures/coordinates-dummy.srt")) }
85
+
86
+ it "should return an SRT::File" do
87
+ expect(file.class).to eq(SRT::File)
88
+ end
89
+
90
+ it "should have 3 lines" do
91
+ expect(file.lines.size).to eq(3)
92
+ end
93
+
94
+ it "should have no errors" do
95
+ expect(file.errors).to be_empty
96
+ end
97
+
98
+ it "should have the expected display coordinates on the first subtitle" do
99
+ expect(file.lines.first.display_coordinates).to eq("X1:100 X2:600 Y1:1 Y2:4")
100
+ end
101
+
102
+ it "should have the expected display coordinates on the last subtitle" do
103
+ expect(file.lines.last.display_coordinates).to eq("X1:1 X2:333 Y1:50 Y2:29")
104
+ end
105
+ end
106
+ end
107
+
108
+ describe SRT::File, "when initialized with a valid BSG SRT string" do
109
+ subject { SRT::File.parse(File.read("./spec/fixtures/bsg-s01e01.srt")) }
110
+ it_should_behave_like "an SRT file"
111
+ end
112
+
113
+ describe SRT::File, "when initialized with a valid BSG SRT File" do
114
+ subject { SRT::File.parse(File.open("./spec/fixtures/bsg-s01e01.srt")) }
115
+ it_should_behave_like "an SRT file"
116
+ end
117
+
118
+ describe "#append" do
119
+ context "when calling it on the first (part1) of two seperate SRT files for Black Swan" do
120
+ let(:part1) { SRT::File.parse(File.open("./spec/fixtures/blackswan-part1.srt")) }
121
+ let(:part2) { SRT::File.parse(File.open("./spec/fixtures/blackswan-part2.srt")) }
122
+
123
+ context "when passing { \"00:53:57,241\" => part2 }" do
124
+ before { part1.append({ "00:53:57,241" => part2 }) }
125
+
126
+ it "should have grown to 808 subtitles" do
127
+ expect(part1.lines.length).to eq(808)
128
+ end
129
+
130
+ it "should have appended subtitles starting with sequence number 448" do
131
+ expect(part1.lines[447].sequence).to eq(448)
132
+ end
133
+
134
+ it "should have appended subtitles ending with sequence number 808" do
135
+ expect(part1.lines.last.sequence).to eq(808)
136
+ end
137
+
138
+ it "should have appended subtitles relatively from 00:53:57,241" do
139
+ expect(part1.lines[447].time_str).to eq("00:54:02,152 --> 00:54:04,204")
140
+ end
141
+ end
142
+
143
+ context "when passing { \"+7.241s\" => part2 }" do
144
+ before { part1.append({ "+7.241s" => part2 }) }
145
+
146
+ it "should have appended subtitles relatively from +7.241s after the previously last subtitle" do
147
+ expect(part1.lines[447].time_str).to eq("00:54:02,283 --> 00:54:04,335")
148
+ end
149
+ end
150
+ end
151
+ end
152
+
153
+ describe "#split" do
154
+ context "when calling it on a properly formatted BSG SRT file" do
155
+ let(:file) { SRT::File.parse(File.open("./spec/fixtures/bsg-s01e01.srt")) }
156
+
157
+ context "when passing { :at => \"00:19:24,500\" }" do
158
+ let(:result) { file.split( :at => "00:19:24,500" ) }
159
+
160
+ it "should return an array containing two SRT::File instances" do
161
+ expect(result.length).to eq(2)
162
+ expect(result[0].class).to eq(SRT::File)
163
+ expect(result[1].class).to eq(SRT::File)
164
+ end
165
+
166
+ it "should include a subtitle that overlaps a splitting point in the first file" do
167
+ expect(result[0].lines.last.text).to eq(["I'll see you guys in combat."])
168
+ end
169
+
170
+ it "should make an overlapping subtitle end at the splitting point in the first file" do
171
+ expect(result[0].lines.last.time_str).to eq("00:19:23,901 --> 00:19:24,500")
172
+ end
173
+
174
+ it "should include a subtitle that overlaps a splitting point in the second file as well" do
175
+ expect(result[1].lines.first.text).to eq(["I'll see you guys in combat."])
176
+ end
177
+
178
+ it "should make an overlapping subtitle remain at the beginning in the second file" do
179
+ expect(result[1].lines.first.time_str).to eq("00:00:00,000 --> 00:00:01,528")
180
+ end
181
+
182
+ it "should shift back all timecodes of the second file relative to the new file beginning" do
183
+ expect(result[1].lines[1].time_str).to eq("00:00:01,737 --> 00:00:03,466")
184
+ end
185
+ end
186
+
187
+ context "when passing { :at => \"00:19:24,500\", :timeshift => false }" do
188
+ let(:result) { file.split( :at => "00:19:24,500", :timeshift => false ) }
189
+
190
+ it "should return an array containing two SRT::File instances" do
191
+ expect(result.length).to eq(2)
192
+ expect(result[0].class).to eq(SRT::File)
193
+ expect(result[1].class).to eq(SRT::File)
194
+ end
195
+
196
+ it "should include a subtitle that overlaps a splitting point in the first file" do
197
+ expect(result[0].lines.last.text).to eq(["I'll see you guys in combat."])
198
+ end
199
+
200
+ it "should not make an overlapping subtitle end at the splitting point in the first file" do
201
+ expect(result[0].lines.last.time_str).to eq("00:19:23,901 --> 00:19:26,028")
202
+ end
203
+
204
+ it "should include a subtitle that overlaps a splitting point in the second file as well" do
205
+ expect(result[1].lines.first.text).to eq(["I'll see you guys in combat."])
206
+ end
207
+
208
+ it "should not make an overlapping subtitle remain at the beginning in the second file" do
209
+ expect(result[1].lines.first.time_str).to eq("00:19:23,901 --> 00:19:26,028")
210
+ end
211
+
212
+ it "should not shift back timecodes of the second file relative to the new file beginning" do
213
+ expect(result[1].lines[1].time_str).to eq("00:19:26,237 --> 00:19:27,966")
214
+ end
215
+ end
216
+
217
+ context "when passing { :at => [\"00:15:00,000\", \"00:30:00,000\"] }" do
218
+ let(:result) { file.split( :at => ["00:15:00,000", "00:30:00,000"] ) }
219
+
220
+ it "should return an array containing three SRT::File instances" do
221
+ expect(result.length).to eq(3)
222
+ expect(result[0].class).to eq(SRT::File)
223
+ expect(result[1].class).to eq(SRT::File)
224
+ expect(result[2].class).to eq(SRT::File)
225
+ end
226
+
227
+ it "should let subtitles start at sequence number #1 in all three files" do
228
+ expect(result[0].lines.first.sequence).to eq(1)
229
+ expect(result[1].lines.first.sequence).to eq(1)
230
+ expect(result[2].lines.first.sequence).to eq(1)
231
+ end
232
+
233
+ it "should put 176 subtitles in the first file" do
234
+ expect(result[0].lines.length).to eq(176)
235
+ expect(result[0].lines.last.sequence).to eq(176)
236
+ end
237
+
238
+ it "should put 213 subtitles in the second file" do
239
+ expect(result[1].lines.length).to eq(213)
240
+ expect(result[1].lines.last.sequence).to eq(213)
241
+ end
242
+
243
+ it "should put 212 subtitles in the third file" do
244
+ expect(result[2].lines.length).to eq(212)
245
+ expect(result[2].lines.last.sequence).to eq(212)
246
+ end
247
+ end
248
+
249
+ context "when passing { :at => \"00:19:24,500\", :every => \"00:00:01,000\" }" do
250
+ let(:result) { file.split( :at => "00:19:24,500", :every => "00:00:01,000" ) }
251
+
252
+ it "should return an array containing two SRT::File instances, ignoring :every" do
253
+ expect(result.length).to eq(2)
254
+ expect(result[0].class).to eq(SRT::File)
255
+ expect(result[1].class).to eq(SRT::File)
256
+ end
257
+ end
258
+
259
+ context "when passing { :every => \"00:05:00,000\" }" do
260
+ let(:result) { file.split( :every => "00:05:00,000" ) }
261
+
262
+ it "should return an array containing nine SRT::File instances" do
263
+ expect(result.length).to eq(9)
264
+ (0...result.count).each do |n|
265
+ expect(result[n].class).to eq(SRT::File)
266
+ end
267
+ end
268
+ end
269
+
270
+ context "when passing { :at => \"00:19:24,500\", :renumber => false }" do
271
+ let(:result) { file.split( :at => "00:19:24,500", :renumber => false ) }
272
+
273
+ it "sequence for the last line of first part should be the sequence for the first line of second part" do
274
+ expect(result[0].lines.last.text).to eq(result[1].lines.first.text)
275
+ expect(result[0].lines.last.sequence).to eq(result[1].lines.first.sequence)
276
+ end
277
+ end
278
+
279
+ context "when passing { :at => \"00:19:24,500\", :renumber => true }" do
280
+ let(:result) { file.split( :at => "00:19:24,500", :renumber => true ) }
281
+
282
+ it "first line of second part's number should be one" do
283
+ expect(result[1].lines.first.sequence).to eq(1)
284
+ end
285
+
286
+ it "sequence for the last line of first part should have different number than the sequence for the first line of second part" do
287
+ expect(result[0].lines.last.text).to eq(result[1].lines.first.text)
288
+ expect(result[0].lines.last.sequence).not_to eq(result[1].lines.first.sequence)
289
+ end
290
+ end
291
+
292
+ context "when passing { :at => \"00:19:24,500\", :timeshift => false }" do
293
+ let(:result) { file.split( :at => "00:19:24,500", :timeshift => false ) }
294
+
295
+ it "time for last line of first part should be the time for first line of second part" do
296
+ expect(result[0].lines.last.text).to eq(result[1].lines.first.text)
297
+ expect(result[0].lines.last.time_str).to eq(result[1].lines.first.time_str)
298
+ end
299
+ end
300
+
301
+ context "when passing { :at => \"00:19:24,500\", :timeshift => true }" do
302
+ let(:result) { file.split( :at => "00:19:24,500", :timeshift => true ) }
303
+
304
+ it "start_time of first line in second part should be 0" do
305
+ expect(result[1].lines.first.start_time).to eq(0)
306
+ end
307
+
308
+ it "time for last line of first part should not be the time for first line of second part" do
309
+ expect(result[0].lines.last.text).to eq(result[1].lines.first.text)
310
+ expect(result[0].lines.last.time_str).not_to eq(result[1].lines.first.time_str)
311
+ end
312
+ end
313
+ end
314
+ end
315
+
316
+ describe "#timeshift" do
317
+ context "when calling it on a properly formatted BSG SRT file" do
318
+ let(:file) { SRT::File.parse(File.open("./spec/fixtures/bsg-s01e01.srt")) }
319
+
320
+ context "when passing { :all => \"+2.5s\" }" do
321
+ before { file.timeshift({ :all => "+2.5s" }) }
322
+
323
+ it "should have timecodes shifted forward by 2.5s for subtitle #24" do
324
+ expect(file.lines[23].time_str).to eq("00:01:59,291 --> 00:02:00,815")
325
+ end
326
+
327
+ it "should have timecodes shifted forward by 2.5s for subtitle #43" do
328
+ expect(file.lines[42].time_str).to eq("00:03:46,164 --> 00:03:47,631")
329
+ end
330
+ end
331
+
332
+ context "when passing { \"25fps\" => \"23.976fps\" }" do
333
+ before { file.timeshift({ "25fps" => "23.976fps" }) }
334
+
335
+ it "should have correctly scaled timecodes for subtitle #24" do
336
+ expect(file.lines[23].time_str).to eq("00:02:01,779 --> 00:02:03,368")
337
+ end
338
+
339
+ it "should have correctly scaled timecodes for subtitle #43" do
340
+ expect(file.lines[42].time_str).to eq("00:03:53,217 --> 00:03:54,746")
341
+ end
342
+ end
343
+
344
+ context "when passing { \"#24\" => \"00:03:53,582\", \"#42\" => \"00:04:24,656\" }" do
345
+ before { file.timeshift({ "#24" => "00:03:53,582", "#42" => "00:04:24,656" }) }
346
+
347
+ it "should have shifted timecodes for subtitle #24" do
348
+ expect(file.lines[23].time_str).to eq("00:03:53,582 --> 00:03:54,042")
349
+ end
350
+
351
+ it "should have differently shifted timecodes for subtitle #43" do
352
+ expect(file.lines[41].time_str).to eq("00:04:24,656 --> 00:04:25,298")
353
+ end
354
+ end
355
+
356
+ context "when passing { 180 => \"+1s\", 264 => \"+1.5s\" }" do
357
+ before { file.timeshift({ 180 => "+1s", 264 => "+1.5s" }) }
358
+
359
+ it "should have shifted by +1s at 180 seconds" do
360
+ expect(file.lines[23].time_str).to eq("00:01:57,415 --> 00:01:58,948")
361
+ end
362
+
363
+ it "should have shifted by +1.5s at 264 seconds" do
364
+ expect(file.lines[41].time_str).to eq("00:03:40,997 --> 00:03:43,136")
365
+ end
366
+ end
367
+ end
368
+
369
+ context "when calling it on a spanish language WOTW SRT file with unknown encoding" do
370
+ let(:file) { SRT::File.parse(File.open("./spec/fixtures/wotw-dubious.srt")) }
371
+
372
+ context "when passing { :all => \"-2.7m\" }" do
373
+ before { file.timeshift({ :all => "-2.7m" }) }
374
+
375
+ it "should have dumped 16 lines with now negative timecodes, leaving 1107" do
376
+ expect(file.lines.size).to eq(1107)
377
+ end
378
+ end
379
+
380
+ context "when passing { \"00:03:25,430\" => \"00:00:44,200\", \"01:49:29,980\" => \"01:46:35,600\" }" do
381
+ before { file.timeshift({ "00:03:25,430" => "00:00:44,200", "01:49:29,980" => "01:46:35,600" }) }
382
+
383
+ it "should have dumped 16 lines with now negative timecodes, leaving 1107" do
384
+ expect(file.lines.size).to eq(1107)
385
+ end
386
+ end
387
+ end
388
+
389
+ describe "#to_s" do
390
+ context "when calling it on a short SRT file" do
391
+ let(:file) { SRT::File.parse(File.open("./spec/fixtures/bsg-s01e01.srt")) }
392
+
393
+ before { file.lines = file.lines[0..2] }
394
+
395
+ it "should produce the exactly correct output" do
396
+ OUTPUT =<<END
397
+ 1
398
+ 00:00:02,110 --> 00:00:04,578
399
+ <i>(male narrator) Previously
400
+ on Battlestar Galactica.</i>
401
+
402
+ 2
403
+ 00:00:05,313 --> 00:00:06,871
404
+ Now you're telling me
405
+ you're a machine.
406
+
407
+ 3
408
+ 00:00:07,014 --> 00:00:08,003
409
+ The robot.
410
+ END
411
+ expect(file.to_s).to eq(OUTPUT)
412
+ end
413
+ end
414
+ end
415
+
416
+ describe "#to_webvtt" do
417
+ context "when calling it on a short SRT file" do
418
+ let(:file) { SRT::File.parse(File.open("./spec/fixtures/bsg-s01e01.srt")) }
419
+
420
+ before { file.lines = file.lines[0..2] }
421
+
422
+ it "should produce the exactly correct output" do
423
+ OUTPUT_WEBVTT =<<END
424
+ WEBVTT
425
+ X-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000
426
+
427
+ 1
428
+ 00:00:02.110 --> 00:00:04.578
429
+ <i>(male narrator) Previously
430
+ on Battlestar Galactica.</i>
431
+
432
+ 2
433
+ 00:00:05.313 --> 00:00:06.871
434
+ Now you're telling me
435
+ you're a machine.
436
+
437
+ 3
438
+ 00:00:07.014 --> 00:00:08.003
439
+ The robot.
440
+ END
441
+ expect(file.to_webvtt).to eq(OUTPUT_WEBVTT)
442
+ end
443
+ end
444
+ end
445
+ end
446
+ end