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.
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