m3u8 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -0
- data/README.md +5 -2
- data/lib/m3u8.rb +1 -0
- data/lib/m3u8/playlist.rb +5 -58
- data/lib/m3u8/version.rb +1 -1
- data/lib/m3u8/writer.rb +41 -0
- data/spec/playlist_spec.rb +42 -32
- data/spec/spec_helper.rb +1 -0
- data/spec/writer_spec.rb +136 -0
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 941d9ae1544d5853fa64790089c269ce9b7cdc9c
|
4
|
+
data.tar.gz: fc32d9311ab491b6049b3a9c27ec6757886237d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5bb40055129102f6b578533fcd0eb2904e9f43b7bfd3d5a9e6e2f14440095d401fbd4cb0fc04c10920ab60195703a5a7d7c1a94cfaafe939d093fbabe5e3521
|
7
|
+
data.tar.gz: bb47741dc6419161bb23e46c8c56478e978d2a6c71757b4665e80394ce74c676e078a8925de7601a8fc77e67561b2968fff5a87792d6e390c52d7f89dba4504f
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
### 0.3.0 (11/26/2014) - DEPRECIATED add_playlist and add_segment on Playlist, manipulate the items array directly instead. Extracted writing of playlists to it's own Writer class (only use directly if you want more control over the process). Added read convience method to Playlist so Reader doesn't have to be used directly unless more control is disired. Simplified validation and other aspects during this refactoring.
|
2
|
+
|
1
3
|
### 0.2.1 (11/26/2014) - Moved codec generation / validation to PlaylistItem, allowing for the flexibility to either specify :audio, :level, :profile when creating new instances (codecs value will be automatically generated) or just set the codecs attribute directly.
|
2
4
|
|
3
5
|
### 0.2.0 (11/25/2014) - Added ability to parse m3u8 playlists with new Reader class. Introduced two new classes to represent the items that make up a Playlist: PlaylistItem and SegmentItem.
|
data/README.md
CHANGED
@@ -66,6 +66,8 @@ Or install it yourself as:
|
|
66
66
|
|
67
67
|
#You can also access the playlist as a string
|
68
68
|
playlist.to_s
|
69
|
+
|
70
|
+
#There is a M3u8::Writer class if you want more control over the write process
|
69
71
|
|
70
72
|
#values for :audio (Codec name)
|
71
73
|
#aac-lc, he-aac, mp3
|
@@ -81,8 +83,7 @@ Or install it yourself as:
|
|
81
83
|
## Parsing Usage (new in v.2.0)
|
82
84
|
|
83
85
|
file = File.open 'spec/fixtures/master.m3u8'
|
84
|
-
|
85
|
-
playlist = reader.read file
|
86
|
+
playlist = M3u8::Playlist.read file
|
86
87
|
playlist.master?
|
87
88
|
# => true
|
88
89
|
|
@@ -101,6 +102,8 @@ Or install it yourself as:
|
|
101
102
|
item = M3u8::PlaylistItem.new options
|
102
103
|
#add it to the top of the playlist
|
103
104
|
playlist.items.insert 0, item
|
105
|
+
|
106
|
+
#There is a M3u8::Reader class if you want more control over parsing
|
104
107
|
|
105
108
|
## Features
|
106
109
|
* Distinction between segment and master playlists is handled automatically (no need to use a different class).
|
data/lib/m3u8.rb
CHANGED
data/lib/m3u8/playlist.rb
CHANGED
@@ -1,11 +1,6 @@
|
|
1
1
|
module M3u8
|
2
2
|
class Playlist
|
3
3
|
attr_accessor :items, :version, :cache, :target, :sequence
|
4
|
-
NON_MASTER_ERROR_MESSAGE = 'Playlist is not a master playlist, playlist' \
|
5
|
-
' can not be added.'
|
6
|
-
MASTER_ERROR_MESSAGE = 'Playlist is a master playlist, segment can not ' \
|
7
|
-
'be added.'
|
8
|
-
MIXED_TYPE_ERROR_MESSAGE = 'Playlist contains mixed types of items'
|
9
4
|
|
10
5
|
def initialize(options = {})
|
11
6
|
assign_options options
|
@@ -17,37 +12,14 @@ module M3u8
|
|
17
12
|
item.codecs
|
18
13
|
end
|
19
14
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
params = { program_id: program_id, playlist: playlist, bitrate: bitrate,
|
24
|
-
width: options[:width], height: options[:height],
|
25
|
-
audio: options[:audio], profile: options[:profile],
|
26
|
-
level: options[:level] }
|
27
|
-
item = PlaylistItem.new params
|
28
|
-
items.push item
|
29
|
-
end
|
30
|
-
|
31
|
-
def add_segment(duration, segment)
|
32
|
-
validate_playlist_type false
|
33
|
-
|
34
|
-
params = { duration: duration, segment: segment }
|
35
|
-
item = SegmentItem.new params
|
36
|
-
items.push item
|
15
|
+
def self.read(input)
|
16
|
+
reader = Reader.new
|
17
|
+
reader.read input
|
37
18
|
end
|
38
19
|
|
39
20
|
def write(output)
|
40
|
-
|
41
|
-
|
42
|
-
output.puts '#EXTM3U'
|
43
|
-
write_header(output) unless master?
|
44
|
-
|
45
|
-
items.each do |item|
|
46
|
-
output.puts item.to_s
|
47
|
-
end
|
48
|
-
|
49
|
-
return if master?
|
50
|
-
output.puts '#EXT-X-ENDLIST'
|
21
|
+
writer = Writer.new output
|
22
|
+
writer.write self
|
51
23
|
end
|
52
24
|
|
53
25
|
def master?
|
@@ -82,20 +54,6 @@ module M3u8
|
|
82
54
|
self.target = options[:target]
|
83
55
|
end
|
84
56
|
|
85
|
-
def validate
|
86
|
-
return if valid?
|
87
|
-
fail PlaylistTypeError, MIXED_TYPE_ERROR_MESSAGE
|
88
|
-
end
|
89
|
-
|
90
|
-
def validate_playlist_type(master)
|
91
|
-
return if items.size == 0
|
92
|
-
if master && !master?
|
93
|
-
fail PlaylistTypeError, NON_MASTER_ERROR_MESSAGE
|
94
|
-
elsif !master && master?
|
95
|
-
fail PlaylistTypeError, MASTER_ERROR_MESSAGE
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
57
|
def playlist_size
|
100
58
|
items.select { |item| item.is_a?(PlaylistItem) }.size
|
101
59
|
end
|
@@ -103,16 +61,5 @@ module M3u8
|
|
103
61
|
def segment_size
|
104
62
|
items.select { |item| item.is_a?(SegmentItem) }.size
|
105
63
|
end
|
106
|
-
|
107
|
-
def write_header(output)
|
108
|
-
output.puts "#EXT-X-VERSION:#{version}"
|
109
|
-
output.puts "#EXT-X-MEDIA-SEQUENCE:#{sequence}"
|
110
|
-
output.puts "#EXT-X-ALLOW-CACHE:#{cache_string}"
|
111
|
-
output.puts "#EXT-X-TARGETDURATION:#{target}"
|
112
|
-
end
|
113
|
-
|
114
|
-
def cache_string
|
115
|
-
cache ? 'YES' : 'NO'
|
116
|
-
end
|
117
64
|
end
|
118
65
|
end
|
data/lib/m3u8/version.rb
CHANGED
data/lib/m3u8/writer.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
module M3u8
|
2
|
+
class Writer
|
3
|
+
attr_accessor :io
|
4
|
+
|
5
|
+
def initialize(io)
|
6
|
+
self.io = io
|
7
|
+
end
|
8
|
+
|
9
|
+
def write(playlist)
|
10
|
+
validate playlist
|
11
|
+
|
12
|
+
io.puts '#EXTM3U'
|
13
|
+
write_header(playlist) unless playlist.master?
|
14
|
+
|
15
|
+
playlist.items.each do |item|
|
16
|
+
io.puts item.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
return if playlist.master?
|
20
|
+
io.puts '#EXT-X-ENDLIST'
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def validate(playlist)
|
26
|
+
return if playlist.valid?
|
27
|
+
fail PlaylistTypeError, 'Playlist is invalid.'
|
28
|
+
end
|
29
|
+
|
30
|
+
def write_header(playlist)
|
31
|
+
io.puts "#EXT-X-VERSION:#{playlist.version}"
|
32
|
+
io.puts "#EXT-X-MEDIA-SEQUENCE:#{playlist.sequence}"
|
33
|
+
io.puts "#EXT-X-ALLOW-CACHE:#{cache(playlist)}"
|
34
|
+
io.puts "#EXT-X-TARGETDURATION:#{playlist.target}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def cache(playlist)
|
38
|
+
playlist.cache ? 'YES' : 'NO'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/spec/playlist_spec.rb
CHANGED
@@ -8,19 +8,23 @@ describe M3u8::Playlist do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it 'should render master playlist' do
|
11
|
+
options = { program_id: '1', playlist: 'playlist_url', bitrate: 6400,
|
12
|
+
audio: 'mp3' }
|
13
|
+
item = M3u8::PlaylistItem.new options
|
11
14
|
playlist = M3u8::Playlist.new
|
12
|
-
playlist.
|
15
|
+
playlist.items.push item
|
13
16
|
|
14
17
|
output = "#EXTM3U\n" +
|
15
18
|
%(#EXT-X-STREAM-INF:PROGRAM-ID=1,CODECS="mp4a.40.34") +
|
16
19
|
",BANDWIDTH=6400\nplaylist_url\n"
|
17
|
-
|
18
20
|
expect(playlist.to_s).to eq output
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
+
options = { program_id: '2', playlist: 'playlist_url', bitrate: 50_000,
|
23
|
+
width: 1920, height: 1080, profile: 'high', level: 4.1,
|
22
24
|
audio: 'aac-lc' }
|
23
|
-
|
25
|
+
item = M3u8::PlaylistItem.new options
|
26
|
+
playlist = M3u8::Playlist.new
|
27
|
+
playlist.items.push item
|
24
28
|
|
25
29
|
output = "#EXTM3U\n" \
|
26
30
|
'#EXT-X-STREAM-INF:PROGRAM-ID=2,RESOLUTION=1920x1080,' +
|
@@ -30,23 +34,29 @@ describe M3u8::Playlist do
|
|
30
34
|
expect(playlist.to_s).to eq output
|
31
35
|
|
32
36
|
playlist = M3u8::Playlist.new
|
33
|
-
|
34
|
-
|
37
|
+
options = { program_id: '1', playlist: 'playlist_url', bitrate: 6400,
|
38
|
+
audio: 'mp3' }
|
39
|
+
item = M3u8::PlaylistItem.new options
|
40
|
+
playlist.items.push item
|
41
|
+
options = { program_id: '2', playlist: 'playlist_url', bitrate: 50_000,
|
42
|
+
width: 1920, height: 1080, profile: 'high', level: 4.1,
|
35
43
|
audio: 'aac-lc' }
|
36
|
-
|
44
|
+
item = M3u8::PlaylistItem.new options
|
45
|
+
playlist.items.push item
|
37
46
|
|
38
47
|
output = "#EXTM3U\n" +
|
39
48
|
%(#EXT-X-STREAM-INF:PROGRAM-ID=1,CODECS="mp4a.40.34") +
|
40
49
|
",BANDWIDTH=6400\nplaylist_url\n#EXT-X-STREAM-INF:PROGRAM-ID=2," +
|
41
50
|
%(RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2") +
|
42
51
|
",BANDWIDTH=50000\nplaylist_url\n"
|
43
|
-
|
44
52
|
expect(playlist.to_s).to eq output
|
45
53
|
end
|
46
54
|
|
47
55
|
it 'should render playlist' do
|
56
|
+
options = { duration: 11.344644, segment: '1080-7mbps00000.ts' }
|
57
|
+
item = M3u8::SegmentItem.new options
|
48
58
|
playlist = M3u8::Playlist.new
|
49
|
-
playlist.
|
59
|
+
playlist.items.push item
|
50
60
|
|
51
61
|
output = "#EXTM3U\n" \
|
52
62
|
"#EXT-X-VERSION:3\n" \
|
@@ -56,10 +66,11 @@ describe M3u8::Playlist do
|
|
56
66
|
"#EXTINF:11.344644,\n" \
|
57
67
|
"1080-7mbps00000.ts\n" \
|
58
68
|
"#EXT-X-ENDLIST\n"
|
59
|
-
|
60
69
|
expect(playlist.to_s).to eq output
|
61
70
|
|
62
|
-
|
71
|
+
options = { duration: 11.261233, segment: '1080-7mbps00001.ts' }
|
72
|
+
item = M3u8::SegmentItem.new options
|
73
|
+
playlist.items.push item
|
63
74
|
|
64
75
|
output = "#EXTM3U\n" \
|
65
76
|
"#EXT-X-VERSION:3\n" \
|
@@ -71,12 +82,13 @@ describe M3u8::Playlist do
|
|
71
82
|
"#EXTINF:11.261233,\n" \
|
72
83
|
"1080-7mbps00001.ts\n" \
|
73
84
|
"#EXT-X-ENDLIST\n"
|
74
|
-
|
75
85
|
expect(playlist.to_s).to eq output
|
76
86
|
|
77
87
|
options = { version: 1, cache: false, target: 12, sequence: 1 }
|
78
88
|
playlist = M3u8::Playlist.new options
|
79
|
-
|
89
|
+
options = { duration: 11.344644, segment: '1080-7mbps00000.ts' }
|
90
|
+
item = M3u8::SegmentItem.new options
|
91
|
+
playlist.items.push item
|
80
92
|
|
81
93
|
output = "#EXTM3U\n" \
|
82
94
|
"#EXT-X-VERSION:1\n" \
|
@@ -93,7 +105,10 @@ describe M3u8::Playlist do
|
|
93
105
|
it 'should write playlist to io' do
|
94
106
|
test_io = StringIO.new
|
95
107
|
playlist = M3u8::Playlist.new
|
96
|
-
|
108
|
+
options = { program_id: '1', playlist: 'playlist_url', bitrate: 6400,
|
109
|
+
audio: 'mp3' }
|
110
|
+
item = M3u8::PlaylistItem.new options
|
111
|
+
playlist.items.push item
|
97
112
|
playlist.write test_io
|
98
113
|
|
99
114
|
output = "#EXTM3U\n" +
|
@@ -115,26 +130,14 @@ describe M3u8::Playlist do
|
|
115
130
|
it 'should report if it is a master playlist' do
|
116
131
|
playlist = M3u8::Playlist.new
|
117
132
|
expect(playlist.master?).to be false
|
133
|
+
options = { program_id: '1', playlist: 'playlist_url', bitrate: 6400,
|
134
|
+
audio: 'mp3' }
|
135
|
+
item = M3u8::PlaylistItem.new options
|
136
|
+
playlist.items.push item
|
118
137
|
|
119
|
-
playlist.add_playlist '1', 'playlist_url', 6400, audio: 'mp3'
|
120
138
|
expect(playlist.master?).to be true
|
121
139
|
end
|
122
140
|
|
123
|
-
it 'should raise error if type of playlist is changed' do
|
124
|
-
playlist = M3u8::Playlist.new
|
125
|
-
playlist.add_playlist '1', 'playlist_url', 6400, audio: 'mp3'
|
126
|
-
|
127
|
-
message = 'Playlist is a master playlist, segment can not be added.'
|
128
|
-
expect { playlist.add_segment 11.344644, '1080-7mbps00000.ts' }
|
129
|
-
.to raise_error(M3u8::PlaylistTypeError, message)
|
130
|
-
|
131
|
-
playlist = M3u8::Playlist.new
|
132
|
-
playlist.add_segment 11.344644, '1080-7mbps00000.ts'
|
133
|
-
message = 'Playlist is not a master playlist, playlist can not be added.'
|
134
|
-
expect { playlist.add_playlist '1', 'playlist_url', 6400 }
|
135
|
-
.to raise_error(M3u8::PlaylistTypeError, message)
|
136
|
-
end
|
137
|
-
|
138
141
|
it 'should raise error on write if item types are mixed' do
|
139
142
|
playlist = M3u8::Playlist.new
|
140
143
|
|
@@ -147,7 +150,7 @@ describe M3u8::Playlist do
|
|
147
150
|
item = M3u8::SegmentItem.new(hash)
|
148
151
|
playlist.items.push item
|
149
152
|
|
150
|
-
message = 'Playlist
|
153
|
+
message = 'Playlist is invalid.'
|
151
154
|
io = StringIO.new
|
152
155
|
expect { playlist.write io }
|
153
156
|
.to raise_error(M3u8::PlaylistTypeError, message)
|
@@ -184,4 +187,11 @@ describe M3u8::Playlist do
|
|
184
187
|
expect(playlist.target).to be 12
|
185
188
|
expect(playlist.sequence).to be 1
|
186
189
|
end
|
190
|
+
|
191
|
+
it 'should allow reading of playlists' do
|
192
|
+
file = File.open 'spec/fixtures/master.m3u8'
|
193
|
+
playlist = M3u8::Playlist.read file
|
194
|
+
expect(playlist.master?).to be true
|
195
|
+
expect(playlist.items.size).to eq 6
|
196
|
+
end
|
187
197
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/writer_spec.rb
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe M3u8::Writer do
|
4
|
+
it 'should render master playlist' do
|
5
|
+
options = { program_id: '1', playlist: 'playlist_url', bitrate: 6400,
|
6
|
+
audio: 'mp3' }
|
7
|
+
item = M3u8::PlaylistItem.new options
|
8
|
+
playlist = M3u8::Playlist.new
|
9
|
+
playlist.items.push item
|
10
|
+
|
11
|
+
output = "#EXTM3U\n" +
|
12
|
+
%(#EXT-X-STREAM-INF:PROGRAM-ID=1,CODECS="mp4a.40.34") +
|
13
|
+
",BANDWIDTH=6400\nplaylist_url\n"
|
14
|
+
|
15
|
+
io = StringIO.open
|
16
|
+
writer = M3u8::Writer.new io
|
17
|
+
writer.write playlist
|
18
|
+
expect(io.string).to eq output
|
19
|
+
|
20
|
+
options = { program_id: '2', playlist: 'playlist_url', bitrate: 50_000,
|
21
|
+
width: 1920, height: 1080, profile: 'high', level: 4.1,
|
22
|
+
audio: 'aac-lc' }
|
23
|
+
item = M3u8::PlaylistItem.new options
|
24
|
+
playlist = M3u8::Playlist.new
|
25
|
+
playlist.items.push item
|
26
|
+
|
27
|
+
output = "#EXTM3U\n" \
|
28
|
+
'#EXT-X-STREAM-INF:PROGRAM-ID=2,RESOLUTION=1920x1080,' +
|
29
|
+
%(CODECS="avc1.640028,mp4a.40.2",BANDWIDTH=50000\n) +
|
30
|
+
"playlist_url\n"
|
31
|
+
|
32
|
+
io = StringIO.open
|
33
|
+
writer = M3u8::Writer.new io
|
34
|
+
writer.write playlist
|
35
|
+
expect(io.string).to eq output
|
36
|
+
|
37
|
+
playlist = M3u8::Playlist.new
|
38
|
+
options = { program_id: '1', playlist: 'playlist_url', bitrate: 6400,
|
39
|
+
audio: 'mp3' }
|
40
|
+
item = M3u8::PlaylistItem.new options
|
41
|
+
playlist.items.push item
|
42
|
+
options = { program_id: '2', playlist: 'playlist_url', bitrate: 50_000,
|
43
|
+
width: 1920, height: 1080, profile: 'high', level: 4.1,
|
44
|
+
audio: 'aac-lc' }
|
45
|
+
item = M3u8::PlaylistItem.new options
|
46
|
+
playlist.items.push item
|
47
|
+
|
48
|
+
output = "#EXTM3U\n" +
|
49
|
+
%(#EXT-X-STREAM-INF:PROGRAM-ID=1,CODECS="mp4a.40.34") +
|
50
|
+
",BANDWIDTH=6400\nplaylist_url\n#EXT-X-STREAM-INF:PROGRAM-ID=2," +
|
51
|
+
%(RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2") +
|
52
|
+
",BANDWIDTH=50000\nplaylist_url\n"
|
53
|
+
|
54
|
+
io = StringIO.open
|
55
|
+
writer = M3u8::Writer.new io
|
56
|
+
writer.write playlist
|
57
|
+
expect(io.string).to eq output
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should render playlist' do
|
61
|
+
options = { duration: 11.344644, segment: '1080-7mbps00000.ts' }
|
62
|
+
item = M3u8::SegmentItem.new options
|
63
|
+
playlist = M3u8::Playlist.new
|
64
|
+
playlist.items.push item
|
65
|
+
|
66
|
+
output = "#EXTM3U\n" \
|
67
|
+
"#EXT-X-VERSION:3\n" \
|
68
|
+
"#EXT-X-MEDIA-SEQUENCE:0\n" \
|
69
|
+
"#EXT-X-ALLOW-CACHE:YES\n" \
|
70
|
+
"#EXT-X-TARGETDURATION:10\n" \
|
71
|
+
"#EXTINF:11.344644,\n" \
|
72
|
+
"1080-7mbps00000.ts\n" \
|
73
|
+
"#EXT-X-ENDLIST\n"
|
74
|
+
io = StringIO.open
|
75
|
+
writer = M3u8::Writer.new io
|
76
|
+
writer.write playlist
|
77
|
+
expect(io.string).to eq output
|
78
|
+
|
79
|
+
options = { duration: 11.261233, segment: '1080-7mbps00001.ts' }
|
80
|
+
item = M3u8::SegmentItem.new options
|
81
|
+
playlist.items.push item
|
82
|
+
|
83
|
+
output = "#EXTM3U\n" \
|
84
|
+
"#EXT-X-VERSION:3\n" \
|
85
|
+
"#EXT-X-MEDIA-SEQUENCE:0\n" \
|
86
|
+
"#EXT-X-ALLOW-CACHE:YES\n" \
|
87
|
+
"#EXT-X-TARGETDURATION:10\n" \
|
88
|
+
"#EXTINF:11.344644,\n" \
|
89
|
+
"1080-7mbps00000.ts\n" \
|
90
|
+
"#EXTINF:11.261233,\n" \
|
91
|
+
"1080-7mbps00001.ts\n" \
|
92
|
+
"#EXT-X-ENDLIST\n"
|
93
|
+
io = StringIO.open
|
94
|
+
writer = M3u8::Writer.new io
|
95
|
+
writer.write playlist
|
96
|
+
expect(io.string).to eq output
|
97
|
+
|
98
|
+
options = { version: 1, cache: false, target: 12, sequence: 1 }
|
99
|
+
playlist = M3u8::Playlist.new options
|
100
|
+
options = { duration: 11.344644, segment: '1080-7mbps00000.ts' }
|
101
|
+
item = M3u8::SegmentItem.new options
|
102
|
+
playlist.items.push item
|
103
|
+
|
104
|
+
output = "#EXTM3U\n" \
|
105
|
+
"#EXT-X-VERSION:1\n" \
|
106
|
+
"#EXT-X-MEDIA-SEQUENCE:1\n" \
|
107
|
+
"#EXT-X-ALLOW-CACHE:NO\n" \
|
108
|
+
"#EXT-X-TARGETDURATION:12\n" \
|
109
|
+
"#EXTINF:11.344644,\n" \
|
110
|
+
"1080-7mbps00000.ts\n" \
|
111
|
+
"#EXT-X-ENDLIST\n"
|
112
|
+
io = StringIO.open
|
113
|
+
writer = M3u8::Writer.new io
|
114
|
+
writer.write playlist
|
115
|
+
expect(io.string).to eq output
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should raise error on write if item types are mixed' do
|
119
|
+
playlist = M3u8::Playlist.new
|
120
|
+
|
121
|
+
hash = { program_id: 1, width: 1920, height: 1080, codecs: 'avc',
|
122
|
+
bitrate: 540, playlist: 'test.url' }
|
123
|
+
item = M3u8::PlaylistItem.new(hash)
|
124
|
+
playlist.items.push item
|
125
|
+
|
126
|
+
hash = { duration: 10.991, segment: 'test.ts' }
|
127
|
+
item = M3u8::SegmentItem.new(hash)
|
128
|
+
playlist.items.push item
|
129
|
+
|
130
|
+
message = 'Playlist is invalid.'
|
131
|
+
io = StringIO.new
|
132
|
+
writer = M3u8::Writer.new io
|
133
|
+
expect { writer.write playlist }
|
134
|
+
.to raise_error(M3u8::PlaylistTypeError, message)
|
135
|
+
end
|
136
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: m3u8
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Seth Deckard
|
@@ -74,6 +74,7 @@ files:
|
|
74
74
|
- lib/m3u8/reader.rb
|
75
75
|
- lib/m3u8/segment_item.rb
|
76
76
|
- lib/m3u8/version.rb
|
77
|
+
- lib/m3u8/writer.rb
|
77
78
|
- m3u8.gemspec
|
78
79
|
- spec/fixtures/master.m3u8
|
79
80
|
- spec/fixtures/playlist.m3u8
|
@@ -82,6 +83,7 @@ files:
|
|
82
83
|
- spec/reader_spec.rb
|
83
84
|
- spec/segment_item_spec.rb
|
84
85
|
- spec/spec_helper.rb
|
86
|
+
- spec/writer_spec.rb
|
85
87
|
homepage: https://github.com/sethdeckard/m3u8
|
86
88
|
licenses:
|
87
89
|
- MIT
|
@@ -114,3 +116,4 @@ test_files:
|
|
114
116
|
- spec/reader_spec.rb
|
115
117
|
- spec/segment_item_spec.rb
|
116
118
|
- spec/spec_helper.rb
|
119
|
+
- spec/writer_spec.rb
|