m3u8 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +14 -4
- data/lib/m3u8/error.rb +1 -1
- data/lib/m3u8/playlist.rb +70 -70
- data/lib/m3u8/version.rb +1 -1
- data/spec/playlist_spec.rb +92 -77
- metadata +14 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9fca5696b131d1b9c9eda4235a34cf23353716d8
|
4
|
+
data.tar.gz: 0582cd52fb35119e458c373f6163be4d0eb8e4b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5b4df0be5dfea3e309644f28d2e00cd26ef9b92a9a018ff0e7714086f2c19d5f16bf40329d8e03938be20a4e829da3edc068aee820b7ab723a41e4defa5c61c
|
7
|
+
data.tar.gz: 8a137600403c6564591422778cf02cc43d6cb5baa9d51a3dcbce6d526e6fa30ed66f1a185d4523e8585ad362726f3e84a5b89ed4c7b56dd015ad90803c565aa2
|
data/README.md
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
[![Coverage Status](https://coveralls.io/repos/sethdeckard/m3u8/badge.png)](https://coveralls.io/r/sethdeckard/m3u8)
|
4
4
|
[![Code Climate](https://codeclimate.com/github/sethdeckard/m3u8/badges/gpa.svg)](https://codeclimate.com/github/sethdeckard/m3u8)
|
5
5
|
[![Dependency Status](https://gemnasium.com/sethdeckard/m3u8.svg)](https://gemnasium.com/sethdeckard/m3u8)
|
6
|
+
[![security](https://hakiri.io/github/sethdeckard/m3u8/master.svg)](https://hakiri.io/github/sethdeckard/m3u8/master)
|
6
7
|
# m3u8
|
7
8
|
|
8
9
|
m3u8 provides generation of m3u8 playlists used the [HTTP Live Streaming](https://developer.apple.com/library/ios/documentation/networkinginternet/conceptual/streamingmediaguide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008332-CH1-SW1) (HLS) specification created by Apple. This is useful if you wish to generate m3u8 playlists on the fly in your web application (to integrate authentication, do something custom, etc) while of course serving up the actual MPEG transport stream files (.ts) from a CDN. You could also use m3u8 to generate playlist files as part of an encoding pipeline.
|
@@ -46,6 +47,14 @@ Or install it yourself as:
|
|
46
47
|
options = { :version => 1, :cache => false, :target => 12, :sequence => 1}
|
47
48
|
playlist = M3u8::Playlist.new options
|
48
49
|
|
50
|
+
#You can pass an IO object to the write method
|
51
|
+
require 'tempfile'
|
52
|
+
f = Tempfile.new 'test'
|
53
|
+
playlist.write f
|
54
|
+
|
55
|
+
#You can also access the playlist as a string
|
56
|
+
playlist.to_s
|
57
|
+
|
49
58
|
#values for :audio (Codec name)
|
50
59
|
#aac-lc, he-aac, mp3
|
51
60
|
|
@@ -62,12 +71,13 @@ Or install it yourself as:
|
|
62
71
|
* Automatically generates the audio/video codec string based on names and options you are familar with.
|
63
72
|
* Provides validation of input when adding playlists or segments.
|
64
73
|
* Allows all options to be configured on a playlist (caching, version, etc.)
|
65
|
-
* Can write playlist to StringIO/File or to_s.
|
74
|
+
* Can write playlist to an IO object (StringIO/File, etc) or access string via to_s.
|
66
75
|
|
67
76
|
## Contributing
|
68
77
|
|
69
78
|
1. Fork it ( https://github.com/sethdeckard/m3u8/fork )
|
70
79
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
71
|
-
3.
|
72
|
-
4.
|
73
|
-
5.
|
80
|
+
3. Run the specs, make sure they pass and that new features are covered
|
81
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
82
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
83
|
+
6. Create a new Pull Request
|
data/lib/m3u8/error.rb
CHANGED
data/lib/m3u8/playlist.rb
CHANGED
@@ -1,50 +1,58 @@
|
|
1
1
|
module M3u8
|
2
2
|
class Playlist
|
3
|
-
attr_accessor :io, :header, :
|
4
|
-
|
5
|
-
|
3
|
+
attr_accessor :io, :options, :header, :empty, :master
|
4
|
+
MISSING_CODEC_MESSAGE = 'An audio or video codec should be provided.'
|
5
|
+
NON_MASTER_ERROR_MESSAGE = 'Playlist is not a master playlist, playlist' \
|
6
|
+
' can not be added.'
|
7
|
+
MASTER_ERROR_MESSAGE = 'Playlist is a master playlist, segment can not ' \
|
8
|
+
'be added.'
|
9
|
+
|
10
|
+
def initialize(options = {})
|
6
11
|
self.options = {
|
7
|
-
:
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
version: 3,
|
13
|
+
sequence: 0,
|
14
|
+
cache: true,
|
15
|
+
target: 10
|
16
|
+
}.merge options
|
17
|
+
|
18
|
+
self.header = false
|
19
|
+
self.empty = true
|
20
|
+
self.master = nil
|
15
21
|
self.io = StringIO.open
|
16
|
-
io.puts
|
22
|
+
io.puts '#EXTM3U'
|
17
23
|
end
|
18
24
|
|
19
|
-
def self.codecs
|
25
|
+
def self.codecs(options = {})
|
20
26
|
playlist = Playlist.new
|
21
27
|
playlist.codecs options
|
22
28
|
end
|
23
29
|
|
24
|
-
def add_playlist
|
30
|
+
def add_playlist(program_id, playlist, bitrate, options = {})
|
25
31
|
options = {
|
26
|
-
:
|
27
|
-
:
|
28
|
-
:
|
29
|
-
:
|
30
|
-
:
|
32
|
+
width: nil,
|
33
|
+
height: nil,
|
34
|
+
profile: nil,
|
35
|
+
level: nil,
|
36
|
+
audio: nil
|
31
37
|
}.merge options
|
32
38
|
|
33
39
|
validate_playlist_type true
|
34
|
-
|
35
|
-
|
40
|
+
self.master = true
|
41
|
+
self.empty = false
|
36
42
|
|
37
43
|
resolution = resolution options[:width], options[:height]
|
38
|
-
codecs = codecs(
|
39
|
-
|
40
|
-
|
44
|
+
codecs = codecs(audio: options[:audio], profile: options[:profile],
|
45
|
+
level: options[:level])
|
46
|
+
fail MissingCodecError, MISSING_CODEC_MESSAGE if codecs.nil?
|
47
|
+
io.puts "#EXT-X-STREAM-INF:PROGRAM-ID=#{program_id},#{resolution}" +
|
48
|
+
%Q{CODECS="#{codecs}",BANDWIDTH=#{bitrate}}
|
41
49
|
io.puts playlist
|
42
50
|
end
|
43
51
|
|
44
|
-
def add_segment
|
52
|
+
def add_segment(duration, segment)
|
45
53
|
validate_playlist_type false
|
46
|
-
|
47
|
-
|
54
|
+
self.master = false
|
55
|
+
self.empty = false
|
48
56
|
|
49
57
|
unless header
|
50
58
|
write_header
|
@@ -55,11 +63,11 @@ module M3u8
|
|
55
63
|
io.puts segment
|
56
64
|
end
|
57
65
|
|
58
|
-
def codecs
|
66
|
+
def codecs(options = {})
|
59
67
|
options = {
|
60
|
-
:
|
61
|
-
:
|
62
|
-
:
|
68
|
+
audio: nil,
|
69
|
+
profile: nil,
|
70
|
+
level: nil
|
63
71
|
}.merge options
|
64
72
|
|
65
73
|
audio_codec = audio_codec options[:audio]
|
@@ -67,7 +75,7 @@ module M3u8
|
|
67
75
|
|
68
76
|
if video_codec.nil?
|
69
77
|
return audio_codec
|
70
|
-
else
|
78
|
+
else
|
71
79
|
if audio_codec.nil?
|
72
80
|
return video_codec
|
73
81
|
else
|
@@ -76,35 +84,31 @@ module M3u8
|
|
76
84
|
end
|
77
85
|
end
|
78
86
|
|
79
|
-
def write
|
87
|
+
def write(output)
|
80
88
|
output.puts to_s
|
81
89
|
end
|
82
90
|
|
83
91
|
def master?
|
84
|
-
if
|
85
|
-
|
86
|
-
end
|
87
|
-
false
|
92
|
+
return false if empty
|
93
|
+
master
|
88
94
|
end
|
89
95
|
|
90
|
-
|
91
96
|
def to_s
|
92
97
|
if master?
|
93
98
|
io.string
|
94
99
|
else
|
95
|
-
io.string
|
100
|
+
"#{io.string}#EXT-X-ENDLIST"
|
96
101
|
end
|
97
102
|
end
|
98
103
|
|
99
104
|
private
|
100
105
|
|
101
|
-
def validate_playlist_type
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
end
|
106
|
+
def validate_playlist_type(master)
|
107
|
+
return if empty
|
108
|
+
if master && !master?
|
109
|
+
fail PlaylistTypeError, NON_MASTER_ERROR_MESSAGE
|
110
|
+
elsif !master && master?
|
111
|
+
fail PlaylistTypeError, MASTER_ERROR_MESSAGE
|
108
112
|
end
|
109
113
|
end
|
110
114
|
|
@@ -116,37 +120,33 @@ module M3u8
|
|
116
120
|
end
|
117
121
|
|
118
122
|
def cache_string
|
119
|
-
options[:cache] ?
|
123
|
+
options[:cache] ? 'YES' : 'NO'
|
120
124
|
end
|
121
125
|
|
122
|
-
def audio_codec
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
end
|
126
|
+
def audio_codec(audio)
|
127
|
+
return if audio.nil?
|
128
|
+
return 'mp4a.40.2' if audio.downcase == 'aac-lc'
|
129
|
+
return 'mp4a.40.5' if audio.downcase == 'he-aac'
|
130
|
+
return 'mp4a.40.34' if audio.downcase == 'mp3'
|
128
131
|
end
|
129
132
|
|
130
|
-
def video_codec
|
131
|
-
if profile.nil?
|
132
|
-
return
|
133
|
-
end
|
133
|
+
def video_codec(profile, level)
|
134
|
+
return if profile.nil? || level.nil?
|
134
135
|
|
135
136
|
profile = profile.downcase
|
136
|
-
return 'avc1.66.30' if profile == 'baseline'
|
137
|
-
return 'avc1.42001f' if profile == 'baseline'
|
138
|
-
return 'avc1.77.30' if profile == 'main'
|
139
|
-
return 'avc1.4d001f' if profile == 'main'
|
140
|
-
return 'avc1.4d0028' if profile == 'main'
|
141
|
-
return 'avc1.64001f' if profile == 'high'
|
142
|
-
return 'avc1.640028' if profile == 'high'
|
137
|
+
return 'avc1.66.30' if profile == 'baseline' && level == 3.0
|
138
|
+
return 'avc1.42001f' if profile == 'baseline' && level == 3.1
|
139
|
+
return 'avc1.77.30' if profile == 'main' && level == 3.0
|
140
|
+
return 'avc1.4d001f' if profile == 'main' && level == 3.1
|
141
|
+
return 'avc1.4d0028' if profile == 'main' && level == 4.0
|
142
|
+
return 'avc1.64001f' if profile == 'high' && level == 3.1
|
143
|
+
return 'avc1.640028' if profile == 'high' &&
|
144
|
+
(level == 4.0 || level == 4.1)
|
143
145
|
end
|
144
146
|
|
145
|
-
def resolution
|
146
|
-
|
147
|
-
|
148
|
-
end
|
147
|
+
def resolution(width, height)
|
148
|
+
return if width.nil?
|
149
|
+
"RESOLUTION=#{width}x#{height},"
|
149
150
|
end
|
150
|
-
|
151
151
|
end
|
152
|
-
end
|
152
|
+
end
|
data/lib/m3u8/version.rb
CHANGED
data/spec/playlist_spec.rb
CHANGED
@@ -5,152 +5,155 @@ describe M3u8::Playlist do
|
|
5
5
|
codecs = M3u8::Playlist.codecs
|
6
6
|
expect(codecs).to be_nil
|
7
7
|
|
8
|
-
codecs = M3u8::Playlist.codecs
|
8
|
+
codecs = M3u8::Playlist.codecs audio: 'aac-lc'
|
9
9
|
expect(codecs).to eq 'mp4a.40.2'
|
10
10
|
|
11
|
-
codecs = M3u8::Playlist.codecs
|
11
|
+
codecs = M3u8::Playlist.codecs audio: 'AAC-LC'
|
12
12
|
expect(codecs).to eq 'mp4a.40.2'
|
13
13
|
|
14
|
-
codecs = M3u8::Playlist.codecs
|
14
|
+
codecs = M3u8::Playlist.codecs audio: 'he-aac'
|
15
15
|
expect(codecs).to eq 'mp4a.40.5'
|
16
16
|
|
17
|
-
codecs = M3u8::Playlist.codecs
|
17
|
+
codecs = M3u8::Playlist.codecs audio: 'HE-AAC'
|
18
18
|
expect(codecs).to eq 'mp4a.40.5'
|
19
19
|
|
20
|
-
codecs = M3u8::Playlist.codecs
|
20
|
+
codecs = M3u8::Playlist.codecs audio: 'he-acc1'
|
21
21
|
expect(codecs).to be_nil
|
22
22
|
|
23
|
-
codecs = M3u8::Playlist.codecs
|
23
|
+
codecs = M3u8::Playlist.codecs audio: 'mp3'
|
24
24
|
expect(codecs).to eq 'mp4a.40.34'
|
25
25
|
|
26
|
-
codecs = M3u8::Playlist.codecs
|
26
|
+
codecs = M3u8::Playlist.codecs audio: 'MP3'
|
27
27
|
expect(codecs).to eq 'mp4a.40.34'
|
28
28
|
|
29
|
-
options = { :
|
29
|
+
options = { profile: 'baseline', level: 3.0 }
|
30
30
|
codecs = M3u8::Playlist.codecs options
|
31
31
|
expect(codecs).to eq 'avc1.66.30'
|
32
32
|
|
33
|
-
options = { :
|
33
|
+
options = { profile: 'baseline', level: 3.0, audio: 'aac-lc' }
|
34
34
|
codecs = M3u8::Playlist.codecs options
|
35
35
|
expect(codecs).to eq 'avc1.66.30,mp4a.40.2'
|
36
36
|
|
37
|
-
options = { :
|
37
|
+
options = { profile: 'baseline', level: 3.0, audio: 'mp3' }
|
38
38
|
codecs = M3u8::Playlist.codecs options
|
39
39
|
expect(codecs).to eq 'avc1.66.30,mp4a.40.34'
|
40
40
|
|
41
|
-
options = { :
|
41
|
+
options = { profile: 'baseline', level: 3.1 }
|
42
42
|
codecs = M3u8::Playlist.codecs options
|
43
43
|
expect(codecs).to eq 'avc1.42001f'
|
44
44
|
|
45
|
-
options = { :
|
45
|
+
options = { profile: 'baseline', level: 3.1, audio: 'he-aac' }
|
46
46
|
codecs = M3u8::Playlist.codecs options
|
47
47
|
expect(codecs).to eq 'avc1.42001f,mp4a.40.5'
|
48
48
|
|
49
|
-
options = { :
|
49
|
+
options = { profile: 'main', level: 3.0 }
|
50
50
|
codecs = M3u8::Playlist.codecs options
|
51
51
|
expect(codecs).to eq 'avc1.77.30'
|
52
52
|
|
53
|
-
options = { :
|
53
|
+
options = { profile: 'main', level: 3.0, audio: 'aac-lc' }
|
54
54
|
codecs = M3u8::Playlist.codecs options
|
55
55
|
expect(codecs).to eq 'avc1.77.30,mp4a.40.2'
|
56
56
|
|
57
|
-
options = { :
|
57
|
+
options = { profile: 'main', level: 3.1 }
|
58
58
|
codecs = M3u8::Playlist.codecs options
|
59
59
|
expect(codecs).to eq 'avc1.4d001f'
|
60
60
|
|
61
|
-
options = { :
|
61
|
+
options = { profile: 'main', level: 4.0 }
|
62
62
|
codecs = M3u8::Playlist.codecs options
|
63
63
|
expect(codecs).to eq 'avc1.4d0028'
|
64
64
|
|
65
|
-
options = { :
|
65
|
+
options = { profile: 'high', level: 3.1 }
|
66
66
|
codecs = M3u8::Playlist.codecs options
|
67
67
|
expect(codecs).to eq 'avc1.64001f'
|
68
68
|
|
69
|
-
options = { :
|
69
|
+
options = { profile: 'high', level: 4.0 }
|
70
70
|
codecs = M3u8::Playlist.codecs options
|
71
71
|
expect(codecs).to eq 'avc1.640028'
|
72
72
|
|
73
|
-
options = { :
|
73
|
+
options = { profile: 'high', level: 4.1 }
|
74
74
|
codecs = M3u8::Playlist.codecs options
|
75
75
|
expect(codecs).to eq 'avc1.640028'
|
76
76
|
end
|
77
77
|
|
78
78
|
it 'should render master playlist' do
|
79
79
|
playlist = M3u8::Playlist.new
|
80
|
-
playlist.add_playlist '1', 'playlist_url', 6400,
|
80
|
+
playlist.add_playlist '1', 'playlist_url', 6400, audio: 'mp3'
|
81
81
|
|
82
82
|
output = "#EXTM3U\n" +
|
83
|
-
|
84
|
-
|
83
|
+
%(#EXT-X-STREAM-INF:PROGRAM-ID=1,CODECS="mp4a.40.34") +
|
84
|
+
",BANDWIDTH=6400\nplaylist_url\n"
|
85
85
|
|
86
86
|
expect(playlist.to_s).to eq output
|
87
87
|
|
88
88
|
playlist = M3u8::Playlist.new
|
89
|
-
options = { :
|
90
|
-
|
89
|
+
options = { width: 1920, height: 1080, profile: 'high', level: 4.1,
|
90
|
+
audio: 'aac-lc' }
|
91
|
+
playlist.add_playlist '2', 'playlist_url', 50_000, options
|
91
92
|
|
92
|
-
output = "#EXTM3U\n"
|
93
|
-
|
94
|
-
|
93
|
+
output = "#EXTM3U\n" \
|
94
|
+
'#EXT-X-STREAM-INF:PROGRAM-ID=2,RESOLUTION=1920x1080,' +
|
95
|
+
%(CODECS="avc1.640028,mp4a.40.2",BANDWIDTH=50000\n) +
|
96
|
+
"playlist_url\n"
|
95
97
|
|
96
98
|
expect(playlist.to_s).to eq output
|
97
99
|
|
98
100
|
playlist = M3u8::Playlist.new
|
99
|
-
playlist.add_playlist '1', 'playlist_url', 6400,
|
100
|
-
options = { :
|
101
|
-
|
101
|
+
playlist.add_playlist '1', 'playlist_url', 6400, audio: 'mp3'
|
102
|
+
options = { width: 1920, height: 1080, profile: 'high', level: 4.1,
|
103
|
+
audio: 'aac-lc' }
|
104
|
+
playlist.add_playlist '2', 'playlist_url', 50_000, options
|
102
105
|
|
103
106
|
output = "#EXTM3U\n" +
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
107
|
+
%(#EXT-X-STREAM-INF:PROGRAM-ID=1,CODECS="mp4a.40.34") +
|
108
|
+
",BANDWIDTH=6400\nplaylist_url\n#EXT-X-STREAM-INF:PROGRAM-ID=2," +
|
109
|
+
%(RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2") +
|
110
|
+
",BANDWIDTH=50000\nplaylist_url\n"
|
108
111
|
|
109
112
|
expect(playlist.to_s).to eq output
|
110
113
|
end
|
111
114
|
|
112
115
|
it 'should render playlist' do
|
113
116
|
playlist = M3u8::Playlist.new
|
114
|
-
playlist.add_segment 11.344644,
|
117
|
+
playlist.add_segment 11.344644, '1080-7mbps00000.ts'
|
115
118
|
|
116
|
-
output = "#EXTM3U\n"
|
117
|
-
"#EXT-X-VERSION:3\n"
|
118
|
-
"#EXT-X-MEDIA-SEQUENCE:0\n"
|
119
|
-
"#EXT-X-ALLOW-CACHE:YES\n"
|
120
|
-
"#EXT-X-TARGETDURATION:10\n"
|
121
|
-
"#EXTINF:11.344644,\n"
|
122
|
-
"1080-7mbps00000.ts\n"
|
123
|
-
|
119
|
+
output = "#EXTM3U\n" \
|
120
|
+
"#EXT-X-VERSION:3\n" \
|
121
|
+
"#EXT-X-MEDIA-SEQUENCE:0\n" \
|
122
|
+
"#EXT-X-ALLOW-CACHE:YES\n" \
|
123
|
+
"#EXT-X-TARGETDURATION:10\n" \
|
124
|
+
"#EXTINF:11.344644,\n" \
|
125
|
+
"1080-7mbps00000.ts\n" \
|
126
|
+
'#EXT-X-ENDLIST'
|
124
127
|
|
125
128
|
expect(playlist.to_s).to eq output
|
126
129
|
|
127
|
-
playlist.add_segment 11.261233,
|
130
|
+
playlist.add_segment 11.261233, '1080-7mbps00001.ts'
|
128
131
|
|
129
|
-
output = "#EXTM3U\n"
|
130
|
-
"#EXT-X-VERSION:3\n"
|
131
|
-
"#EXT-X-MEDIA-SEQUENCE:0\n"
|
132
|
-
"#EXT-X-ALLOW-CACHE:YES\n"
|
133
|
-
"#EXT-X-TARGETDURATION:10\n"
|
134
|
-
"#EXTINF:11.344644,\n"
|
135
|
-
"1080-7mbps00000.ts\n"
|
136
|
-
"#EXTINF:11.261233,\n"
|
137
|
-
"1080-7mbps00001.ts\n"
|
138
|
-
|
132
|
+
output = "#EXTM3U\n" \
|
133
|
+
"#EXT-X-VERSION:3\n" \
|
134
|
+
"#EXT-X-MEDIA-SEQUENCE:0\n" \
|
135
|
+
"#EXT-X-ALLOW-CACHE:YES\n" \
|
136
|
+
"#EXT-X-TARGETDURATION:10\n" \
|
137
|
+
"#EXTINF:11.344644,\n" \
|
138
|
+
"1080-7mbps00000.ts\n" \
|
139
|
+
"#EXTINF:11.261233,\n" \
|
140
|
+
"1080-7mbps00001.ts\n" \
|
141
|
+
'#EXT-X-ENDLIST'
|
139
142
|
|
140
143
|
expect(playlist.to_s).to eq output
|
141
144
|
|
142
|
-
options = { :
|
145
|
+
options = { version: 1, cache: false, target: 12, sequence: 1 }
|
143
146
|
playlist = M3u8::Playlist.new options
|
144
|
-
playlist.add_segment 11.344644,
|
147
|
+
playlist.add_segment 11.344644, '1080-7mbps00000.ts'
|
145
148
|
|
146
|
-
output = "#EXTM3U\n"
|
147
|
-
"#EXT-X-VERSION:1\n"
|
148
|
-
"#EXT-X-MEDIA-SEQUENCE:1\n"
|
149
|
-
"#EXT-X-ALLOW-CACHE:NO\n"
|
150
|
-
"#EXT-X-TARGETDURATION:12\n"
|
151
|
-
"#EXTINF:11.344644,\n"
|
152
|
-
"1080-7mbps00000.ts\n"
|
153
|
-
|
149
|
+
output = "#EXTM3U\n" \
|
150
|
+
"#EXT-X-VERSION:1\n" \
|
151
|
+
"#EXT-X-MEDIA-SEQUENCE:1\n" \
|
152
|
+
"#EXT-X-ALLOW-CACHE:NO\n" \
|
153
|
+
"#EXT-X-TARGETDURATION:12\n" \
|
154
|
+
"#EXTINF:11.344644,\n" \
|
155
|
+
"1080-7mbps00000.ts\n" \
|
156
|
+
'#EXT-X-ENDLIST'
|
154
157
|
|
155
158
|
expect(playlist.to_s).to eq output
|
156
159
|
end
|
@@ -158,12 +161,21 @@ describe M3u8::Playlist do
|
|
158
161
|
it 'should write playlist to io' do
|
159
162
|
test_io = StringIO.new
|
160
163
|
playlist = M3u8::Playlist.new
|
161
|
-
playlist.add_playlist '1', 'playlist_url', 6400,
|
164
|
+
playlist.add_playlist '1', 'playlist_url', 6400, audio: 'mp3'
|
165
|
+
playlist.write test_io
|
166
|
+
|
167
|
+
output = "#EXTM3U\n" +
|
168
|
+
%(#EXT-X-STREAM-INF:PROGRAM-ID=1,CODECS="mp4a.40.34",) +
|
169
|
+
"BANDWIDTH=6400\nplaylist_url\n"
|
170
|
+
|
171
|
+
expect(test_io.string).to eq output
|
172
|
+
|
173
|
+
test_io = StringIO.new
|
162
174
|
playlist.write test_io
|
163
175
|
|
164
176
|
output = "#EXTM3U\n" +
|
165
|
-
|
166
|
-
|
177
|
+
%(#EXT-X-STREAM-INF:PROGRAM-ID=1,CODECS="mp4a.40.34",) +
|
178
|
+
"BANDWIDTH=6400\nplaylist_url\n"
|
167
179
|
|
168
180
|
expect(test_io.string).to eq output
|
169
181
|
end
|
@@ -172,27 +184,30 @@ describe M3u8::Playlist do
|
|
172
184
|
playlist = M3u8::Playlist.new
|
173
185
|
expect(playlist.master?).to be false
|
174
186
|
|
175
|
-
playlist.add_playlist '1', 'playlist_url', 6400,
|
187
|
+
playlist.add_playlist '1', 'playlist_url', 6400, audio: 'mp3'
|
176
188
|
expect(playlist.master?).to be true
|
177
189
|
end
|
178
190
|
|
179
|
-
it 'should raise error if type of playlist is changed' do
|
191
|
+
it 'should raise error if type of playlist is changed' do
|
180
192
|
playlist = M3u8::Playlist.new
|
181
|
-
playlist.add_playlist '1', 'playlist_url', 6400,
|
193
|
+
playlist.add_playlist '1', 'playlist_url', 6400, audio: 'mp3'
|
182
194
|
|
183
|
-
message =
|
184
|
-
expect { playlist.add_segment 11.344644,
|
195
|
+
message = 'Playlist is a master playlist, segment can not be added.'
|
196
|
+
expect { playlist.add_segment 11.344644, '1080-7mbps00000.ts' }
|
197
|
+
.to raise_error(M3u8::PlaylistTypeError, message)
|
185
198
|
|
186
199
|
playlist = M3u8::Playlist.new
|
187
|
-
playlist.add_segment 11.344644,
|
188
|
-
message =
|
189
|
-
expect { playlist.add_playlist '1', 'playlist_url', 6400 }
|
200
|
+
playlist.add_segment 11.344644, '1080-7mbps00000.ts'
|
201
|
+
message = 'Playlist is not a master playlist, playlist can not be added.'
|
202
|
+
expect { playlist.add_playlist '1', 'playlist_url', 6400 }
|
203
|
+
.to raise_error(M3u8::PlaylistTypeError, message)
|
190
204
|
end
|
191
205
|
|
192
206
|
it 'should raise error if codecs are missing' do
|
193
207
|
playlist = M3u8::Playlist.new
|
194
|
-
message =
|
195
|
-
expect { playlist.add_playlist '1', 'playlist_url', 6400 }
|
208
|
+
message = 'An audio or video codec should be provided.'
|
209
|
+
expect { playlist.add_playlist '1', 'playlist_url', 6400 }
|
210
|
+
.to raise_error(M3u8::MissingCodecError, message)
|
196
211
|
end
|
197
212
|
|
198
213
|
end
|
metadata
CHANGED
@@ -1,55 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: m3u8
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Seth Deckard
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.6'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.6'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '10.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '2.11'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '2.11'
|
55
55
|
description: Generate m3u8 playlists for HTTP Live Streaming (HLS).
|
@@ -59,9 +59,9 @@ executables: []
|
|
59
59
|
extensions: []
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
|
-
- .gitignore
|
63
|
-
- .rspec
|
64
|
-
- .travis.yml
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- ".travis.yml"
|
65
65
|
- Gemfile
|
66
66
|
- LICENSE.txt
|
67
67
|
- README.md
|
@@ -83,17 +83,17 @@ require_paths:
|
|
83
83
|
- lib
|
84
84
|
required_ruby_version: !ruby/object:Gem::Requirement
|
85
85
|
requirements:
|
86
|
-
- -
|
86
|
+
- - ">="
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
version: '0'
|
89
89
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
90
|
requirements:
|
91
|
-
- -
|
91
|
+
- - ">="
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0'
|
94
94
|
requirements: []
|
95
95
|
rubyforge_project:
|
96
|
-
rubygems_version: 2.
|
96
|
+
rubygems_version: 2.4.4
|
97
97
|
signing_key:
|
98
98
|
specification_version: 4
|
99
99
|
summary: Generate m3u8 playlists for HTTP Live Streaming (HLS).
|