m3uzi 0.1.4 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
data/lib/m3uzi.rb CHANGED
@@ -6,12 +6,13 @@ require 'm3uzi/version'
6
6
 
7
7
  class M3Uzi
8
8
 
9
- # Unsupported: KEY PROGRAM-DATE-TIME DISCONTINUITY
10
- VALID_TAGS = %w{TARGETDURATION MEDIA-SEQUENCE ALLOW-CACHE ENDLIST VERSION}
9
+ # Unsupported: PROGRAM-DATE-TIME DISCONTINUITY
10
+ VALID_TAGS = %w{TARGETDURATION MEDIA-SEQUENCE ALLOW-CACHE ENDLIST KEY}
11
11
 
12
12
  attr_accessor :files, :streams
13
13
  attr_accessor :tags, :comments
14
14
  attr_accessor :final_media_file
15
+ attr_accessor :version
15
16
 
16
17
  def initialize
17
18
  @files = []
@@ -19,6 +20,7 @@ class M3Uzi
19
20
  @tags = []
20
21
  @comments = []
21
22
  @final_media_file = true
23
+ @version = 1
22
24
  end
23
25
 
24
26
 
@@ -65,31 +67,38 @@ class M3Uzi
65
67
  m3u
66
68
  end
67
69
 
68
- def write(path)
69
- f = ::File.open(path, "w")
70
- f << "#EXTM3U\n"
70
+ def write_to_io(io_stream)
71
+ check_version_restrictions
72
+ io_stream << "#EXTM3U\n"
73
+ io_stream << "#EXT-X-VERSION:#{@version.to_i}" if @version > 1
71
74
  comments.each do |comment|
72
- f << "##{comment}\n"
75
+ io_stream << "##{comment}\n"
73
76
  end
74
77
  tags.each do |tag|
75
78
  next if %w{M3U ENDLIST}.include?(tag.name.to_s.upcase)
76
79
  if VALID_TAGS.include?(tag.name.to_s.upcase)
77
- f << "#EXT-X-#{tag.name.to_s.upcase}"
80
+ io_stream << "#EXT-X-#{tag.name.to_s.upcase}"
78
81
  else
79
- f << "##{tag.name.to_s.upcase}"
82
+ io_stream << "##{tag.name.to_s.upcase}"
80
83
  end
81
- tag.value && f << ":#{tag.value}"
82
- f << "\n"
84
+ tag.value && io_stream << ":#{tag.value}"
85
+ io_stream << "\n"
83
86
  end
84
87
  files.each do |file|
85
- f << "#EXTINF:#{file.attribute_string}"
86
- f << "\n#{file.path}\n"
88
+ io_stream << "#EXTINF:#{file.attribute_string}"
89
+ io_stream << "\n#{file.path}\n"
87
90
  end
88
91
  streams.each do |stream|
89
- f << "#EXT-X-STREAM-INF:#{stream.attribute_string}"
90
- f << "\n#{stream.path}\n"
92
+ io_stream << "#EXT-X-STREAM-INF:#{stream.attribute_string}"
93
+ io_stream << "\n#{stream.path}\n"
91
94
  end
92
- f << "#EXT-X-ENDLIST\n" if files.length > 0 && final_media_file
95
+ io_stream << "#EXT-X-ENDLIST\n" if files.length > 0 && final_media_file
96
+ end
97
+
98
+ def write(path)
99
+ check_version_restrictions
100
+ f = ::File.open(path, "w")
101
+ write_to_io(f)
93
102
  f.close()
94
103
  end
95
104
 
@@ -105,7 +114,7 @@ class M3Uzi
105
114
  end
106
115
 
107
116
  def filenames
108
- files.map{|file| file.path }
117
+ files.map { |file| file.path }
109
118
  end
110
119
 
111
120
 
@@ -120,7 +129,7 @@ class M3Uzi
120
129
  end
121
130
 
122
131
  def stream_names
123
- streams.map{|stream| stream.path }
132
+ streams.map { |stream| stream.path }
124
133
  end
125
134
 
126
135
 
