m3u8 0.7.1 → 0.8.0
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.
- checksums.yaml +4 -4
- data/.gitignore +5 -14
- data/.travis.yml +3 -3
- data/CHANGELOG.md +11 -2
- data/README.md +26 -58
- data/lib/m3u8/byte_range.rb +2 -2
- data/lib/m3u8/discontinuity_item.rb +0 -2
- data/lib/m3u8/error.rb +4 -1
- data/lib/m3u8/map_item.rb +2 -2
- data/lib/m3u8/media_item.rb +39 -14
- data/lib/m3u8/playlist.rb +26 -15
- data/lib/m3u8/playlist_item.rb +13 -7
- data/lib/m3u8/reader.rb +22 -3
- data/lib/m3u8/time_item.rb +1 -1
- data/lib/m3u8/version.rb +1 -1
- data/lib/m3u8/writer.rb +20 -9
- data/spec/fixtures/playlist.m3u8 +1 -0
- data/spec/fixtures/session_data.m3u8 +1 -0
- data/spec/lib/m3u8/discontinuity_item_spec.rb +1 -3
- data/spec/lib/m3u8/media_item_spec.rb +80 -33
- data/spec/lib/m3u8/playlist_item_spec.rb +105 -79
- data/spec/lib/m3u8/playlist_spec.rb +211 -190
- data/spec/lib/m3u8/reader_spec.rb +33 -23
- data/spec/lib/m3u8/writer_spec.rb +221 -147
- metadata +3 -3
@@ -8,233 +8,254 @@ describe M3u8::Playlist do
|
|
8
8
|
it 'initializes with defaults' do
|
9
9
|
expect(playlist.version).to be_nil
|
10
10
|
expect(playlist.cache).to be_nil
|
11
|
-
expect(playlist.target).to
|
12
|
-
expect(playlist.sequence).to
|
11
|
+
expect(playlist.target).to eq(10)
|
12
|
+
expect(playlist.sequence).to eq(0)
|
13
|
+
expect(playlist.discontinuity_sequence).to be_nil
|
13
14
|
expect(playlist.type).to be_nil
|
14
15
|
expect(playlist.iframes_only).to be false
|
15
16
|
expect(playlist.independent_segments).to be false
|
16
17
|
end
|
17
18
|
|
18
|
-
it 'initializes from
|
19
|
+
it 'initializes from options' do
|
19
20
|
options = { version: 7, cache: false, target: 12, sequence: 1,
|
20
|
-
type: 'VOD',
|
21
|
-
|
22
|
-
|
21
|
+
discontinuity_sequence: 2, type: 'VOD',
|
22
|
+
independent_segments: true }
|
23
|
+
playlist = described_class.new(options)
|
24
|
+
expect(playlist.version).to eq(7)
|
23
25
|
expect(playlist.cache).to be false
|
24
|
-
expect(playlist.target).to
|
25
|
-
expect(playlist.sequence).to
|
26
|
+
expect(playlist.target).to eq(12)
|
27
|
+
expect(playlist.sequence).to eq(1)
|
28
|
+
expect(playlist.discontinuity_sequence).to eq(2)
|
26
29
|
expect(playlist.type).to eq('VOD')
|
27
30
|
expect(playlist.iframes_only).to be false
|
28
31
|
expect(playlist.independent_segments).to be true
|
29
32
|
end
|
33
|
+
|
34
|
+
it 'initializes as master playlist' do
|
35
|
+
playlist = described_class.new(master: true)
|
36
|
+
expect(playlist.master?).to be true
|
37
|
+
end
|
30
38
|
end
|
31
39
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
40
|
+
describe '.codecs' do
|
41
|
+
it 'generates codecs string' do
|
42
|
+
options = { profile: 'baseline', level: 3.0, audio_codec: 'aac-lc' }
|
43
|
+
codecs = described_class.codecs(options)
|
44
|
+
expect(codecs).to eq('avc1.66.30,mp4a.40.2')
|
45
|
+
end
|
36
46
|
end
|
37
47
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
output = "#EXTM3U\n" \
|
46
|
-
"#EXT-X-INDEPENDENT-SEGMENTS\n" +
|
47
|
-
%(#EXT-X-STREAM-INF:CODECS="mp4a.40.34") +
|
48
|
-
",BANDWIDTH=6400\nplaylist_url\n"
|
49
|
-
expect(playlist.to_s).to eq output
|
50
|
-
|
51
|
-
options = { program_id: '1', uri: 'playlist_url', bandwidth: 6400,
|
52
|
-
audio_codec: 'mp3' }
|
53
|
-
item = M3u8::PlaylistItem.new options
|
54
|
-
playlist = M3u8::Playlist.new
|
55
|
-
playlist.items << item
|
56
|
-
|
57
|
-
output = "#EXTM3U\n" +
|
58
|
-
%(#EXT-X-STREAM-INF:PROGRAM-ID=1,CODECS="mp4a.40.34") +
|
59
|
-
",BANDWIDTH=6400\nplaylist_url\n"
|
60
|
-
expect(playlist.to_s).to eq output
|
61
|
-
|
62
|
-
options = { program_id: '2', uri: 'playlist_url', bandwidth: 50_000,
|
63
|
-
width: 1920, height: 1080, profile: 'high', level: 4.1,
|
64
|
-
audio_codec: 'aac-lc' }
|
65
|
-
item = M3u8::PlaylistItem.new options
|
66
|
-
playlist = M3u8::Playlist.new
|
67
|
-
playlist.items << item
|
68
|
-
|
69
|
-
output = "#EXTM3U\n" \
|
70
|
-
'#EXT-X-STREAM-INF:PROGRAM-ID=2,RESOLUTION=1920x1080,' +
|
71
|
-
%(CODECS="avc1.640029,mp4a.40.2",BANDWIDTH=50000\n) +
|
72
|
-
"playlist_url\n"
|
73
|
-
|
74
|
-
expect(playlist.to_s).to eq output
|
75
|
-
|
76
|
-
playlist = M3u8::Playlist.new
|
77
|
-
options = { program_id: '1', uri: 'playlist_url', bandwidth: 6400,
|
78
|
-
audio_codec: 'mp3' }
|
79
|
-
item = M3u8::PlaylistItem.new options
|
80
|
-
playlist.items << item
|
81
|
-
options = { program_id: '2', uri: 'playlist_url', bandwidth: 50_000,
|
82
|
-
width: 1920, height: 1080, profile: 'high', level: 4.1,
|
83
|
-
audio_codec: 'aac-lc' }
|
84
|
-
item = M3u8::PlaylistItem.new options
|
85
|
-
playlist.items << item
|
86
|
-
|
87
|
-
output = "#EXTM3U\n" +
|
88
|
-
%(#EXT-X-STREAM-INF:PROGRAM-ID=1,CODECS="mp4a.40.34") +
|
89
|
-
",BANDWIDTH=6400\nplaylist_url\n#EXT-X-STREAM-INF:PROGRAM-ID=2," +
|
90
|
-
%(RESOLUTION=1920x1080,CODECS="avc1.640029,mp4a.40.2") +
|
91
|
-
",BANDWIDTH=50000\nplaylist_url\n"
|
92
|
-
expect(playlist.to_s).to eq output
|
48
|
+
describe '.read' do
|
49
|
+
it 'returns new playlist from content' do
|
50
|
+
file = File.open('spec/fixtures/master.m3u8')
|
51
|
+
playlist = described_class.read(file)
|
52
|
+
expect(playlist.master?).to be true
|
53
|
+
expect(playlist.items.size).to eq(8)
|
54
|
+
end
|
93
55
|
end
|
94
56
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
options = { duration: 11.261233, segment: '1080-7mbps00001.ts' }
|
110
|
-
item = M3u8::SegmentItem.new(options)
|
111
|
-
playlist.items << item
|
112
|
-
|
113
|
-
output = "#EXTM3U\n" \
|
114
|
-
"#EXT-X-MEDIA-SEQUENCE:0\n" \
|
115
|
-
"#EXT-X-TARGETDURATION:10\n" \
|
116
|
-
"#EXTINF:11.344644,\n" \
|
117
|
-
"1080-7mbps00000.ts\n" \
|
118
|
-
"#EXTINF:11.261233,\n" \
|
119
|
-
"1080-7mbps00001.ts\n" \
|
120
|
-
"#EXT-X-ENDLIST\n"
|
121
|
-
expect(playlist.to_s).to eq output
|
122
|
-
|
123
|
-
options = { version: 7, cache: false, target: 12, sequence: 1,
|
124
|
-
type: 'VOD' }
|
125
|
-
playlist = M3u8::Playlist.new options
|
126
|
-
options = { duration: 11.344644, segment: '1080-7mbps00000.ts' }
|
127
|
-
item = M3u8::SegmentItem.new options
|
128
|
-
playlist.items << item
|
129
|
-
|
130
|
-
output = "#EXTM3U\n" \
|
131
|
-
"#EXT-X-PLAYLIST-TYPE:VOD\n" \
|
132
|
-
"#EXT-X-VERSION:7\n" \
|
133
|
-
"#EXT-X-MEDIA-SEQUENCE:1\n" \
|
134
|
-
"#EXT-X-ALLOW-CACHE:NO\n" \
|
135
|
-
"#EXT-X-TARGETDURATION:12\n" \
|
136
|
-
"#EXTINF:11.344644,\n" \
|
137
|
-
"1080-7mbps00000.ts\n" \
|
138
|
-
"#EXT-X-ENDLIST\n"
|
139
|
-
|
140
|
-
expect(playlist.to_s).to eq output
|
57
|
+
describe '#duration' do
|
58
|
+
it 'should return the total duration of a playlist' do
|
59
|
+
item = M3u8::SegmentItem.new(duration: 10.991, segment: 'test_01.ts')
|
60
|
+
playlist.items << item
|
61
|
+
item = M3u8::SegmentItem.new(duration: 9.891, segment: 'test_02.ts')
|
62
|
+
playlist.items << item
|
63
|
+
item = M3u8::SegmentItem.new(duration: 10.556, segment: 'test_03.ts')
|
64
|
+
playlist.items << item
|
65
|
+
item = M3u8::SegmentItem.new(duration: 8.790, segment: 'test_04.ts')
|
66
|
+
playlist.items << item
|
67
|
+
|
68
|
+
expect(playlist.duration.round(3)).to eq(40.228)
|
69
|
+
end
|
141
70
|
end
|
142
71
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
playlist.write test_io
|
72
|
+
describe '#master?' do
|
73
|
+
context 'when playlist is a master playlist' do
|
74
|
+
it 'returns true' do
|
75
|
+
options = { program_id: '1', uri: 'playlist_url', bandwidth: 6400,
|
76
|
+
audio_codec: 'mp3' }
|
77
|
+
item = M3u8::PlaylistItem.new(options)
|
78
|
+
playlist.items << item
|
151
79
|
|
152
|
-
|
153
|
-
|
154
|
-
|
80
|
+
expect(playlist.master?).to be true
|
81
|
+
end
|
82
|
+
end
|
155
83
|
|
156
|
-
|
84
|
+
context 'when playlist is a media playlist' do
|
85
|
+
it 'returns false' do
|
86
|
+
item = M3u8::SegmentItem.new(duration: 10.991, segment: 'test_01.ts')
|
87
|
+
playlist.items << item
|
88
|
+
expect(playlist.master?).to be false
|
89
|
+
end
|
90
|
+
end
|
157
91
|
|
158
|
-
|
159
|
-
|
92
|
+
context 'when playlist is a new playlist' do
|
93
|
+
it 'returns false' do
|
94
|
+
expect(playlist.master?).to be false
|
95
|
+
end
|
96
|
+
end
|
160
97
|
|
161
|
-
|
162
|
-
|
163
|
-
|
98
|
+
context 'when a new playlist is set as master' do
|
99
|
+
it 'returns true' do
|
100
|
+
playlist = described_class.new(master: true)
|
101
|
+
expect(playlist.master?).to be true
|
102
|
+
end
|
103
|
+
end
|
164
104
|
|
165
|
-
|
105
|
+
context 'when a new playlist is set as not master' do
|
106
|
+
it 'returns false' do
|
107
|
+
playlist = described_class.new(master: false)
|
108
|
+
expect(playlist.master?).to be false
|
109
|
+
end
|
110
|
+
end
|
166
111
|
end
|
167
112
|
|
168
|
-
|
169
|
-
playlist
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
113
|
+
describe '#live?' do
|
114
|
+
context 'when playlist is a master playlist' do
|
115
|
+
it 'returns false' do
|
116
|
+
options = { program_id: '1', uri: 'playlist_url', bandwidth: 6400,
|
117
|
+
audio_codec: 'mp3' }
|
118
|
+
item = M3u8::PlaylistItem.new(options)
|
119
|
+
playlist.items << item
|
175
120
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
it 'should raise error on write if item types are mixed' do
|
180
|
-
playlist = M3u8::Playlist.new
|
121
|
+
expect(playlist.live).to be false
|
122
|
+
end
|
123
|
+
end
|
181
124
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
125
|
+
context 'when playlist is a media playlist and set as live' do
|
126
|
+
it 'returns true' do
|
127
|
+
playlist = described_class.new(live: true)
|
128
|
+
item = M3u8::SegmentItem.new(duration: 10.991, segment: 'test_01.ts')
|
129
|
+
playlist.items << item
|
130
|
+
expect(playlist.live?).to be true
|
131
|
+
end
|
132
|
+
end
|
186
133
|
|
187
|
-
|
188
|
-
|
189
|
-
|
134
|
+
context 'when a new playlist is set as not live' do
|
135
|
+
it 'returns false' do
|
136
|
+
playlist = described_class.new(live: false)
|
137
|
+
expect(playlist.live).to be false
|
138
|
+
end
|
139
|
+
end
|
190
140
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
141
|
+
context 'when playlist is a new playlist' do
|
142
|
+
it 'returns false' do
|
143
|
+
expect(playlist.live?).to be false
|
144
|
+
end
|
145
|
+
end
|
195
146
|
end
|
196
147
|
|
197
|
-
|
198
|
-
playlist
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
148
|
+
describe '#to_s' do
|
149
|
+
it 'returns master playlist text' do
|
150
|
+
options = { program_id: '1', uri: 'playlist_url', bandwidth: 6400,
|
151
|
+
audio_codec: 'mp3' }
|
152
|
+
item = M3u8::PlaylistItem.new(options)
|
153
|
+
playlist.items << item
|
154
|
+
|
155
|
+
options = { program_id: '2', uri: 'playlist_url', bandwidth: 50_000,
|
156
|
+
width: 1920, height: 1080, profile: 'high', level: 4.1,
|
157
|
+
audio_codec: 'aac-lc' }
|
158
|
+
item = M3u8::PlaylistItem.new(options)
|
159
|
+
playlist.items << item
|
160
|
+
|
161
|
+
expected = "#EXTM3U\n" +
|
162
|
+
%(#EXT-X-STREAM-INF:PROGRAM-ID=1,CODECS="mp4a.40.34") +
|
163
|
+
",BANDWIDTH=6400\nplaylist_url\n" \
|
164
|
+
'#EXT-X-STREAM-INF:PROGRAM-ID=2,' +
|
165
|
+
%(RESOLUTION=1920x1080,CODECS="avc1.640029,mp4a.40.2") +
|
166
|
+
",BANDWIDTH=50000\nplaylist_url\n"
|
167
|
+
expect(playlist.to_s).to eq(expected)
|
168
|
+
end
|
206
169
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
170
|
+
it 'returns media playlist text' do
|
171
|
+
options = { duration: 11.344644, segment: '1080-7mbps00000.ts' }
|
172
|
+
item = M3u8::SegmentItem.new(options)
|
173
|
+
playlist.items << item
|
174
|
+
|
175
|
+
options = { duration: 11.261233, segment: '1080-7mbps00001.ts' }
|
176
|
+
item = M3u8::SegmentItem.new(options)
|
177
|
+
playlist.items << item
|
178
|
+
|
179
|
+
expected = "#EXTM3U\n" \
|
180
|
+
"#EXT-X-MEDIA-SEQUENCE:0\n" \
|
181
|
+
"#EXT-X-TARGETDURATION:10\n" \
|
182
|
+
"#EXTINF:11.344644,\n" \
|
183
|
+
"1080-7mbps00000.ts\n" \
|
184
|
+
"#EXTINF:11.261233,\n" \
|
185
|
+
"1080-7mbps00001.ts\n" \
|
186
|
+
"#EXT-X-ENDLIST\n"
|
187
|
+
expect(playlist.to_s).to eq(expected)
|
188
|
+
end
|
189
|
+
end
|
212
190
|
|
213
|
-
|
214
|
-
|
215
|
-
|
191
|
+
describe '#valid?' do
|
192
|
+
context 'when playlist is valid' do
|
193
|
+
it 'returns true' do
|
194
|
+
expect(playlist.valid?).to be true
|
195
|
+
|
196
|
+
options = { program_id: 1, width: 1920, height: 1080, codecs: 'avc',
|
197
|
+
bandwidth: 540, uri: 'test.url' }
|
198
|
+
item = M3u8::PlaylistItem.new(options)
|
199
|
+
playlist.items << item
|
200
|
+
expect(playlist.valid?).to be true
|
201
|
+
|
202
|
+
options = { program_id: 1, width: 1920, height: 1080, codecs: 'avc',
|
203
|
+
bandwidth: 540, uri: 'test.url' }
|
204
|
+
item = M3u8::PlaylistItem.new(options)
|
205
|
+
playlist.items << item
|
206
|
+
expect(playlist.valid?).to be true
|
207
|
+
end
|
208
|
+
end
|
216
209
|
|
217
|
-
|
210
|
+
context 'when playlist is invalid' do
|
211
|
+
it 'returns false' do
|
212
|
+
options = { program_id: 1, width: 1920, height: 1080, codecs: 'avc',
|
213
|
+
bandwidth: 540, uri: 'test.url' }
|
214
|
+
item = M3u8::PlaylistItem.new(options)
|
215
|
+
playlist.items << item
|
216
|
+
expect(playlist.valid?).to be true
|
217
|
+
|
218
|
+
options = { duration: 10.991, segment: 'test.ts' }
|
219
|
+
item = M3u8::SegmentItem.new(options)
|
220
|
+
playlist.items << item
|
221
|
+
expect(playlist.valid?).to be false
|
222
|
+
end
|
223
|
+
end
|
218
224
|
end
|
219
225
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
+
describe '#write' do
|
227
|
+
context 'when playlist is valid' do
|
228
|
+
it 'returns playlist text' do
|
229
|
+
options = { program_id: '1', uri: 'playlist_url', bandwidth: 6400,
|
230
|
+
audio_codec: 'mp3' }
|
231
|
+
item = M3u8::PlaylistItem.new(options)
|
232
|
+
playlist.items << item
|
233
|
+
|
234
|
+
io = StringIO.new
|
235
|
+
playlist.write(io)
|
236
|
+
expected = "#EXTM3U\n" +
|
237
|
+
%(#EXT-X-STREAM-INF:PROGRAM-ID=1,CODECS="mp4a.40.34",) +
|
238
|
+
"BANDWIDTH=6400\nplaylist_url\n"
|
239
|
+
expect(io.string).to eq(expected)
|
240
|
+
end
|
241
|
+
end
|
226
242
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
243
|
+
context 'when item types are invalid' do
|
244
|
+
it 'raises error' do
|
245
|
+
options = { program_id: 1, width: 1920, height: 1080, codecs: 'avc',
|
246
|
+
bandwidth: 540, uri: 'test.url' }
|
247
|
+
item = M3u8::PlaylistItem.new(options)
|
248
|
+
playlist.items << item
|
249
|
+
|
250
|
+
options = { duration: 10.991, segment: 'test.ts' }
|
251
|
+
item = M3u8::SegmentItem.new(options)
|
252
|
+
playlist.items << item
|
253
|
+
|
254
|
+
message = 'Playlist is invalid.'
|
255
|
+
io = StringIO.new
|
256
|
+
expect { playlist.write(io) }
|
257
|
+
.to raise_error(M3u8::PlaylistTypeError, message)
|
258
|
+
end
|
259
|
+
end
|
239
260
|
end
|
240
261
|
end
|
@@ -2,13 +2,15 @@
|
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
4
|
describe M3u8::Reader do
|
5
|
+
let(:reader) { described_class.new }
|
6
|
+
|
5
7
|
describe '#read' do
|
6
|
-
it '
|
8
|
+
it 'parses master playlist' do
|
7
9
|
file = File.open('spec/fixtures/master.m3u8')
|
8
10
|
reader = M3u8::Reader.new
|
9
11
|
playlist = reader.read(file)
|
10
12
|
expect(playlist.master?).to be true
|
11
|
-
|
13
|
+
expect(playlist.discontinuity_sequence).to be_nil
|
12
14
|
expect(playlist.independent_segments).to be true
|
13
15
|
|
14
16
|
item = playlist.items[0]
|
@@ -50,7 +52,7 @@ describe M3u8::Reader do
|
|
50
52
|
expect(item.resolution).to be_nil
|
51
53
|
end
|
52
54
|
|
53
|
-
it '
|
55
|
+
it 'parses master playlist with I-Frames' do
|
54
56
|
file = File.open('spec/fixtures/master_iframes.m3u8')
|
55
57
|
reader = M3u8::Reader.new
|
56
58
|
playlist = reader.read(file)
|
@@ -65,13 +67,14 @@ describe M3u8::Reader do
|
|
65
67
|
expect(item.uri).to eq('low/iframe.m3u8')
|
66
68
|
end
|
67
69
|
|
68
|
-
it '
|
70
|
+
it 'parses media playlist' do
|
69
71
|
file = File.open('spec/fixtures/playlist.m3u8')
|
70
72
|
reader = M3u8::Reader.new
|
71
73
|
playlist = reader.read(file)
|
72
74
|
expect(playlist.master?).to be false
|
73
75
|
expect(playlist.version).to eq(4)
|
74
76
|
expect(playlist.sequence).to eq(1)
|
77
|
+
expect(playlist.discontinuity_sequence).to eq(8)
|
75
78
|
expect(playlist.cache).to be false
|
76
79
|
expect(playlist.target).to eq(12)
|
77
80
|
expect(playlist.type).to eq('VOD')
|
@@ -88,7 +91,7 @@ describe M3u8::Reader do
|
|
88
91
|
expect(playlist.items.size).to eq(140)
|
89
92
|
end
|
90
93
|
|
91
|
-
it '
|
94
|
+
it 'parses I-Frame playlist' do
|
92
95
|
file = File.open('spec/fixtures/iframes.m3u8')
|
93
96
|
reader = M3u8::Reader.new
|
94
97
|
playlist = reader.read(file)
|
@@ -108,7 +111,7 @@ describe M3u8::Reader do
|
|
108
111
|
expect(item.byterange.start).to be_nil
|
109
112
|
end
|
110
113
|
|
111
|
-
it '
|
114
|
+
it 'parses segment playlist with comments' do
|
112
115
|
file = File.open('spec/fixtures/playlist_with_comments.m3u8')
|
113
116
|
reader = M3u8::Reader.new
|
114
117
|
playlist = reader.read(file)
|
@@ -130,7 +133,7 @@ describe M3u8::Reader do
|
|
130
133
|
expect(playlist.items.size).to eq(139)
|
131
134
|
end
|
132
135
|
|
133
|
-
it '
|
136
|
+
it 'parses variant playlist with audio options and groups' do
|
134
137
|
file = File.open('spec/fixtures/variant_audio.m3u8')
|
135
138
|
reader = M3u8::Reader.new
|
136
139
|
playlist = reader.read(file)
|
@@ -151,7 +154,7 @@ describe M3u8::Reader do
|
|
151
154
|
expect(item.forced).to be true
|
152
155
|
end
|
153
156
|
|
154
|
-
it '
|
157
|
+
it 'parses variant playlist with camera angles' do
|
155
158
|
file = File.open('spec/fixtures/variant_angles.m3u8')
|
156
159
|
reader = M3u8::Reader.new
|
157
160
|
playlist = reader.read(file)
|
@@ -177,7 +180,7 @@ describe M3u8::Reader do
|
|
177
180
|
expect(item.subtitles).to eq('subs')
|
178
181
|
end
|
179
182
|
|
180
|
-
it '
|
183
|
+
it 'processes multiple reads as separate playlists' do
|
181
184
|
file = File.open('spec/fixtures/master.m3u8')
|
182
185
|
reader = M3u8::Reader.new
|
183
186
|
playlist = reader.read(file)
|
@@ -190,7 +193,7 @@ describe M3u8::Reader do
|
|
190
193
|
expect(playlist.items.size).to eq(8)
|
191
194
|
end
|
192
195
|
|
193
|
-
it '
|
196
|
+
it 'parses playlist with session data' do
|
194
197
|
file = File.open('spec/fixtures/session_data.m3u8')
|
195
198
|
reader = M3u8::Reader.new
|
196
199
|
playlist = reader.read(file)
|
@@ -203,7 +206,7 @@ describe M3u8::Reader do
|
|
203
206
|
expect(item.uri).to eq('lyrics.json')
|
204
207
|
end
|
205
208
|
|
206
|
-
it '
|
209
|
+
it 'parses encrypted playlist' do
|
207
210
|
file = File.open('spec/fixtures/encrypted.m3u8')
|
208
211
|
reader = M3u8::Reader.new
|
209
212
|
playlist = reader.read(file)
|
@@ -216,7 +219,7 @@ describe M3u8::Reader do
|
|
216
219
|
expect(item.uri).to eq('https://priv.example.com/key.php?r=52')
|
217
220
|
end
|
218
221
|
|
219
|
-
it '
|
222
|
+
it 'parses map (media intialization section) playlists' do
|
220
223
|
file = File.open('spec/fixtures/map_playlist.m3u8')
|
221
224
|
reader = M3u8::Reader.new
|
222
225
|
playlist = reader.read(file)
|
@@ -230,7 +233,7 @@ describe M3u8::Reader do
|
|
230
233
|
expect(item.byterange.start).to eq(600)
|
231
234
|
end
|
232
235
|
|
233
|
-
it '
|
236
|
+
it 'reads segment with timestamp' do
|
234
237
|
file = File.open('spec/fixtures/timestamp_playlist.m3u8')
|
235
238
|
reader = M3u8::Reader.new
|
236
239
|
playlist = reader.read(file)
|
@@ -241,18 +244,25 @@ describe M3u8::Reader do
|
|
241
244
|
expect(item_date_time.time).to eq(Time.iso8601('2016-04-11T15:24:31Z'))
|
242
245
|
end
|
243
246
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
247
|
+
it 'parses playlist with daterange' do
|
248
|
+
file = File.open('spec/fixtures/date_range_scte35.m3u8')
|
249
|
+
reader = M3u8::Reader.new
|
250
|
+
playlist = reader.read(file)
|
251
|
+
expect(playlist.items.count).to eq(5)
|
252
|
+
|
253
|
+
item = playlist.items[0]
|
254
|
+
expect(item).to be_a(M3u8::DateRangeItem)
|
250
255
|
|
251
|
-
|
252
|
-
|
256
|
+
item = playlist.items[4]
|
257
|
+
expect(item).to be_a(M3u8::DateRangeItem)
|
258
|
+
end
|
253
259
|
|
254
|
-
|
255
|
-
|
260
|
+
context 'when playlist source is invalid' do
|
261
|
+
it 'raises error with message' do
|
262
|
+
message = 'Playlist must start with a #EXTM3U tag, line read ' \
|
263
|
+
'contained the value: /path/to/file'
|
264
|
+
expect { reader.read('/path/to/file') }
|
265
|
+
.to raise_error(M3u8::InvalidPlaylistError, message)
|
256
266
|
end
|
257
267
|
end
|
258
268
|
end
|