srt 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +2 -1
- data/lib/srt/file.rb +45 -32
- data/lib/srt/version.rb +1 -1
- data/spec/srt_spec.rb +87 -57
- metadata +2 -8
data/README.md
CHANGED
@@ -57,7 +57,8 @@ Example options for the timespan variant: `{ "+3.56s" => part2 }`
|
|
57
57
|
```
|
58
58
|
|
59
59
|
The method `split` splits your subtitles at one (or more) points and returns an array of two (or more) instances of `SRT::File`.
|
60
|
-
|
60
|
+
By default, the timecodes of the split parts are relatively shifted towards their beginnings (to line up with correspondingly split multi-part video);
|
61
|
+
By additionally passing `:timeshift => false` you can prevent that behaviour and retain the original timecodes for each split part.
|
61
62
|
|
62
63
|
Example options for a multi-split: `{ :at => ["00:19:24,500", "01:32:09,120", ...] }`
|
63
64
|
|
data/lib/srt/file.rb
CHANGED
@@ -74,12 +74,12 @@ module SRT
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
def append(
|
78
|
-
if
|
79
|
-
reshift = SRT::File.parse_timecode(
|
77
|
+
def append(options)
|
78
|
+
if options.length == 1 && options.values[0].class == SRT::File
|
79
|
+
reshift = SRT::File.parse_timecode(options.keys[0]) || (lines.last.end_time + SRT::File.parse_timespan(options.keys[0]))
|
80
80
|
renumber = lines.last.sequence
|
81
81
|
|
82
|
-
|
82
|
+
options.values[0].lines.each do |line|
|
83
83
|
lines << line.clone
|
84
84
|
lines.last.sequence += renumber
|
85
85
|
lines.last.start_time += reshift
|
@@ -90,9 +90,10 @@ module SRT
|
|
90
90
|
self
|
91
91
|
end
|
92
92
|
|
93
|
-
def split(
|
94
|
-
|
95
|
-
|
93
|
+
def split(options)
|
94
|
+
options = { :timeshift => true }.merge(options)
|
95
|
+
if options[:at]
|
96
|
+
split_points = [options[:at]].flatten.map{ |timecode| SRT::File.parse_timecode(timecode) }.sort
|
96
97
|
split_offsprings = [SRT::File.new]
|
97
98
|
|
98
99
|
reshift = 0
|
@@ -100,35 +101,47 @@ module SRT
|
|
100
101
|
|
101
102
|
lines.each do |line|
|
102
103
|
if split_points.empty? || line.end_time <= split_points.first
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
104
|
+
cloned_line = line.clone
|
105
|
+
cloned_line.sequence -= renumber
|
106
|
+
if options[:timeshift]
|
107
|
+
cloned_line.start_time -= reshift
|
108
|
+
cloned_line.end_time -= reshift
|
109
|
+
end
|
110
|
+
split_offsprings.last.lines << cloned_line
|
107
111
|
elsif line.start_time < split_points.first
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
+
cloned_line = line.clone
|
113
|
+
cloned_line.sequence -= renumber
|
114
|
+
if options[:timeshift]
|
115
|
+
cloned_line.start_time -= reshift
|
116
|
+
cloned_line.end_time = split_points.first - reshift
|
117
|
+
end
|
118
|
+
split_offsprings.last.lines << cloned_line
|
112
119
|
|
113
120
|
renumber = line.sequence - 1
|
114
121
|
reshift = split_points.first
|
115
122
|
split_points.delete_at(0)
|
116
123
|
|
117
124
|
split_offsprings << SRT::File.new
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
125
|
+
cloned_line = line.clone
|
126
|
+
cloned_line.sequence -= renumber
|
127
|
+
if options[:timeshift]
|
128
|
+
cloned_line.start_time = 0
|
129
|
+
cloned_line.end_time -= reshift
|
130
|
+
end
|
131
|
+
split_offsprings.last.lines << cloned_line
|
122
132
|
else
|
123
133
|
renumber = line.sequence - 1
|
124
134
|
reshift = split_points.first
|
125
135
|
split_points.delete_at(0)
|
126
136
|
|
127
137
|
split_offsprings << SRT::File.new
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
138
|
+
cloned_line = line.clone
|
139
|
+
cloned_line.sequence -= renumber
|
140
|
+
if options[:timeshift]
|
141
|
+
cloned_line.start_time -= reshift
|
142
|
+
cloned_line.end_time -= reshift
|
143
|
+
end
|
144
|
+
split_offsprings.last.lines << cloned_line
|
132
145
|
end
|
133
146
|
end
|
134
147
|
end
|
@@ -136,25 +149,25 @@ module SRT
|
|
136
149
|
split_offsprings
|
137
150
|
end
|
138
151
|
|
139
|
-
def timeshift(
|
140
|
-
if
|
141
|
-
if
|
152
|
+
def timeshift(options)
|
153
|
+
if options.length == 1
|
154
|
+
if options[:all] && (seconds = SRT::File.parse_timespan(options[:all]))
|
142
155
|
lines.each do |line|
|
143
156
|
line.start_time += seconds
|
144
157
|
line.end_time += seconds
|
145
158
|
end
|
146
|
-
elsif (original_framerate = SRT::File.parse_framerate(
|
159
|
+
elsif (original_framerate = SRT::File.parse_framerate(options.keys[0])) && (target_framerate = SRT::File.parse_framerate(options.values[0]))
|
147
160
|
ratio = target_framerate / original_framerate
|
148
161
|
lines.each do |line|
|
149
162
|
line.start_time *= ratio
|
150
163
|
line.end_time *= ratio
|
151
164
|
end
|
152
165
|
end
|
153
|
-
elsif
|
154
|
-
original_timecode_a = (
|
155
|
-
original_timecode_b = (
|
156
|
-
target_timecode_a = SRT::File.parse_timecode(
|
157
|
-
target_timecode_b = SRT::File.parse_timecode(
|
166
|
+
elsif options.length == 2
|
167
|
+
original_timecode_a = (options.keys[0].is_a?(String) ? SRT::File.parse_timecode(options.keys[0]) : lines[options.keys[0] - 1].start_time)
|
168
|
+
original_timecode_b = (options.keys[1].is_a?(String) ? SRT::File.parse_timecode(options.keys[1]) : lines[options.keys[1] - 1].start_time)
|
169
|
+
target_timecode_a = SRT::File.parse_timecode(options.values[0]) || (original_timecode_a + SRT::File.parse_timespan(options.values[0]))
|
170
|
+
target_timecode_b = SRT::File.parse_timecode(options.values[1]) || (original_timecode_b + SRT::File.parse_timespan(options.values[1]))
|
158
171
|
|
159
172
|
time_rescale_factor = (target_timecode_b - target_timecode_a) / (original_timecode_b - original_timecode_a)
|
160
173
|
time_rebase_shift = target_timecode_a - original_timecode_a * time_rescale_factor
|
data/lib/srt/version.rb
CHANGED
data/spec/srt_spec.rb
CHANGED
@@ -7,7 +7,7 @@ describe SRT do
|
|
7
7
|
let(:line) { SRT::Line.new }
|
8
8
|
|
9
9
|
it "should create an empty subtitle" do
|
10
|
-
|
10
|
+
line.should be_empty
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -20,7 +20,7 @@ describe SRT do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
it "should produce timecodes that match the internal float values" do
|
23
|
-
|
23
|
+
line.time_str.should eq("00:03:44,200 --> 00:04:04,578")
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -28,58 +28,58 @@ describe SRT do
|
|
28
28
|
describe SRT::File do
|
29
29
|
describe ".parse_timecode" do
|
30
30
|
it "should convert the SRT timecode format to a float representing seconds" do
|
31
|
-
|
31
|
+
SRT::File.parse_timecode("01:03:44,200").should eq(3824.2)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
35
|
describe ".parse_timespan" do
|
36
36
|
it "should convert a timespan string ([+|-][amount][h|m|s|mil]) to a float representing seconds" do
|
37
|
-
|
37
|
+
SRT::File.parse_timespan("-3.5m").should eq(-210)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
41
|
describe ".parse_framerate" do
|
42
42
|
it "should convert a framerate string ([number]fps) to a float representing seconds" do
|
43
|
-
|
43
|
+
SRT::File.parse_framerate("23.976fps").should eq(23.976)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
shared_examples_for "an SRT file" do
|
48
48
|
context "when parsing a properly formatted BSG SRT file" do
|
49
49
|
it "should return an SRT::File" do
|
50
|
-
|
50
|
+
subject.class.should eq(SRT::File)
|
51
51
|
end
|
52
52
|
|
53
53
|
it "should have 600 lines" do
|
54
|
-
|
54
|
+
subject.lines.size.should eq(600)
|
55
55
|
end
|
56
56
|
|
57
57
|
it "should have no errors" do
|
58
|
-
|
58
|
+
subject.errors.should be_empty
|
59
59
|
end
|
60
60
|
|
61
61
|
it "should have the expected sequence number on the first subtitle" do
|
62
|
-
|
62
|
+
subject.lines.first.sequence.should eq(1)
|
63
63
|
end
|
64
64
|
|
65
65
|
it "should have the expected timecodes on the first subtitle" do
|
66
|
-
|
66
|
+
subject.lines.first.time_str.should eq("00:00:02,110 --> 00:00:04,578")
|
67
67
|
end
|
68
68
|
|
69
69
|
it "should have the expected text on the first subtitle" do
|
70
|
-
|
70
|
+
subject.lines.first.text.should eq(["<i>(male narrator) Previously", "on Battlestar Galactica.</i>"])
|
71
71
|
end
|
72
72
|
|
73
73
|
it "should have the expected sequence number on the last subtitle" do
|
74
|
-
|
74
|
+
subject.lines.last.sequence.should eq(600)
|
75
75
|
end
|
76
76
|
|
77
77
|
it "should have the expected timecodes on the last subtitle" do
|
78
|
-
|
78
|
+
subject.lines.last.time_str.should eq("00:43:26,808 --> 00:43:28,139")
|
79
79
|
end
|
80
80
|
|
81
81
|
it "should have the expected text on the last subtitle" do
|
82
|
-
|
82
|
+
subject.lines.last.text.should eq(["Thank you."])
|
83
83
|
end
|
84
84
|
end
|
85
85
|
end
|
@@ -89,15 +89,15 @@ describe SRT do
|
|
89
89
|
let(:file) { SRT::File.parse(File.open("./spec/wotw-dubious.srt")) }
|
90
90
|
|
91
91
|
it "should parse" do
|
92
|
-
|
92
|
+
file.class.should eq(SRT::File)
|
93
93
|
end
|
94
94
|
|
95
95
|
it "should have 1123 lines" do
|
96
|
-
|
96
|
+
file.lines.size.should eq(1123)
|
97
97
|
end
|
98
98
|
|
99
99
|
it "should have no errors" do
|
100
|
-
|
100
|
+
file.errors.should be_empty
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
@@ -105,23 +105,23 @@ describe SRT do
|
|
105
105
|
let(:file) { SRT::File.parse(File.open("./spec/coordinates-dummy.srt")) }
|
106
106
|
|
107
107
|
it "should return an SRT::File" do
|
108
|
-
|
108
|
+
file.class.should eq(SRT::File)
|
109
109
|
end
|
110
110
|
|
111
111
|
it "should have 3 lines" do
|
112
|
-
|
112
|
+
file.lines.size.should eq(3)
|
113
113
|
end
|
114
114
|
|
115
115
|
it "should have no errors" do
|
116
|
-
|
116
|
+
file.errors.should be_empty
|
117
117
|
end
|
118
118
|
|
119
119
|
it "should have the expected display coordinates on the first subtitle" do
|
120
|
-
|
120
|
+
file.lines.first.display_coordinates.should eq("X1:100 X2:600 Y1:1 Y2:4")
|
121
121
|
end
|
122
122
|
|
123
123
|
it "should have the expected display coordinates on the last subtitle" do
|
124
|
-
|
124
|
+
file.lines.last.display_coordinates.should eq("X1:1 X2:333 Y1:50 Y2:29")
|
125
125
|
end
|
126
126
|
end
|
127
127
|
end
|
@@ -145,19 +145,19 @@ describe SRT do
|
|
145
145
|
before { part1.append({ "00:53:57,241" => part2 }) }
|
146
146
|
|
147
147
|
it "should have grown to 808 subtitles" do
|
148
|
-
|
148
|
+
part1.lines.length.should eq(808)
|
149
149
|
end
|
150
150
|
|
151
151
|
it "should have appended subtitles starting with sequence number 448" do
|
152
|
-
|
152
|
+
part1.lines[447].sequence.should eq(448)
|
153
153
|
end
|
154
154
|
|
155
155
|
it "should have appended subtitles ending with sequence number 808" do
|
156
|
-
|
156
|
+
part1.lines.last.sequence.should eq(808)
|
157
157
|
end
|
158
158
|
|
159
159
|
it "should have appended subtitles relatively from 00:53:57,241" do
|
160
|
-
|
160
|
+
part1.lines[447].time_str.should eq("00:54:02,152 --> 00:54:04,204")
|
161
161
|
end
|
162
162
|
end
|
163
163
|
|
@@ -165,7 +165,7 @@ describe SRT do
|
|
165
165
|
before { part1.append({ "+7.241s" => part2 }) }
|
166
166
|
|
167
167
|
it "should have appended subtitles relatively from +7.241s after the previously last subtitle" do
|
168
|
-
|
168
|
+
part1.lines[447].time_str.should eq("00:54:02,283 --> 00:54:04,335")
|
169
169
|
end
|
170
170
|
end
|
171
171
|
end
|
@@ -179,29 +179,59 @@ describe SRT do
|
|
179
179
|
let(:result) { file.split( :at => "00:19:24,500" ) }
|
180
180
|
|
181
181
|
it "should return an array containing two SRT::File instances" do
|
182
|
-
|
183
|
-
|
184
|
-
|
182
|
+
result.length.should eq(2)
|
183
|
+
result[0].class.should eq(SRT::File)
|
184
|
+
result[1].class.should eq(SRT::File)
|
185
185
|
end
|
186
186
|
|
187
187
|
it "should include a subtitle that overlaps a splitting point in the first file" do
|
188
|
-
|
188
|
+
result[0].lines.last.text.should eq(["I'll see you guys in combat."])
|
189
189
|
end
|
190
190
|
|
191
191
|
it "should make an overlapping subtitle end at the splitting point in the first file" do
|
192
|
-
|
192
|
+
result[0].lines.last.time_str.should eq("00:19:23,901 --> 00:19:24,500")
|
193
193
|
end
|
194
194
|
|
195
195
|
it "should include a subtitle that overlaps a splitting point in the second file as well" do
|
196
|
-
|
196
|
+
result[1].lines.first.text.should eq(["I'll see you guys in combat."])
|
197
197
|
end
|
198
198
|
|
199
199
|
it "should make an overlapping subtitle remain at the beginning in the second file" do
|
200
|
-
|
200
|
+
result[1].lines.first.time_str.should eq("00:00:00,000 --> 00:00:01,528")
|
201
201
|
end
|
202
202
|
|
203
203
|
it "should shift back all timecodes of the second file relative to the new file beginning" do
|
204
|
-
|
204
|
+
result[1].lines[1].time_str.should eq("00:00:01,737 --> 00:00:03,466")
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context "when passing { :at => \"00:19:24,500\", :timeshift => false }" do
|
209
|
+
let(:result) { file.split( :at => "00:19:24,500", :timeshift => false ) }
|
210
|
+
|
211
|
+
it "should return an array containing two SRT::File instances" do
|
212
|
+
result.length.should eq(2)
|
213
|
+
result[0].class.should eq(SRT::File)
|
214
|
+
result[1].class.should eq(SRT::File)
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should include a subtitle that overlaps a splitting point in the first file" do
|
218
|
+
result[0].lines.last.text.should eq(["I'll see you guys in combat."])
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should not make an overlapping subtitle end at the splitting point in the first file" do
|
222
|
+
result[0].lines.last.time_str.should eq("00:19:23,901 --> 00:19:26,028")
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should include a subtitle that overlaps a splitting point in the second file as well" do
|
226
|
+
result[1].lines.first.text.should eq(["I'll see you guys in combat."])
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should not make an overlapping subtitle remain at the beginning in the second file" do
|
230
|
+
result[1].lines.first.time_str.should eq("00:19:23,901 --> 00:19:26,028")
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should not shift back timecodes of the second file relative to the new file beginning" do
|
234
|
+
result[1].lines[1].time_str.should eq("00:19:26,237 --> 00:19:27,966")
|
205
235
|
end
|
206
236
|
end
|
207
237
|
|
@@ -209,31 +239,31 @@ describe SRT do
|
|
209
239
|
let(:result) { file.split( :at => ["00:15:00,000", "00:30:00,000"] ) }
|
210
240
|
|
211
241
|
it "should return an array containing three SRT::File instances" do
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
242
|
+
result.length.should eq(3)
|
243
|
+
result[0].class.should eq(SRT::File)
|
244
|
+
result[1].class.should eq(SRT::File)
|
245
|
+
result[2].class.should eq(SRT::File)
|
216
246
|
end
|
217
247
|
|
218
248
|
it "should let subtitles start at sequence number #1 in all three files" do
|
219
|
-
|
220
|
-
|
221
|
-
|
249
|
+
result[0].lines.first.sequence.should eq(1)
|
250
|
+
result[1].lines.first.sequence.should eq(1)
|
251
|
+
result[2].lines.first.sequence.should eq(1)
|
222
252
|
end
|
223
253
|
|
224
254
|
it "should put 176 subtitles in the first file" do
|
225
|
-
|
226
|
-
|
255
|
+
result[0].lines.length.should eq(176)
|
256
|
+
result[0].lines.last.sequence.should eq(176)
|
227
257
|
end
|
228
258
|
|
229
259
|
it "should put 213 subtitles in the second file" do
|
230
|
-
|
231
|
-
|
260
|
+
result[1].lines.length.should eq(213)
|
261
|
+
result[1].lines.last.sequence.should eq(213)
|
232
262
|
end
|
233
263
|
|
234
264
|
it "should put 212 subtitles in the third file" do
|
235
|
-
|
236
|
-
|
265
|
+
result[2].lines.length.should eq(212)
|
266
|
+
result[2].lines.last.sequence.should eq(212)
|
237
267
|
end
|
238
268
|
end
|
239
269
|
end
|
@@ -247,11 +277,11 @@ describe SRT do
|
|
247
277
|
before { file.timeshift({ :all => "+2.5s" }) }
|
248
278
|
|
249
279
|
it "should have timecodes shifted forward by 2.5s for subtitle #24" do
|
250
|
-
|
280
|
+
file.lines[23].time_str.should eq("00:01:59,291 --> 00:02:00,815")
|
251
281
|
end
|
252
282
|
|
253
283
|
it "should have timecodes shifted forward by 2.5s for subtitle #43" do
|
254
|
-
|
284
|
+
file.lines[42].time_str.should eq("00:03:46,164 --> 00:03:47,631")
|
255
285
|
end
|
256
286
|
end
|
257
287
|
|
@@ -259,11 +289,11 @@ describe SRT do
|
|
259
289
|
before { file.timeshift({ "25fps" => "23.976fps" }) }
|
260
290
|
|
261
291
|
it "should have correctly scaled timecodes for subtitle #24" do
|
262
|
-
|
292
|
+
file.lines[23].time_str.should eq("00:01:52,007 --> 00:01:53,469")
|
263
293
|
end
|
264
294
|
|
265
295
|
it "should have correctly scaled timecodes for subtitle #43" do
|
266
|
-
|
296
|
+
file.lines[42].time_str.should eq("00:03:34,503 --> 00:03:35,910")
|
267
297
|
end
|
268
298
|
end
|
269
299
|
|
@@ -271,11 +301,11 @@ describe SRT do
|
|
271
301
|
before { file.timeshift({ 24 => "00:03:53,582", 42 => "00:04:24,656" }) }
|
272
302
|
|
273
303
|
it "should have shifted timecodes for subtitle #24" do
|
274
|
-
|
304
|
+
file.lines[23].time_str.should eq("00:03:53,582 --> 00:03:54,042")
|
275
305
|
end
|
276
306
|
|
277
307
|
it "should have differently shifted timecodes for subtitle #43" do
|
278
|
-
|
308
|
+
file.lines[41].time_str.should eq("00:04:24,656 --> 00:04:25,298")
|
279
309
|
end
|
280
310
|
end
|
281
311
|
end
|
@@ -287,7 +317,7 @@ describe SRT do
|
|
287
317
|
before { file.timeshift({ :all => "-2.7m" }) }
|
288
318
|
|
289
319
|
it "should have dumped 16 lines with now negative timecodes, leaving 1107" do
|
290
|
-
|
320
|
+
file.lines.size.should eq(1107)
|
291
321
|
end
|
292
322
|
end
|
293
323
|
|
@@ -295,7 +325,7 @@ describe SRT do
|
|
295
325
|
before { file.timeshift({ "00:03:25,430" => "00:00:44,200", "01:49:29,980" => "01:46:35,600" }) }
|
296
326
|
|
297
327
|
it "should have dumped 16 lines with now negative timecodes, leaving 1107" do
|
298
|
-
|
328
|
+
file.lines.size.should eq(1107)
|
299
329
|
end
|
300
330
|
end
|
301
331
|
end
|
@@ -322,7 +352,7 @@ you're a machine.
|
|
322
352
|
00:00:07,014 --> 00:00:08,003
|
323
353
|
The robot.
|
324
354
|
END
|
325
|
-
|
355
|
+
file.to_s.should eq(OUTPUT)
|
326
356
|
end
|
327
357
|
end
|
328
358
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: srt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -80,21 +80,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
80
80
|
- - ! '>='
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
-
segments:
|
84
|
-
- 0
|
85
|
-
hash: 1816904703886705092
|
86
83
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
84
|
none: false
|
88
85
|
requirements:
|
89
86
|
- - ! '>='
|
90
87
|
- !ruby/object:Gem::Version
|
91
88
|
version: '0'
|
92
|
-
segments:
|
93
|
-
- 0
|
94
|
-
hash: 1816904703886705092
|
95
89
|
requirements: []
|
96
90
|
rubyforge_project:
|
97
|
-
rubygems_version: 1.8.
|
91
|
+
rubygems_version: 1.8.23
|
98
92
|
signing_key:
|
99
93
|
specification_version: 3
|
100
94
|
summary: Ruby gem for parsing subtitle files.
|