@@ -136,7 +145,7 @@ class M3Uzi
136
145
 
137
146
  def [](key)
138
147
  tag_name = key.to_s.upcase.gsub("_", "-")
139
- obj = tags.detect{|tag| tag.name == tag_name }
148
+ obj = tags.detect { |tag| tag.name == tag_name }
140
149
  obj && obj.value
141
150
  end
142
151
 
@@ -160,6 +169,33 @@ class M3Uzi
160
169
  add_comment(comment)
161
170
  end
162
171
 
172
+ def check_version_restrictions
173
+ @version = 1
174
+
175
+ # Version 2 Features
176
+ if @tags.detect { |tag| tag.name == 'KEY' && tag.value.to_s =~ /,IV=/ }
177
+ @version = 2 if @version < 2
178
+ end
179
+
180
+ # Version 3 Features
181
+ if @files.detect { |file| file.duration.kind_of?(Float) }
182
+ @version = 3 if @version < 3
183
+ end
184
+
185
+ # Version 4 Features
186
+ if @files.detect { |file| file.byterange }
187
+ @version = 4 if @version < 4
188
+ end
189
+ if @tags.detect { |tag| ['MEDIA','I-FRAMES-ONLY'].include?(tag.name) }
190
+ @version = 4 if @version < 4
191
+ end
192
+
193
+ # NOTES
194
+ # EXT-X-I-FRAME-STREAM-INF is supposed to be ignored by older clients.
195
+ # AUDIO/VIDEO attributes of X-STREAM-INF are used in conjunction with MEDIA, so it should trigger v4.
196
+
197
+ @version
198
+ end
163
199
 
164
200
  protected
165
201
 
data/lib/m3uzi/file.rb CHANGED
@@ -1,10 +1,14 @@
1
1
  class M3Uzi
2
2
  class File
3
3
 
4
- attr_accessor :path, :duration, :description
4
+ attr_accessor :path, :duration, :description, :byterange
5
5
 
6
6
  def attribute_string
7
- "#{duration},#{description}"
7
+ if duration.kind_of?(Float)
8
+ "#{sprintf('%0.3f',duration)},#{description}"
9
+ else
10
+ "#{duration},#{description}"
11
+ end
8
12
  end
9
13
 
10
14
  end
data/lib/m3uzi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class M3Uzi
2
- VERSION = '0.1.4'
2
+ VERSION = '0.1.6'
3
3
  end
@@ -0,0 +1,78 @@
1
+ $: << File.join(File.dirname(__FILE__),'../lib')
2
+ require 'm3uzi'
3
+ require 'test/unit'
4
+ require 'rubygems'
5
+ require 'shoulda'
6
+
7
+ class M3UziTest < Test::Unit::TestCase
8
+
9
+ context "basic checks" do
10
+ should "instantiate an M3Uzi object" do
11
+ m3u = M3Uzi.new
12
+ assert_equal M3Uzi, m3u.class
13
+ end
14
+
15
+ should "read in an index file" do
16
+ m3u = M3Uzi.read(File.join(File.dirname(__FILE__), "fixtures/index.m3u8"))
17
+ assert_equal M3Uzi, m3u.class
18
+ end
19
+ end
20
+
21
+ context "with protocol versions" do
22
+ should "set version 2 for encryption IV" do
23
+ m3u = M3Uzi.new
24
+ m3u['KEY'] = "0x1234567890abcdef1234567890abcdef"
25
+ assert_equal 1, m3u.check_version_restrictions
26
+ m3u['KEY'] = "0x1234567890abcdef1234567890abcdef,IV=0x1234567890abcdef1234567890abcdef"
27
+ assert_equal 2, m3u.check_version_restrictions
28
+
29
+ output_stream = StringIO.new
30
+ m3u.write_to_io(output_stream)
31
+ assert output_stream.string =~ /,IV=/
32
+ end
33
+
34
+ should "set version 3 for floating point durations" do
35
+ m3u = M3Uzi.new
36
+ m3u.add_file do |f|
37
+ f.path = "stuff.ts"
38
+ f.duration = 10
39
+ end
40
+ assert_equal 1, m3u.check_version_restrictions
41
+
42
+ output_stream = StringIO.new
43
+ m3u.write_to_io(output_stream)
44
+ assert output_stream.string =~ /:10,/
45
+ assert output_stream.string !~ /:10\./
46
+
47
+ m3u = M3Uzi.new
48
+ m3u.add_file do |f|
49
+ f.path = "stuff.ts"
50
+ f.duration = 10.0
51
+ end
52
+ assert_equal 3, m3u.check_version_restrictions
53
+
54
+ output_stream = StringIO.new
55
+ m3u.write_to_io(output_stream)
56
+ assert output_stream.string =~ /:10\.000,/
57
+ assert output_stream.string !~ /:10,/
58
+ end
59
+
60
+ should "set version 4 for advanced features" do
61
+ m3u = M3Uzi.new
62
+ m3u.add_file do |f|
63
+ f.path = "stuff.ts"
64
+ f.duration = 10
65
+ end
66
+ assert_equal 1, m3u.check_version_restrictions
67
+
68
+ m3u = M3Uzi.new
69
+ m3u.add_file do |f|
70
+ f.path = "stuff.ts"
71
+ f.duration = 10.0
72
+ f.byterange = "1234@0"
73
+ end
74
+ assert_equal 4, m3u.check_version_restrictions
75
+ end
76
+ end
77
+
78
+ end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: m3uzi
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
7
  - 1
