m3u8 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/Gemfile +1 -0
  4. data/Guardfile +1 -0
  5. data/Rakefile +1 -0
  6. data/lib/m3u8.rb +6 -1
  7. data/lib/m3u8/byte_range.rb +1 -0
  8. data/lib/m3u8/date_range_item.rb +113 -0
  9. data/lib/m3u8/discontinuity_item.rb +1 -3
  10. data/lib/m3u8/encryptable.rb +1 -0
  11. data/lib/m3u8/error.rb +1 -0
  12. data/lib/m3u8/key_item.rb +1 -0
  13. data/lib/m3u8/map_item.rb +1 -0
  14. data/lib/m3u8/media_item.rb +1 -0
  15. data/lib/m3u8/playback_start.rb +1 -0
  16. data/lib/m3u8/playlist.rb +1 -0
  17. data/lib/m3u8/playlist_item.rb +12 -18
  18. data/lib/m3u8/reader.rb +17 -9
  19. data/lib/m3u8/segment_item.rb +1 -0
  20. data/lib/m3u8/session_data_item.rb +1 -0
  21. data/lib/m3u8/session_key_item.rb +1 -0
  22. data/lib/m3u8/time_item.rb +1 -0
  23. data/lib/m3u8/version.rb +2 -1
  24. data/lib/m3u8/writer.rb +1 -0
  25. data/spec/fixtures/date_range_scte35.m3u8 +16 -0
  26. data/spec/lib/m3u8/byte_range_spec.rb +1 -0
  27. data/spec/lib/m3u8/date_range_item_spec.rb +124 -0
  28. data/spec/lib/m3u8/discontinuity_item_spec.rb +1 -0
  29. data/spec/lib/m3u8/key_item_spec.rb +1 -0
  30. data/spec/lib/m3u8/map_item_spec.rb +2 -5
  31. data/spec/lib/m3u8/media_item_spec.rb +1 -0
  32. data/spec/lib/m3u8/playback_start_spec.rb +1 -0
  33. data/spec/lib/m3u8/playlist_item_spec.rb +1 -0
  34. data/spec/lib/m3u8/playlist_spec.rb +1 -0
  35. data/spec/lib/m3u8/reader_spec.rb +254 -236
  36. data/spec/lib/m3u8/segment_item_spec.rb +4 -14
  37. data/spec/lib/m3u8/session_data_item_spec.rb +1 -0
  38. data/spec/lib/m3u8/session_key_item_spec.rb +1 -0
  39. data/spec/lib/m3u8/time_item_spec.rb +1 -0
  40. data/spec/lib/m3u8/writer_spec.rb +174 -171
  41. data/spec/lib/m3u8_spec.rb +1 -0
  42. data/spec/spec_helper.rb +1 -0
  43. metadata +8 -3
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  describe M3u8::DiscontinuityItem do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  describe M3u8::KeyItem do
@@ -1,13 +1,10 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  describe M3u8::MapItem do
4
5
  it 'should provide m3u8 format representation' do
5
6
  hash = { uri: 'frelo/prog_index.m3u8',
6
- byterange: {
7
- length: 4500,
8
- start: 600
9
- }
10
- }
7
+ byterange: { length: 4500, start: 600 } }
11
8
  item = M3u8::MapItem.new(hash)
12
9
  output = item.to_s
