m3u8 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/m3u8/reader.rb CHANGED
@@ -14,8 +14,9 @@ module M3u8
14
14
  end
15
15
 
16
16
  def read(input)
17
- self.playlist = Playlist.new
18
- input.each_line do |line|
17
+ @playlist = Playlist.new
18
+ input.each_line.with_index do |line, index|
19
+ validate_file_format(line) if index.zero?
19
20
  parse_line(line)
20
21
  end
21
22
  playlist
@@ -42,6 +43,9 @@ module M3u8
42
43
  def media_playlist_tags
43
44
  {
44
45
  '#EXT-X-MEDIA-SEQUENCE' => ->(line) { parse_sequence(line) },
46
+ '#EXT-X-DISCONTINUITY-SEQUENCE' => lambda do |line|
47
+ parse_discontinuity_sequence(line)
48
+ end,
45
49
  '#EXT-X-ALLOW-CACHE' => ->(line) { parse_cache(line) },
46
50
  '#EXT-X-TARGETDURATION' => ->(line) { parse_target(line) },
47
51
  '#EXT-X-I-FRAMES-ONLY' => proc { playlist.iframes_only = true },
@@ -74,7 +78,10 @@ module M3u8
74
78
  end
75
79
 
76
80
  def match_tag(line)
77
- tag = @tags.select { |key| line.start_with? key }
81
+ tag = @tags.select do |key|
82
+ line.start_with?(key) && !line.start_with?("#{key}-")
83
+ end
84
+
78
85
  return unless tag.values.first
79
86
  tag.values.first.call(line)
80
87
  true
@@ -125,6 +132,11 @@ module M3u8
125
132
  playlist.items << item
126
133
  end
127
134
 
135
+ def parse_discontinuity_sequence(line)
136
+ value = line.gsub('#EXT-X-DISCONTINUITY-SEQUENCE:', '').strip
137
+ playlist.discontinuity_sequence = Integer(value)
138
+ end
139
+
128
140
  def parse_key(line)
129
141
  item = M3u8::KeyItem.parse(line)
130
142
  playlist.items << item
@@ -197,5 +209,12 @@ module M3u8
197
209
  playlist.items << item
198
210
  self.open = false
199
211
  end
212
+
213
+ def validate_file_format(line)
214
+ return if line.rstrip == '#EXTM3U'
215
+ message = 'Playlist must start with a #EXTM3U tag, line read ' \
216
+ "contained the value: #{line}"
217
+ raise InvalidPlaylistError, message
218
+ end
200
219
  end
201
220
  end
@@ -14,7 +14,7 @@ module M3u8
14
14
  def self.parse(text)
15
15
  time = text.gsub('#EXT-X-PROGRAM-DATE-TIME:', '')
16
16
  options = { time: Time.parse(time) }
17
- TimeItem.new options
17
+ TimeItem.new(options)
18
18
  end
19
19
 
20
20
  def to_s
data/lib/m3u8/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  # M3u8 provides parsing, generation, and validation of m3u8 playlists
3
3
  module M3u8
4
- VERSION = '0.7.1'
4
+ VERSION = '0.8.0'
5
5
  end
data/lib/m3u8/writer.rb CHANGED
@@ -5,7 +5,7 @@ module M3u8
5
5
  attr_accessor :io
6
6
 
7
7
  def initialize(io)
8
- self.io = io
8
+ @io = io
9
9
  end
10
10
 
11
11
  def write(playlist)
@@ -16,10 +16,23 @@ module M3u8
16
16
  io.puts item.to_s
17
17
  end
18
18
 
19
- return if playlist.master?
19
+ write_footer(playlist)
20
+ end
21
+
22
+ def write_footer(playlist)
23
+ return if playlist.live? || playlist.master?
20
24
  io.puts '#EXT-X-ENDLIST'
21
25
  end
22
26
 
27
+ def write_header(playlist)
28
+ io.puts '#EXTM3U'
29
+ if playlist.master?
30
+ write_master_playlist_header(playlist)
31
+ else
32
+ write_media_playlist_header(playlist)
33
+ end
34
+ end
35
+
23
36
  private
24
37
 
25
38
  def target_duration_format(playlist)
@@ -37,13 +50,10 @@ module M3u8
37
50
  io.puts "#EXT-X-ALLOW-CACHE:#{cache ? 'YES' : 'NO'}"
38
51
  end
39
52
 
40
- def write_header(playlist)
41
- io.puts '#EXTM3U'
42
- if playlist.master?
43
- write_master_playlist_header(playlist)
44
- else
45
- write_media_playlist_header(playlist)
46
- end
53
+ def write_discontinuity_sequence_tag(sequence)
54
+ return if sequence.nil?
55
+
56
+ io.puts "#EXT-X-DISCONTINUITY-SEQUENCE:#{sequence}"
47
57
  end
48
58
 
49
59
  def write_independent_segments_tag(independent_segments)
@@ -63,6 +73,7 @@ module M3u8
63
73
  write_independent_segments_tag(playlist.independent_segments)
64
74
  io.puts '#EXT-X-I-FRAMES-ONLY' if playlist.iframes_only
65
75
  io.puts "#EXT-X-MEDIA-SEQUENCE:#{playlist.sequence}"
76
+ write_discontinuity_sequence_tag(playlist.discontinuity_sequence)
66
77
  write_cache_tag(playlist.cache)
67
78
  io.puts target_duration_format(playlist)
68
79
  end
@@ -2,6 +2,7 @@
2
2
  #EXT-X-PLAYLIST-TYPE:VOD
3
3
  #EXT-X-VERSION:4
4
4
  #EXT-X-MEDIA-SEQUENCE:1
5
+ #EXT-X-DISCONTINUITY-SEQUENCE:8
5
6
  #EXT-X-ALLOW-CACHE:NO
6
7
  #EXT-X-TARGETDURATION:12
7
8
  #EXTINF:11.344644,
@@ -1,3 +1,4 @@
1
+ #EXTM3U
1
2
  #EXT-X-SESSION-DATA:DATA-ID="com.example.lyrics",URI="lyrics.json"
2
3
 
3
4
  #EXT-X-SESSION-DATA:DATA-ID="com.example.title",LANGUAGE="en",VALUE="This is an example"
@@ -4,8 +4,6 @@ require 'spec_helper'
4
4
  describe M3u8::DiscontinuityItem do
5
5
  it 'should provide m3u8 format representation' do
6
6
  item = M3u8::DiscontinuityItem.new
7
- output = item.to_s
8
- expected = "#EXT-X-DISCONTINUITY\n"
9
- expect(output).to eq expected
7
+ expect(item.to_s).to eq("#EXT-X-DISCONTINUITY\n")
10
8
  end
11
9
  end
@@ -2,42 +2,89 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe M3u8::MediaItem do
5
- it 'should provide m3u8 format representation' do
6
- hash = { type: 'AUDIO', group_id: 'audio-lo', language: 'fre',
7
- name: 'Francais', autoselect: true, default: false,
8
- uri: 'frelo/prog_index.m3u8' }
9
- item = M3u8::MediaItem.new(hash)
10
- output = item.to_s
11
- expected = '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-lo",LANGUAGE="fre",' \
12
- 'NAME="Francais",AUTOSELECT=YES,DEFAULT=NO,' \
13
- 'URI="frelo/prog_index.m3u8"'
14
- expect(output).to eq expected
5
+ describe '.new' do
6
+ it 'assigns attributes from options' do
7
+ options = { type: 'AUDIO', group_id: 'audio-lo', language: 'fre',
8
+ assoc_language: 'spoken', name: 'Francais', autoselect: true,
9
+ default: false, forced: true, uri: 'frelo/prog_index.m3u8',
10
+ instream_id: 'SERVICE3', characteristics: 'public.html',
11
+ channels: '6' }
12
+ item = described_class.new(options)
15
13
 
16
- hash = { type: 'AUDIO', group_id: 'audio-lo', language: 'fre',
17
- assoc_language: 'spoken', name: 'Francais', autoselect: true,
18
- default: false, forced: true, uri: 'frelo/prog_index.m3u8' }
19
- item = M3u8::MediaItem.new(hash)
20
- output = item.to_s
21
- expected = '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-lo",LANGUAGE="fre",' \
22
- 'ASSOC-LANGUAGE="spoken",NAME="Francais",AUTOSELECT=YES,' \
23
- 'DEFAULT=NO,URI="frelo/prog_index.m3u8",FORCED=YES'
24
- expect(output).to eq expected
14
+ expect(item.type).to eq('AUDIO')
15
+ expect(item.group_id).to eq('audio-lo')
16
+ expect(item.language).to eq('fre')
17
+ expect(item.assoc_language).to eq('spoken')
18
+ expect(item.name).to eq('Francais')
19
+ expect(item.autoselect).to be true
20
+ expect(item.default).to be false
21
+ expect(item.uri).to eq('frelo/prog_index.m3u8')
22
+ expect(item.forced).to be true
23
+ expect(item.instream_id).to eq('SERVICE3')
24
+ expect(item.characteristics).to eq('public.html')
25
+ expect(item.channels).to eq('6')
26
+ end
25
27
  end
26
28
 
27
- it 'should parse m3u8 text into instance' do
28
- format = '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-lo",LANGUAGE="fre",' \
29
- 'ASSOC-LANGUAGE="spoken",NAME="Francais",AUTOSELECT=YES,' +
30
- %("DEFAULT=NO,URI="frelo/prog_index.m3u8",FORCED=YES\n")
31
- item = M3u8::MediaItem.parse format
29
+ describe '.parse' do
30
+ it 'returns instance from parsed tag' do
31
+ tag = '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-lo",LANGUAGE="fre",' \
32
+ 'ASSOC-LANGUAGE="spoken",NAME="Francais",AUTOSELECT=YES,' \
33
+ 'INSTREAM-ID="SERVICE3",CHARACTERISTICS="public.html",' \
34
+ 'CHANNELS="6",' +
35
+ %("DEFAULT=NO,URI="frelo/prog_index.m3u8",FORCED=YES\n")
36
+ item = described_class.parse(tag)
32
37
 
33
- expect(item.type).to eq 'AUDIO'
34
- expect(item.group_id).to eq 'audio-lo'
35
- expect(item.language).to eq 'fre'
36
- expect(item.assoc_language).to eq 'spoken'
37
- expect(item.name).to eq 'Francais'
38
- expect(item.autoselect).to be true
39
- expect(item.default).to be false
40
- expect(item.uri).to eq 'frelo/prog_index.m3u8'
41
- expect(item.forced).to be true
38
+ expect(item.type).to eq('AUDIO')
39
+ expect(item.group_id).to eq('audio-lo')
40
+ expect(item.language).to eq('fre')
41
+ expect(item.assoc_language).to eq('spoken')
42
+ expect(item.name).to eq('Francais')
43
+ expect(item.autoselect).to be true
44
+ expect(item.default).to be false
45
+ expect(item.uri).to eq('frelo/prog_index.m3u8')
46
+ expect(item.forced).to be true
47
+ expect(item.instream_id).to eq('SERVICE3')
48
+ expect(item.characteristics).to eq('public.html')
49
+ expect(item.channels).to eq('6')
50
+ end
51
+ end
52
+
53
+ describe '#to_s' do
54
+ context 'when no attributes are assigned' do
55
+ it 'returns default tag text' do
56
+ item = described_class.new
57
+ expected = '#EXT-X-MEDIA:TYPE=,GROUP-ID="",NAME=""'
58
+ expect(item.to_s).to eq(expected)
59
+ end
60
+ end
61
+
62
+ context 'when only required attributes are assigned' do
63
+ it 'returns tag text' do
64
+ options = { type: 'AUDIO', group_id: 'audio-lo', name: 'Francais' }
65
+ item = described_class.new(options)
66
+ expected = '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-lo",NAME="Francais"'
67
+ expect(item.to_s).to eq(expected)
68
+ end
69
+ end
70
+
71
+ context 'when all attributes are assigned' do
72
+ it 'returns tag text' do
73
+ options = { type: 'AUDIO', group_id: 'audio-lo', language: 'fre',
74
+ assoc_language: 'spoken', name: 'Francais',
75
+ autoselect: true, default: false, forced: true,
76
+ uri: 'frelo/prog_index.m3u8', instream_id: 'SERVICE3',
77
+ characteristics: 'public.html', channels: '6' }
78
+ item = M3u8::MediaItem.new(options)
79
+ output = item.to_s
80
+ expected = '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-lo",' \
81
+ 'LANGUAGE="fre",ASSOC-LANGUAGE="spoken",' \
82
+ 'NAME="Francais",AUTOSELECT=YES,' \
83
+ 'DEFAULT=NO,URI="frelo/prog_index.m3u8",FORCED=YES,' \
84
+ 'INSTREAM-ID="SERVICE3",CHARACTERISTICS="public.html",' \
85
+ 'CHANNELS="6"'
86
+ expect(output).to eq(expected)
87
+ end
88
+ end
42
89
  end
43
90
  end
@@ -2,27 +2,58 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe M3u8::PlaylistItem do
5
- it 'should initialize with hash' do
6
- hash = { program_id: 1, width: 1920, height: 1080, codecs: 'avc',
7
- bandwidth: 540, uri: 'test.url' }
8
- item = M3u8::PlaylistItem.new(hash)
9
- expect(item.program_id).to eq 1
10
- expect(item.width).to eq 1920
11
- expect(item.height).to eq 1080
12
- expect(item.resolution).to eq '1920x1080'
13
- expect(item.codecs).to eq 'avc'
14
- expect(item.bandwidth).to eq 540
15
- expect(item.uri).to eq 'test.url'
16
- expect(item.iframe).to be false
5
+ describe '.new' do
6
+ it 'assigns attributes from options' do
7
+ options = { program_id: 1, width: 1920, height: 1080, codecs: 'avc',
8
+ bandwidth: 540, audio_codec: 'mp3', level: '2',
9
+ profile: 'baseline', video: 'test_video', audio: 'test_a',
10
+ uri: 'test.url', average_bandwidth: 500, subtitles: 'subs',
11
+ closed_captions: 'cc', iframe: true, frame_rate: 24.6,
12
+ name: 'test_name', hdcp_level: 'TYPE-0' }
13
+ item = described_class.new(options)
14
+
15
+ expect(item.program_id).to eq(1)
16
+ expect(item.width).to eq(1920)
17
+ expect(item.height).to eq(1080)
18
+ expect(item.resolution).to eq('1920x1080')
19
+ expect(item.codecs).to eq('avc')
20
+ expect(item.bandwidth).to eq(540)
21
+ expect(item.audio_codec).to eq('mp3')
22
+ expect(item.level).to eq('2')
23
+ expect(item.profile).to eq('baseline')
24
+ expect(item.video).to eq('test_video')
25
+ expect(item.audio).to eq('test_a')
26
+ expect(item.uri).to eq('test.url')
27
+ expect(item.average_bandwidth).to eq(500)
28
+ expect(item.subtitles).to eq('subs')
29
+ expect(item.closed_captions).to eq('cc')
30
+ expect(item.iframe).to be true
31
+ expect(item.frame_rate).to eq(24.6)
32
+ expect(item.name).to eq('test_name')
33
+ expect(item.hdcp_level).to eq('TYPE-0')
34
+ end
35
+ end
36
+
37
+ describe '.parse' do
38
+ it 'returns new instance from parsed tag' do
39
+ tag = %(#EXT-X-STREAM-INF:CODECS="avc",BANDWIDTH=540,) +
40
+ %(PROGRAM-ID=1,RESOLUTION=1920x1080,FRAME-RATE=23.976,) +
41
+ %(AVERAGE-BANDWIDTH=550,AUDIO="test",VIDEO="test2",) +
42
+ %(SUBTITLES="subs",CLOSED-CAPTIONS="caps",URI="test.url",) +
43
+ %(NAME="1080p",HDCP-LEVEL=TYPE-0)
44
+ expect_any_instance_of(described_class).to receive(:parse).with(tag)
45
+ item = described_class.parse(tag)
46
+ expect(item).to be_a(described_class)
47
+ end
17
48
  end
18
49
 
19
- describe 'parse' do
20
- it 'should parse m3u8 text into instance' do
50
+ describe '#parse' do
51
+ it 'assigns values from parsed tag' do
21
52
  input = %(#EXT-X-STREAM-INF:CODECS="avc",BANDWIDTH=540,) +
22
53
  %(PROGRAM-ID=1,RESOLUTION=1920x1080,FRAME-RATE=23.976,) +
23
54
  %(AVERAGE-BANDWIDTH=550,AUDIO="test",VIDEO="test2",) +
24
55
  %(SUBTITLES="subs",CLOSED-CAPTIONS="caps",URI="test.url",) +
25
- %(NAME="1080p")
56
+ %(NAME="1080p",HDCP-LEVEL=TYPE-0)
26
57
  item = M3u8::PlaylistItem.parse(input)
27
58
  expect(item.program_id).to eq '1'
28
59
  expect(item.codecs).to eq 'avc'
@@ -37,70 +68,72 @@ describe M3u8::PlaylistItem do
37
68
  expect(item.closed_captions).to eq 'caps'
38
69
  expect(item.uri).to eq 'test.url'
39
70
  expect(item.name).to eq '1080p'
71
+ expect(item.iframe).to be false
72
+ expect(item.hdcp_level).to eq('TYPE-0')
40
73
  end
74
+ end
41
75
 
42
- it 'should parse m3u8 into current instance' do
43
- input = %(#EXT-X-STREAM-INF:CODECS="avc",BANDWIDTH=540,) +
44
- %(PROGRAM-ID=1,AUDIO="test",VIDEO="test2",) +
45
- %(SUBTITLES="subs",CLOSED-CAPTIONS="caps",URI="test.url",) +
46
- %(NAME="SD")
47
- item = M3u8::PlaylistItem.new
48
- item.parse(input)
49
- expect(item.program_id).to eq '1'
50
- expect(item.codecs).to eq 'avc'
51
- expect(item.bandwidth).to eq 540
52
- expect(item.average_bandwidth).to be_nil
53
- expect(item.width).to be_nil
54
- expect(item.height).to be_nil
55
- expect(item.audio).to eq 'test'
56
- expect(item.video).to eq 'test2'
57
- expect(item.subtitles).to eq 'subs'
58
- expect(item.closed_captions).to eq 'caps'
59
- expect(item.uri).to eq 'test.url'
60
- expect(item.name).to eq 'SD'
76
+ describe '#to_s' do
77
+ context 'when codecs is missing' do
78
+ it 'raises error' do
79
+ params = { bandwidth: 540, uri: 'test.url' }
80
+ item = M3u8::PlaylistItem.new params
81
+ message = 'Audio or video codec info should be provided.'
82
+ expect { item.to_s }.to raise_error(M3u8::MissingCodecError, message)
83
+ end
61
84
  end
62
- end
63
85
 
64
- it 'should provide m3u8 format representation' do
65
- hash = { program_id: 1, width: 1920, height: 1080, codecs: 'avc',
66
- bandwidth: 540, uri: 'test.url', closed_captions: 'NONE' }
67
- item = M3u8::PlaylistItem.new(hash)
68
- output = item.to_s
69
- expected = '#EXT-X-STREAM-INF:PROGRAM-ID=1,RESOLUTION=1920x1080,' +
70
- %(CODECS="avc",BANDWIDTH=540,CLOSED-CAPTIONS=NONE\ntest.url)
71
- expect(output).to eq expected
72
-
73
- hash = { program_id: 1, codecs: 'avc', bandwidth: 540,
74
- uri: 'test.url' }
75
- item = M3u8::PlaylistItem.new(hash)
76
- output = item.to_s
77
- expected = '#EXT-X-STREAM-INF:PROGRAM-ID=1,' +
78
- %(CODECS="avc",BANDWIDTH=540\ntest.url)
79
- expect(output).to eq expected
80
-
81
- hash = { codecs: 'avc', bandwidth: 540, uri: 'test.url', audio: 'test',
82
- video: 'test2', average_bandwidth: 500, subtitles: 'subs',
83
- frame_rate: 30, closed_captions: 'caps', name: 'SD' }
84
- item = M3u8::PlaylistItem.new(hash)
85
- output = item.to_s
86
- expected = %(#EXT-X-STREAM-INF:CODECS="avc",BANDWIDTH=540,) +
87
- %(AVERAGE-BANDWIDTH=500,FRAME-RATE=30.000,) +
88
- %(AUDIO="test",VIDEO="test2",SUBTITLES="subs",) +
89
- %(CLOSED-CAPTIONS="caps",NAME="SD"\ntest.url)
90
- expect(output).to eq expected
91
- end
86
+ context 'when only required attributes are present' do
87
+ it 'returns tag' do
88
+ options = { codecs: 'avc', bandwidth: 540,
89
+ uri: 'test.url' }
90
+ item = described_class.new(options)
91
+ expected = %(#EXT-X-STREAM-INF:CODECS="avc",BANDWIDTH=540) +
92
+ "\ntest.url"
93
+ expect(item.to_s).to eq(expected)
94
+ end
95
+ end
96
+
97
+ context 'when all attributes are present' do
98
+ it 'returns tag' do
99
+ options = { codecs: 'avc', bandwidth: 540, uri: 'test.url',
100
+ audio: 'test', video: 'test2', average_bandwidth: 500,
101
+ subtitles: 'subs', frame_rate: 30, closed_captions: 'caps',
102
+ name: 'SD', hdcp_level: 'TYPE-0', program_id: '1' }
103
+ item = described_class.new(options)
104
+ expected = %(#EXT-X-STREAM-INF:PROGRAM-ID=1,CODECS="avc",BANDWIDTH=540,) +
105
+ %(AVERAGE-BANDWIDTH=500,FRAME-RATE=30.000,) +
106
+ 'HDCP-LEVEL=TYPE-0,' +
107
+ %(AUDIO="test",VIDEO="test2",SUBTITLES="subs",) +
108
+ %(CLOSED-CAPTIONS="caps",NAME="SD"\ntest.url)
109
+ expect(item.to_s).to eq(expected)
110
+ end
111
+ end
112
+
113
+ context 'when closed captions is NONE' do
114
+ it 'returns tag' do
115
+ options = { program_id: 1, width: 1920, height: 1080, codecs: 'avc',
116
+ bandwidth: 540, uri: 'test.url', closed_captions: 'NONE' }
117
+ item = described_class.new(options)
118
+ expected = '#EXT-X-STREAM-INF:PROGRAM-ID=1,RESOLUTION=1920x1080,' +
119
+ %(CODECS="avc",BANDWIDTH=540,CLOSED-CAPTIONS=NONE\ntest.url)
120
+ expect(item.to_s).to eq(expected)
121
+ end
122
+ end
92
123
 
93
- it 'should provided m3u8 format with I-Frame option' do
94
- hash = { codecs: 'avc', bandwidth: 540, uri: 'test.url', iframe: true,
95
- video: 'test2', average_bandwidth: 550 }
96
- item = M3u8::PlaylistItem.new(hash)
97
- output = item.to_s
98
- expected = %(#EXT-X-I-FRAME-STREAM-INF:CODECS="avc",BANDWIDTH=540,) +
99
- %(AVERAGE-BANDWIDTH=550,VIDEO="test2",URI="test.url")
100
- expect(output).to eq expected
124
+ context 'when iframe is enabled' do
125
+ it 'returns EXT-X-I-FRAME-STREAM-INF tag' do
126
+ options = { codecs: 'avc', bandwidth: 540, uri: 'test.url',
127
+ iframe: true, video: 'test2', average_bandwidth: 550 }
128
+ item = described_class.new(options)
129
+ expected = %(#EXT-X-I-FRAME-STREAM-INF:CODECS="avc",BANDWIDTH=540,) +
130
+ %(AVERAGE-BANDWIDTH=550,VIDEO="test2",URI="test.url")
131
+ expect(item.to_s).to eq(expected)
132
+ end
133
+ end
101
134
  end
102
135
 
103
- it 'should generate codecs string' do
136
+ it 'generates codecs string' do
104
137
  item = M3u8::PlaylistItem.new
105
138
  expect(item.codecs).to be_nil
106
139
 
@@ -180,11 +213,4 @@ describe M3u8::PlaylistItem do
180
213
  item = M3u8::PlaylistItem.new options
181
214
  expect(item.codecs).to eq 'avc1.640029'
182
215
  end
183
-
184
- it 'should raise error if codecs are missing' do
185
- params = { program_id: 1, bandwidth: 540, uri: 'test.url' }
186
- item = M3u8::PlaylistItem.new params
187
- message = 'Audio or video codec info should be provided.'
188
- expect { item.to_s }.to raise_error(M3u8::MissingCodecError, message)
189
- end
190
216
  end