9
- - 4
10
- version: 0.1.4
8
+ - 6
9
+ version: 0.1.6
11
10
  platform: ruby
12
11
  authors:
13
12
  - Brandon Arbini
@@ -16,7 +15,7 @@ autorequire:
16
15
  bindir: bin
17
16
  cert_chain: []
18
17
 
19
- date: 2011-01-09 00:00:00 -06:00
18
+ date: 2011-10-10 00:00:00 -05:00
20
19
  default_executable:
21
20
  dependencies: []
22
21
 
@@ -38,7 +37,7 @@ files:
38
37
  - lib/m3uzi.rb
39
38
  - test/fixtures/index.m3u8
40
39
  - test/fixtures/stream.m3u8
41
- - test/m3uzzi_test.rb
40
+ - test/m3uzi_test.rb
42
41
  - LICENSE
43
42
  - Rakefile
44
43
  - README.md
@@ -52,27 +51,23 @@ rdoc_options: []
52
51
  require_paths:
53
52
  - lib
54
53
  required_ruby_version: !ruby/object:Gem::Requirement
55
- none: false
56
54
  requirements:
57
55
  - - ">="
58
56
  - !ruby/object:Gem::Version
59
- hash: 3
60
57
  segments:
61
58
  - 0
62
59
  version: "0"
63
60
  required_rubygems_version: !ruby/object:Gem::Requirement
64
- none: false
65
61
  requirements:
66
62
  - - ">="
67
63
  - !ruby/object:Gem::Version
68
- hash: 3
69
64
  segments:
70
65
  - 0
71
66
  version: "0"
72
67
  requirements: []
73
68
 
74
69
  rubyforge_project:
75
- rubygems_version: 1.3.7
70
+ rubygems_version: 1.3.6
76
71
  signing_key:
77
72
  specification_version: 3
78
73
  summary: Read and write M3U files with (relative) ease.
data/test/m3uzzi_test.rb DELETED
@@ -1,18 +0,0 @@
1
- require 'rubygems'
2
- require 'm3uzzi'
3
- require 'test/unit'
4
- require 'shoulda'
5
-
6
- class M3UziTest < Test::Unit::TestCase
7
-
8
- should "instantiate an M3Uzi object" do
9
- m3u = M3Uzi.new
10
- assert_equal M3Uzi, m3u.class
11
- end
12
-
13
- should "read in an index file" do
14
- m3u = M3Uzi.read_file("#{Rails.root}/test/fixtures/index.m3u8")
15
- assert_equal M3Uzi, m3u.class
16
- end
17
-
18
- end