13
10
  expected = '#EXT-X-MAP:URI="frelo/prog_index.m3u8",' \
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  describe M3u8::MediaItem do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  describe M3u8::PlaybackStart do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  describe M3u8::PlaylistItem do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  describe M3u8::Playlist do
@@ -1,241 +1,259 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  describe M3u8::Reader do
4
- it 'should parse master playlist' do
5
- file = File.open 'spec/fixtures/master.m3u8'
6
- reader = M3u8::Reader.new
7
- playlist = reader.read file
8
- expect(playlist.master?).to be true
9
-
10
- expect(playlist.independent_segments).to be true
11
-
12
- item = playlist.items[0]
13
- expect(item).to be_a(M3u8::SessionKeyItem)
14
- expect(item.method).to eq('AES-128')
15
- expect(item.uri).to eq('https://priv.example.com/key.php?r=52')
16
-
17
- item = playlist.items[1]
18
- expect(item).to be_a(M3u8::PlaybackStart)
19
- expect(item.time_offset).to eq(20.2)
20
-
21
- item = playlist.items[2]
22
- expect(item).to be_a(M3u8::PlaylistItem)
23
- expect(item.uri).to eq('hls/1080-7mbps/1080-7mbps.m3u8')
24
- expect(item.program_id).to eq('1')
25
- expect(item.width).to eq(1920)
26
- expect(item.height).to eq(1080)
27
- expect(item.resolution).to eq('1920x1080')
28
- expect(item.codecs).to eq('avc1.640028,mp4a.40.2')
29
- expect(item.bandwidth).to eq(5_042_000)
30
- expect(item.iframe).to be false
31
- expect(item.average_bandwidth).to be_nil
32
-
33
- item = playlist.items[7]
34
- expect(item).to be_a(M3u8::PlaylistItem)
35
- expect(item.uri).to eq('hls/64k/64k.m3u8')
36
- expect(item.program_id).to eq('1')
37
- expect(item.width).to be_nil
38
- expect(item.height).to be_nil
39
- expect(item.resolution).to be_nil
40
- expect(item.codecs).to eq('mp4a.40.2')
41
- expect(item.bandwidth).to eq(6400)
42
- expect(item.iframe).to be false
43
- expect(item.average_bandwidth).to be_nil
44
-
45
- expect(playlist.items.size).to eq(8)
46
-
47
- item = playlist.items.last
48
- expect(item.resolution).to be_nil
49
- end
50
-
51
- it 'should parse master playlist with I-Frames' do
52
- file = File.open 'spec/fixtures/master_iframes.m3u8'
53
- reader = M3u8::Reader.new
54
- playlist = reader.read file
55
- expect(playlist.master?).to be true
56
-
57
- expect(playlist.items.size).to eq(7)
58
-
59
- item = playlist.items[1]
60
- expect(item).to be_a(M3u8::PlaylistItem)
61
- expect(item.bandwidth).to eq(86_000)
62
- expect(item.iframe).to be true
63
- expect(item.uri).to eq 'low/iframe.m3u8'
64
- end
65
-
66
- it 'should parse segment playlist' do
67
- file = File.open 'spec/fixtures/playlist.m3u8'
68
- reader = M3u8::Reader.new
69
- playlist = reader.read file
70
- expect(playlist.master?).to be false
71
- expect(playlist.version).to eq 4
72
- expect(playlist.sequence).to eq 1
73
- expect(playlist.cache).to be false
74
- expect(playlist.target).to eq 12
75
- expect(playlist.type).to eq 'VOD'
76
-
77
- item = playlist.items[0]
78
- expect(item).to be_a(M3u8::SegmentItem)
79
- expect(item.duration).to eq 11.344644
80
- expect(item.comment).to be_nil
81
-
82
- item = playlist.items[4]
83
- expect(item).to be_a(M3u8::TimeItem)
84
- expect(item.time).to eq(Time.iso8601('2010-02-19T14:54:23Z'))
85
-
86
- expect(playlist.items.size).to eq 140
87
- end
88
-
89
- it 'should parse I-Frame playlist' do
90
- file = File.open 'spec/fixtures/iframes.m3u8'
91
- reader = M3u8::Reader.new
92
- playlist = reader.read file
93
-
94
- expect(playlist.iframes_only).to be true
95
- expect(playlist.items.size).to eq 3
96
-
97
- item = playlist.items[0]
98
- expect(item).to be_a(M3u8::SegmentItem)
99
- expect(item.duration).to eq 4.12
100
- expect(item.byterange.length).to eq 9400
101
- expect(item.byterange.start).to eq 376
102
- expect(item.segment).to eq 'segment1.ts'
103
-
104
- item = playlist.items[1]
105
- expect(item.byterange.length).to eq 7144
106
- expect(item.byterange.start).to be_nil
107
- end
108
-
109
- it 'should parse segment playlist with comments' do
110
- file = File.open 'spec/fixtures/playlist_with_comments.m3u8'
111
- reader = M3u8::Reader.new
112
- playlist = reader.read file
113
- expect(playlist.master?).to be false
114
- expect(playlist.version).to be 4
115
- expect(playlist.sequence).to be 1
116
- expect(playlist.cache).to be false
117
- expect(playlist.target).to be 12
118
- expect(playlist.type).to eq 'VOD'
119
-
120
- item = playlist.items[0]
121
- expect(item).to be_a(M3u8::SegmentItem)
122
- expect(item.duration).to eq 11.344644
123
- expect(item.comment).to eq 'anything'
124
-
125
- item = playlist.items[1]
126
- expect(item).to be_a(M3u8::DiscontinuityItem)
127
-
128
- expect(playlist.items.size).to eq 139
129
- end
130
-
131
- it 'should parse variant playlist with audio options and groups' do
132
- file = File.open 'spec/fixtures/variant_audio.m3u8'
133
- reader = M3u8::Reader.new
134
- playlist = reader.read file
135
-
136
- expect(playlist.master?).to be true
137
- expect(playlist.items.size).to eq 10
138
-
139
- item = playlist.items[0]
140
- expect(item).to be_a M3u8::MediaItem
141
- expect(item.type).to eq 'AUDIO'
142
- expect(item.group_id).to eq 'audio-lo'
143
- expect(item.language).to eq 'eng'
144
- expect(item.assoc_language).to eq 'spoken'
145
- expect(item.name).to eq 'English'
146
- expect(item.autoselect).to be true
147
- expect(item.default).to be true
148
- expect(item.uri).to eq 'englo/prog_index.m3u8'
149
- expect(item.forced).to be true
150
- end
151
-
152
- it 'should parse variant playlist with camera angles' do
153
- file = File.open 'spec/fixtures/variant_angles.m3u8'
154
- reader = M3u8::Reader.new
155
- playlist = reader.read file
156
-
157
- expect(playlist.master?).to be true
158
- expect(playlist.items.size).to eq 11
159
-
160
- item = playlist.items[1]
161
- expect(item).to be_a M3u8::MediaItem
162
- expect(item.type).to eq 'VIDEO'
163
- expect(item.group_id).to eq '200kbs'
164
- expect(item.language).to be_nil
165
- expect(item.name).to eq 'Angle2'
166
- expect(item.autoselect).to be true
167
- expect(item.default).to be false
168
- expect(item.uri).to eq 'Angle2/200kbs/prog_index.m3u8'
169
-
170
- item = playlist.items[9]
171
- expect(item.average_bandwidth).to eq 300_001
172
- expect(item.audio).to eq 'aac'
173
- expect(item.video).to eq '200kbs'
174
- expect(item.closed_captions).to eq 'captions'
175
- expect(item.subtitles).to eq 'subs'
176
- end
177
-
178
- it 'should process multiple reads as separate playlists' do
179
- file = File.open 'spec/fixtures/master.m3u8'
180
- reader = M3u8::Reader.new
181
- playlist = reader.read file
182
-
183
- expect(playlist.items.size).to eq(8)
184
-
185
- file = File.open 'spec/fixtures/master.m3u8'
186
- playlist = reader.read file
187
-
188
- expect(playlist.items.size).to eq(8)
189
- end
190
-
191
- it 'should parse playlist with session data' do
192
- file = File.open 'spec/fixtures/session_data.m3u8'
193
- reader = M3u8::Reader.new
194
- playlist = reader.read file
195
-
196
- expect(playlist.items.size).to eq 3
197
-
198
- item = playlist.items[0]
199
- expect(item).to be_a M3u8::SessionDataItem
200
- expect(item.data_id).to eq 'com.example.lyrics'
201
- expect(item.uri).to eq 'lyrics.json'
202
- end
203
-
204
- it 'should parse encrypted playlist' do
205
- file = File.open 'spec/fixtures/encrypted.m3u8'
206
- reader = M3u8::Reader.new
207
- playlist = reader.read file
208
-
209
- expect(playlist.items.size).to eq 6
210
-
211
- item = playlist.items[0]
212
- expect(item).to be_a M3u8::KeyItem
213
- expect(item.method).to eq 'AES-128'
214
- expect(item.uri).to eq 'https://priv.example.com/key.php?r=52'
215
- end
216
-
217
- it 'should parse map (media intialization section) playlists' do
218
- file = File.open 'spec/fixtures/map_playlist.m3u8'
219
- reader = M3u8::Reader.new
220
- playlist = reader.read file
221
-
222
- expect(playlist.items.size).to eq 1
223
-
224
- item = playlist.items[0]
225
- expect(item).to be_a M3u8::MapItem
226
- expect(item.uri).to eq 'frelo/prog_index.m3u8'
227
- expect(item.byterange.length).to eq 4500
228
- expect(item.byterange.start).to eq 600
229
- end
230
-
231
- it 'should read segment with timestamp' do
232
- file = File.open 'spec/fixtures/timestamp_playlist.m3u8'
233
- reader = M3u8::Reader.new
234
- playlist = reader.read file
235
- expect(playlist.items.count).to eq 6
236
-
237
- item_date_time = playlist.items.first.program_date_time
238
- expect(item_date_time).to be_a M3u8::TimeItem
239
- expect(item_date_time.time).to eq Time.iso8601('2016-04-11T15:24:31Z')
5
+ describe '#read' do
6
+ it 'should parse master playlist' do
7
+ file = File.open('spec/fixtures/master.m3u8')
8
+ reader = M3u8::Reader.new
9
+ playlist = reader.read(file)
10
+ expect(playlist.master?).to be true
11
+
12
+ expect(playlist.independent_segments).to be true
13
+
14
+ item = playlist.items[0]
15
+ expect(item).to be_a(M3u8::SessionKeyItem)
16
+ expect(item.method).to eq('AES-128')
17
+ expect(item.uri).to eq('https://priv.example.com/key.php?r=52')
18
+
19
+ item = playlist.items[1]
20
+ expect(item).to be_a(M3u8::PlaybackStart)
21
+ expect(item.time_offset).to eq(20.2)
22
+
23
+ item = playlist.items[2]
24
+ expect(item).to be_a(M3u8::PlaylistItem)
25
+ expect(item.uri).to eq('hls/1080-7mbps/1080-7mbps.m3u8')
26
+ expect(item.program_id).to eq('1')
27
+ expect(item.width).to eq(1920)
28
+ expect(item.height).to eq(1080)
29
+ expect(item.resolution).to eq('1920x1080')
30
+ expect(item.codecs).to eq('avc1.640028,mp4a.40.2')
31
+ expect(item.bandwidth).to eq(5_042_000)
32
+ expect(item.iframe).to be false
33
+ expect(item.average_bandwidth).to be_nil
34
+
35
+ item = playlist.items[7]
36
+ expect(item).to be_a(M3u8::PlaylistItem)
37
+ expect(item.uri).to eq('hls/64k/64k.m3u8')
38
+ expect(item.program_id).to eq('1')
39
+ expect(item.width).to be_nil
40
+ expect(item.height).to be_nil
41
+ expect(item.resolution).to be_nil
42
+ expect(item.codecs).to eq('mp4a.40.2')
43
+ expect(item.bandwidth).to eq(6400)
44
+ expect(item.iframe).to be false
45
+ expect(item.average_bandwidth).to be_nil
46
+
47
+ expect(playlist.items.size).to eq(8)
48
+
49
+ item = playlist.items.last
50
+ expect(item.resolution).to be_nil
51
+ end
52
+
53
+ it 'should parse master playlist with I-Frames' do
54
+ file = File.open('spec/fixtures/master_iframes.m3u8')
55
+ reader = M3u8::Reader.new
56
+ playlist = reader.read(file)
57
+ expect(playlist.master?).to be true
58
+
59
+ expect(playlist.items.size).to eq(7)
60
+
61
+ item = playlist.items[1]
62
+ expect(item).to be_a(M3u8::PlaylistItem)
63
+ expect(item.bandwidth).to eq(86_000)
64
+ expect(item.iframe).to be true
65
+ expect(item.uri).to eq('low/iframe.m3u8')
66
+ end
67
+
68
+ it 'should parse segment playlist' do
69
+ file = File.open('spec/fixtures/playlist.m3u8')
70
+ reader = M3u8::Reader.new
71
+ playlist = reader.read(file)
72
+ expect(playlist.master?).to be false
73
+ expect(playlist.version).to eq(4)
74
+ expect(playlist.sequence).to eq(1)
75
+ expect(playlist.cache).to be false
76
+ expect(playlist.target).to eq(12)
77
+ expect(playlist.type).to eq('VOD')
78
+
79
+ item = playlist.items[0]
80
+ expect(item).to be_a(M3u8::SegmentItem)
81
+ expect(item.duration).to eq(11.344644)
82
+ expect(item.comment).to be_nil
83
+
84
+ item = playlist.items[4]
85
+ expect(item).to be_a(M3u8::TimeItem)
86
+ expect(item.time).to eq(Time.iso8601('2010-02-19T14:54:23Z'))
87
+
88
+ expect(playlist.items.size).to eq(140)
89
+ end
90
+
91
+ it 'should parse I-Frame playlist' do
92
+ file = File.open('spec/fixtures/iframes.m3u8')
93
+ reader = M3u8::Reader.new
94
+ playlist = reader.read(file)
95
+
96
+ expect(playlist.iframes_only).to be true
97
+ expect(playlist.items.size).to eq(3)
98
+
99
+ item = playlist.items[0]
100
+ expect(item).to be_a(M3u8::SegmentItem)
101
+ expect(item.duration).to eq(4.12)
102
+ expect(item.byterange.length).to eq(9400)
103
+ expect(item.byterange.start).to eq(376)
104
+ expect(item.segment).to eq('segment1.ts')
105
+
106
+ item = playlist.items[1]
107
+ expect(item.byterange.length).to eq(7144)
108
+ expect(item.byterange.start).to be_nil
109
+ end
110
+
111
+ it 'should parse segment playlist with comments' do
112
+ file = File.open('spec/fixtures/playlist_with_comments.m3u8')
113
+ reader = M3u8::Reader.new
114
+ playlist = reader.read(file)
115
+ expect(playlist.master?).to be false
116
+ expect(playlist.version).to eq(4)
117
+ expect(playlist.sequence).to eq(1)
118
+ expect(playlist.cache).to be false
119
+ expect(playlist.target).to eq(12)
120
+ expect(playlist.type).to eq('VOD')
121
+
122
+ item = playlist.items[0]
123
+ expect(item).to be_a(M3u8::SegmentItem)
124
+ expect(item.duration).to eq(11.344644)
125
+ expect(item.comment).to eq('anything')
126
+
127
+ item = playlist.items[1]
128
+ expect(item).to be_a(M3u8::DiscontinuityItem)
129
+
130
+ expect(playlist.items.size).to eq(139)
131
+ end
132
+
133
+ it 'should parse variant playlist with audio options and groups' do
134
+ file = File.open('spec/fixtures/variant_audio.m3u8')
135
+ reader = M3u8::Reader.new
136
+ playlist = reader.read(file)
137
+
138
+ expect(playlist.master?).to be true
139
+ expect(playlist.items.size).to eq(10)
140
+
141
+ item = playlist.items[0]
142
+ expect(item).to be_a(M3u8::MediaItem)
143
+ expect(item.type).to eq('AUDIO')
144
+ expect(item.group_id).to eq('audio-lo')
145
+ expect(item.language).to eq('eng')
146
+ expect(item.assoc_language).to eq('spoken')
147
+ expect(item.name).to eq('English')
148
+ expect(item.autoselect).to be true
149
+ expect(item.default).to be true
150
+ expect(item.uri).to eq('englo/prog_index.m3u8')
151
+ expect(item.forced).to be true
152
+ end
153
+
154
+ it 'should parse variant playlist with camera angles' do
155
+ file = File.open('spec/fixtures/variant_angles.m3u8')
156
+ reader = M3u8::Reader.new
157
+ playlist = reader.read(file)
158
+
159
+ expect(playlist.master?).to be true
160
+ expect(playlist.items.size).to eq(11)
161
+
162
+ item = playlist.items[1]
163
+ expect(item).to be_a(M3u8::MediaItem)
164
+ expect(item.type).to eq('VIDEO')
165
+ expect(item.group_id).to eq('200kbs')
166
+ expect(item.language).to be_nil
167
+ expect(item.name).to eq('Angle2')
168
+ expect(item.autoselect).to be true
169
+ expect(item.default).to be false
170
+ expect(item.uri).to eq('Angle2/200kbs/prog_index.m3u8')
171
+
172
+ item = playlist.items[9]
173
+ expect(item.average_bandwidth).to eq(300_001)
174
+ expect(item.audio).to eq('aac')
175
+ expect(item.video).to eq('200kbs')
176
+ expect(item.closed_captions).to eq('captions')
177
+ expect(item.subtitles).to eq('subs')
178
+ end
179
+
180
+ it 'should process multiple reads as separate playlists' do
181
+ file = File.open('spec/fixtures/master.m3u8')
182
+ reader = M3u8::Reader.new
183
+ playlist = reader.read(file)
184
+
185
+ expect(playlist.items.size).to eq(8)
186
+
187
+ file = File.open('spec/fixtures/master.m3u8')
188
+ playlist = reader.read(file)
189
+
190
+ expect(playlist.items.size).to eq(8)
191
+ end
192
+
193
+ it 'should parse playlist with session data' do
194
+ file = File.open('spec/fixtures/session_data.m3u8')
195
+ reader = M3u8::Reader.new
196
+ playlist = reader.read(file)
197
+
198
+ expect(playlist.items.size).to eq(3)
199
+
200
+ item = playlist.items[0]
201
+ expect(item).to be_a(M3u8::SessionDataItem)
202
+ expect(item.data_id).to eq('com.example.lyrics')
203
+ expect(item.uri).to eq('lyrics.json')
204
+ end
205
+
206
+ it 'should parse encrypted playlist' do
207
+ file = File.open('spec/fixtures/encrypted.m3u8')
208
+ reader = M3u8::Reader.new
209
+ playlist = reader.read(file)
210
+
211
+ expect(playlist.items.size).to eq(6)
212
+
213
+ item = playlist.items[0]
214
+ expect(item).to be_a(M3u8::KeyItem)
215
+ expect(item.method).to eq('AES-128')
216
+ expect(item.uri).to eq('https://priv.example.com/key.php?r=52')
217
+ end
218
+
219
+ it 'should parse map (media intialization section) playlists' do
220
+ file = File.open('spec/fixtures/map_playlist.m3u8')
221
+ reader = M3u8::Reader.new
222
+ playlist = reader.read(file)
223
+
224
+ expect(playlist.items.size).to eq(1)
225
+
226
+ item = playlist.items[0]
227
+ expect(item).to be_a(M3u8::MapItem)
228
+ expect(item.uri).to eq('frelo/prog_index.m3u8')
229
+ expect(item.byterange.length).to eq(4500)
230
+ expect(item.byterange.start).to eq(600)
231
+ end
232
+
233
+ it 'should read segment with timestamp' do
234
+ file = File.open('spec/fixtures/timestamp_playlist.m3u8')
235
+ reader = M3u8::Reader.new
236
+ playlist = reader.read(file)
237
+ expect(playlist.items.count).to eq(6)
238
+
239
+ item_date_time = playlist.items.first.program_date_time
240
+ expect(item_date_time).to be_a(M3u8::TimeItem)
241
+ expect(item_date_time.time).to eq(Time.iso8601('2016-04-11T15:24:31Z'))
242
+ end
243
+
244
+ context 'playlist with daterange' do
245
+ it 'parses playlist' do
246
+ file = File.open('spec/fixtures/date_range_scte35.m3u8')
247
+ reader = M3u8::Reader.new
248
+ playlist = reader.read(file)
249
+ expect(playlist.items.count).to eq(5)
250
+
251
+ item = playlist.items[0]
252
+ expect(item).to be_a(M3u8::DateRangeItem)
253
+
254
+ item = playlist.items[4]
255
+ expect(item).to be_a(M3u8::DateRangeItem)
256
+ end
257
+ end
240
258
  end
241
259
  end