azure_media_service 0.1.3 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 08fdee82fc0f65b5448bafb95f064da9ed031492
4
- data.tar.gz: 47143a23d14af482ba7232029c680c69aa0ad629
3
+ metadata.gz: 00a545eccf5a1d981e5d5eacbced9300cef26fd0
4
+ data.tar.gz: 5981d595b2245482d11e4aa0ad15585f7a54e85c
5
5
  SHA512:
6
- metadata.gz: 8a4528a7cebb310197623e84d367860596e42990b621d06a11935f8d0e9c0233e46ae19b832033a4cfcaf29749f08cd5b6bb331a9a460b1f4a2517c82c0b6f92
7
- data.tar.gz: 5f65881823d38b3db53843a04e2194227d830c7bdfff79492cbac328453bf6c6831e96e07314d7588ba2cba1f5534544128e9eff35dc8ba0030c65599a54da24
6
+ metadata.gz: 0fc36138286d3f0ea302c3aa559fe74c417849980ea7834611abb640242ef54a32cbf42ae2dfc7d172029f1d1bb4c53e7bcaaa05b5a6b66eb8860a0900c5a5f7
7
+ data.tar.gz: 8ca181545faa585d65657ff09ff807683e54ae638ff54a6cca82a4fc542ae3bb191f964e687b899270f778c21231666e9498123bf09b5d37caee51f867ec173e
data/README.md CHANGED
@@ -22,29 +22,30 @@ Or install it yourself as:
22
22
 
23
23
  # initialize
24
24
  AzureMediaService.configure do |config|
25
- cofig.id = 'xxxxxxxx'
25
+ cofig.id = 'xxxxxxxx'
26
26
  config.secret = 'xxxxxxxxxxxxxxxxxx'
27
27
  end
28
28
 
29
- # service instance
30
- ams = AzureMediaService.service
31
-
32
29
  # upload file
30
+ ams = AzureMediaService.service
33
31
  asset = ams.upload_media('path/to/example.mp4')
34
32
 
33
+ # or
34
+
35
+ asset = AzureMediaService::Asset.create(asset_name)
36
+ asset.upload('path/to/example.mp4')
37
+
35
38
  # encode job
36
- asset = ams.assets('nb:cid:UUID:xxxxxxxxxxx-xxxxxxxxxxx-xxxxxx-xxxxxxx')
39
+ asset = AzureMediaService::Asset.get('nb:cid:UUID:xxxxxxxxxxx-xxxxxxxxxxx-xxxxxx-xxxxxxx')
37
40
  job = asset.encode_job('H264 Smooth Streaming 720p')
38
41
 
39
42
  # or
40
- job = ams.create_encode_job('nb:cid:UUID:xxxxxxxxxxx-xxxxxxxxxxx-xxxxxx-xxxxxxx', 'H264 Smooth Streaming 720p')
43
+ job = AzureMediaService::Job.create('nb:cid:UUID:xxxxxxxxxxx-xxxxxxxxxxx-xxxxxx-xxxxxxx', 'H264 Smooth Streaming 720p')
41
44
 
42
45
  # publish asset
43
- asset = ams.assets('nb:cid:UUID:xxxxxxxxxxx-xxxxxxxxxxx-xxxxxx-xxxxxxx')
46
+ asset = AzureMediaService::Asset.get('nb:cid:UUID:xxxxxxxxxxx-xxxxxxxxxxx-xxxxxx-xxxxxxx')
44
47
  asset.publish(expire_minutes: 43200)
45
48
 
46
- # or
47
- ams.publish('nb:cid:UUID:xxxxxxxxxxx-xxxxxxxxxxx-xxxxxx-xxxxxxx', 43200)
48
49
  ```
49
50
 
50
51
  ### Custom Encode Task
@@ -54,11 +55,60 @@ AzureMediaService.configure do |config|
54
55
  config.add_encode_task('Custom Encode Task', File.read('path/to/custome_task.xml'))
55
56
  end
56
57
 
57
- ams = AzureMediaService.service
58
- asset = ams.assets('nb:cid:UUID:xxxxxxxxxxx-xxxxxxxxxxx-xxxxxx-xxxxxxx')
58
+ asset = AzureMediaService::Asset.get('nb:cid:UUID:xxxxxxxxxxx-xxxxxxxxxxx-xxxxxx-xxxxxxx')
59
59
  asset.encode_job('Custom Encode Task')
60
60
  ```
61
61
 
62
+ ### AES Protection
63
+
64
+ ```ruby
65
+ asset = AzureMediaService::Asset.get(asset_id)
66
+
67
+ key = ScureRandom::random_bytes(16)
68
+
69
+ content_key = AzureMediaService::ContentKey.create({
70
+ content_key: key,
71
+ content_key_type: AzureMediaService::ContentKey::ContentKeyTypes[:EnvelopeEncryption],
72
+ name: 'content-key-name'
73
+ })
74
+ asset.content_key_link(content_key)
75
+
76
+
77
+ content_key_policies = AzureMediaService::ContentKeyAuthorizationPolicy.get()
78
+ content_key_policy = content_key_policies.fin { |p| p.name == 'your policy name' }
79
+ unless content_key_policy
80
+ content_key_policy = AzureMediaService::ContentKeyAuthorizationPolicy.create('your policy name')
81
+ policy_options = AzureMediaService::ContentKeyAuthorizationPolicyOption.create({
82
+ name: 'policy option',
83
+ key_delivery_type: AzureMediaService::ContentKeyAuthorizationPolicyOption::KeyDeliveryTypes[:BaselineHttp],
84
+ key_delivery_configuration: nil,
85
+ restrictions: [
86
+ {
87
+ "Name" => "HLS Authorization Policy",
88
+ "KeyRestrictionType" => AzureMediaService::ContentKeyAuthorizationPolicyOption::KeyRestrictionTypes[:Open]
89
+ }
90
+ ]
91
+ })
92
+ content_key_policy.option_link(policy_options)
93
+ end
94
+
95
+ content_key.add_authorization_policy(content_key_policy.Id)
96
+
97
+ protocols = AzureMediaService::AssetDeliveryPolicy::Protocol
98
+ # Your need to register the key to your key delivery server
99
+ kid = content_key.Id.split(':').last
100
+ key_delivery_url = "your key delivery server url"
101
+ delivery_policy = AzureMediaService::AssetDeliveryPolicy.create({
102
+ name: 'your delivery policy name',
103
+ protocol: protocols[:HLS] | protocols[:SmoothStreaming] | protocols[:Dash],
104
+ policy_type: AzureMediaService::AssetDeliveryPolicy::PolicyType[:DynamicEnvelopeEncryption],
105
+ configuration: JSON.generate([{Key: AzureMediaService::AssetDeliveryPolicy::ConfigurationKey[:EnvelopeBaseKeyAcquisitionUrl], Vlaue: key_delivery_url}])
106
+ })
107
+ asset.delivery_policy_link(delivery_policy)
108
+
109
+ asset.publish(expire_minutes: 43200)
110
+ ```
111
+
62
112
  ## Contributing
63
113
 
64
114
  1. Fork it ( https://github.com/murayama/azure_media_service_ruby/fork )
@@ -5,6 +5,9 @@ require 'azure_media_service/request'
5
5
  require 'azure_media_service/service'
6
6
  require 'azure_media_service/model'
7
7
 
8
+ require 'base64'
9
+ require 'openssl'
10
+ require 'securerandom'
8
11
  require 'faraday'
9
12
  require 'faraday_middleware'
10
13
  require 'time'
@@ -12,6 +15,7 @@ require 'mime/types'
12
15
  require 'base64'
13
16
  require 'builder/xmlmarkup'
14
17
 
18
+
15
19
  module AzureMediaService
16
20
 
17
21
  @@tasks = {}
@@ -5,3 +5,7 @@ require 'azure_media_service/model/locator'
5
5
  require 'azure_media_service/model/asset_file'
6
6
  require 'azure_media_service/model/media_processor'
7
7
  require 'azure_media_service/model/job'
8
+ require 'azure_media_service/model/content_key'
9
+ require 'azure_media_service/model/content_key_authorization_policy'
10
+ require 'azure_media_service/model/content_key_authorization_policy_option'
11
+ require 'azure_media_service/model/asset_delivery_policy'
@@ -1,7 +1,16 @@
1
1
  module AzureMediaService
2
- module Model
3
- class AccessPolicy < Base
2
+ class AccessPolicy < Model::Base
4
3
 
4
+ class << self
5
+ def create(name:'Policy', duration_minutes:300, permission:2)
6
+ post_body = {
7
+ "Name" => name,
8
+ "DurationInMinutes" => duration_minutes,
9
+ "Permissions" => permission
10
+ }
11
+ create_response(service.post("AccessPolicies", post_body))
12
+ end
5
13
  end
14
+
6
15
  end
7
16
  end
@@ -1,197 +1,245 @@
1
1
  module AzureMediaService
2
- module Model
3
- class Asset < Base
4
-
5
- def locators
6
- @locators ||= []
7
- if @locators.empty?
8
- _uri = URI.parse(self.Locators["__deferred"]["uri"])
9
- url = _uri.path.gsub('/api/','')
10
- res = @request.get(url)
11
- res["d"]["results"].each do |v|
12
- @locators << Model::Locator.new(v)
13
- end
2
+ class Asset < Model::Base
3
+
4
+ class << self
5
+
6
+ def create(name)
7
+ post_body = {
8
+ "Name" => name
9
+ }
10
+ create_response(service.post("Assets", post_body))
11
+ end
12
+
13
+ def get(asset_id=nil)
14
+ service.get('Assets', Asset, asset_id)
15
+ end
16
+ end
17
+
18
+ def locators
19
+ @locators ||= []
20
+ if @locators.empty?
21
+ _uri = URI.parse(self.Locators["__deferred"]["uri"])
22
+ url = _uri.path.gsub('/api/','')
23
+ res = @request.get(url)
24
+ res["d"]["results"].each do |v|
25
+ @locators << Locator.new(v)
14
26
  end
15
- @locators
16
27
  end
28
+ @locators
29
+ end
17
30
 
18
- def files
19
- @files ||= []
20
- if @files.empty?
21
- _uri = URI.parse(self.Files["__deferred"]["uri"])
22
- url = _uri.path.gsub('/api/','')
23
- res = @request.get(url)
24
- res["d"]["results"].each do |v|
25
- @files << Model::AssetFile.new(v)
26
- end
31
+ def files
32
+ @files ||= []
33
+ if @files.empty?
34
+ _uri = URI.parse(self.Files["__deferred"]["uri"])
35
+ url = _uri.path.gsub('/api/','')
36
+ res = @request.get(url)
37
+ res["d"]["results"].each do |v|
38
+ @files << AssetFile.new(v)
27
39
  end
28
- @files
29
40
  end
41
+ @files
42
+ end
30
43
 
31
- def upload(filepath)
32
- begin
33
- mime_type = MIME::Types.type_for(filepath)[0].to_s
34
- basename = File.basename(filepath, '.*')
35
- filename = File.basename(filepath)
36
- f = Faraday::UploadIO.new(filepath, mime_type)
37
-
38
- # create policy
39
- policy = @service.create_access_policy(name:"UploadPolicy", duration_minutes:1800, permission:2)
40
-
41
- # create Locator
42
- locator = @service.create_locator(policy_id:policy.Id, asset_id:self.Id, type:1)
43
-
44
- # upload
45
- upload_url = File.join(locator.BaseUri, filename)
46
- upload_url += locator.ContentAccessComponent
47
-
48
- if f.size > Config::UPLOAD_LIMIT_SIZE
49
- # put block and put block list API
50
- i = 1
51
- blockids = []
52
- while buf = f.read(Config::READ_BUFFER_SIZE) do
53
- id = "%05d" % i # サイズを同じにしなければいけないので、5桁にする
54
- blockid = Base64.strict_encode64("#{id}-#{filename}")
55
- blockids << blockid
56
- put_block_url = upload_url + "&comp=block&blockid=#{URI.escape(blockid)}"
57
- res = put_blob(url:put_block_url, blob:buf)
58
- i+=1
59
- end
44
+ def content_keys
45
+ @content_keys ||= []
46
+ if @content_keys.empty?
47
+ _uri = URI.parse(self.ContentKeys["__deferred"]["uri"])
48
+ url = _uri.path.gsub('/api/','')
49
+ res = @request.get(url)
50
+ res["d"]["results"].each do |v|
51
+ @content_keys << ContentKey.new(v)
52
+ end
53
+ end
54
+ @content_keys
55
+ end
60
56
 
61
- put_block_list_url = upload_url + "&comp=blocklist"
62
- let = ''
63
- xml = Builder::XmlMarkup.new(:target => let, :indent => 3)
64
- xml.instruct!
65
- xml.BlockList {
66
- blockids.each do |id|
67
- xml.Latest id
68
- end
69
- }
70
-
71
- res = @request.put(put_block_list_url, let) do |headers|
72
- headers['x-ms-date'] = Time.now.httpdate
73
- headers['x-ms-version'] = '2014-02-14'
74
- headers['Content-Type'] = 'text/plain; charset = UTF-8'
75
- headers['Content-Length'] = let.size.to_s
76
- end
57
+ def delivery_policies
58
+ @delivery_policies ||= []
59
+ if @delivery_policies.empty?
60
+ _uri = URI.parse(self.DeliveryPolicies["__deferred"]["uri"])
61
+ url = _uri.path.gsub('/api/','')
62
+ res = @request.get(url)
63
+ res["d"]["results"].each do |v|
64
+ @delivery_policies << AssetDeliveryPolicy.new(v)
65
+ end
66
+ end
67
+ @delivery_policies
68
+ end
77
69
 
78
- else
79
- res = put_blob(url:upload_url, blob:f)
70
+ def upload(filepath)
71
+ begin
72
+ mime_type = MIME::Types.type_for(filepath)[0].to_s
73
+ basename = File.basename(filepath, '.*')
74
+ filename = File.basename(filepath)
75
+ f = Faraday::UploadIO.new(filepath, mime_type)
76
+
77
+ # create policy
78
+ policy = AccessPolicy.create(name:"UploadPolicy", duration_minutes:1800, permission:2)
79
+
80
+ # create Locator
81
+ locator = Locator.create(policy_id:policy.Id, asset_id:self.Id, type:1)
82
+
83
+ # upload
84
+ upload_url = File.join(locator.BaseUri, filename)
85
+ upload_url += locator.ContentAccessComponent
86
+
87
+ if f.size > Config::UPLOAD_LIMIT_SIZE
88
+ # put block and put block list API
89
+ i = 1
90
+ blockids = []
91
+ while buf = f.read(Config::READ_BUFFER_SIZE) do
92
+ id = "%05d" % i # サイズを同じにしなければいけないので、5桁にする
93
+ blockid = Base64.strict_encode64("#{id}-#{filename}")
94
+ blockids << blockid
95
+ put_block_url = upload_url + "&comp=block&blockid=#{URI.escape(blockid)}"
96
+ res = put_blob(url:put_block_url, blob:buf)
97
+ i+=1
80
98
  end
81
99
 
82
- # create metadata
83
- @request.get("CreateFileInfos", {"assetid" => "'#{URI.encode(self.Id)}'"})
100
+ put_block_list_url = upload_url + "&comp=blocklist"
101
+ let = ''
102
+ xml = Builder::XmlMarkup.new(:target => let, :indent => 3)
103
+ xml.instruct!
104
+ xml.BlockList {
105
+ blockids.each do |id|
106
+ xml.Latest id
107
+ end
108
+ }
109
+
110
+ res = @request.put_row(put_block_list_url, let) do |headers|
111
+ headers['x-ms-date'] = Time.now.httpdate
112
+ headers['x-ms-version'] = '2014-02-14'
113
+ headers['Content-Type'] = 'text/plain; charset = UTF-8'
114
+ headers['Content-Length'] = let.size.to_s
115
+ end
84
116
 
85
- clear_cache
86
- rescue => e
87
- raise MediaServiceError.new(e.message)
117
+ else
118
+ res = put_blob(url:upload_url, blob:f)
88
119
  end
89
- self
120
+
121
+ # create metadata
122
+ @request.get("CreateFileInfos", {"assetid" => "'#{URI.encode(self.Id)}'"})
123
+
124
+ clear_cache
125
+ rescue => e
126
+ raise MediaServiceError.new(e.message)
90
127
  end
128
+ self
129
+ end
91
130
 
92
131
 
93
- def encode_job(encode_configuration)
94
- media_processor = @service.media_processor_id_by_name('Windows Azure Media Encoder')
132
+ def encode_job(encode_configuration)
133
+ media_processor = @service.media_processor_id_by_name('Windows Azure Media Encoder')
95
134
 
96
- conf_str = encode_configuration.gsub(' ', '_')
135
+ conf_str = encode_configuration.gsub(' ', '_')
97
136
 
98
- if AzureMediaService.encode_tasks.has_key?(encode_configuration)
99
- encode_configuration = AzureMediaService.encode_tasks[encode_configuration]
100
- end
137
+ if AzureMediaService.encode_tasks.has_key?(encode_configuration)
138
+ encode_configuration = AzureMediaService.encode_tasks[encode_configuration]
139
+ end
101
140
 
102
- job_name, output_name = job_and_output_name(asset_name:self.Name, conf:conf_str)
141
+ job_name, output_name = job_and_output_name(asset_name:self.Name, conf:conf_str)
103
142
 
104
- post_body = {}
105
- post_body["Name"] = job_name
106
- post_body["InputMediaAssets"] = [
107
- {
108
- "__metadata" => {
109
- "uri" => self.__metadata["uri"]
110
- }
143
+ post_body = {}
144
+ post_body["Name"] = job_name
145
+ post_body["InputMediaAssets"] = [
146
+ {
147
+ "__metadata" => {
148
+ "uri" => self.__metadata["uri"]
111
149
  }
112
- ]
113
- task_body = ''
114
- xml = Builder::XmlMarkup.new(:target => task_body)
115
- xml.instruct!
116
- xml.taskBody {
117
- xml.inputAsset 'JobInputAsset(0)'
118
- xml.outputAsset 'JobOutputAsset(0)', :assetName => output_name
119
150
  }
120
- post_body["Tasks"] = [
121
- {
122
- "Configuration" => encode_configuration,
123
- "MediaProcessorId" => media_processor.Id,
124
- "TaskBody" => task_body
125
- }
126
- ]
151
+ ]
152
+ task_body = ''
153
+ xml = Builder::XmlMarkup.new(:target => task_body)
154
+ xml.instruct!
155
+ xml.taskBody {
156
+ xml.inputAsset 'JobInputAsset(0)'
157
+ xml.outputAsset 'JobOutputAsset(0)', :assetName => output_name
158
+ }
159
+ post_body["Tasks"] = [
160
+ {
161
+ "Configuration" => encode_configuration,
162
+ "MediaProcessorId" => media_processor.Id,
163
+ "TaskBody" => task_body
164
+ }
165
+ ]
127
166
 
128
- res = @request.post('Jobs', post_body)
129
- Model::Job.new(res["d"])
130
- end
167
+ res = @request.post('Jobs', post_body)
168
+ Job.new(res["d"])
169
+ end
131
170
 
132
171
 
133
- def publish(expire_minutes: 43200)
134
- locator = locators.select {|l| l.Type == 2}.first
135
- unless locator
136
- policy = @service.create_access_policy(name:"PublishPolicy", duration_minutes: expire_minutes, permission:1)
137
- locator = @service.create_locator(policy_id: policy.Id, asset_id: self.Id, type: 2)
138
- end
139
- locator
172
+ def publish(expire_minutes: 43200)
173
+ locator = locators.select {|l| l.Type == 2}.first
174
+ unless locator
175
+ policy = AccessPolicy.create(name:"PublishPolicy", duration_minutes: expire_minutes, permission:1)
176
+ locator = Locator.create(policy_id: policy.Id, asset_id: self.Id, type: 2)
140
177
  end
178
+ locator
179
+ end
141
180
 
142
- def publish_url
143
- primary_file = files.select {|f| f.IsPrimary == true}.first
144
- locator = locators.select {|l| l.Type == 2 }.first
145
- if primary_file && locator
146
- File.join(locator.Path, primary_file.Name, 'Manifest')
147
- else
148
- nil
149
- end
181
+ def publish_url
182
+ primary_file = files.select {|f| f.IsPrimary == true}.first
183
+ locator = locators.select {|l| l.Type == 2 }.first
184
+ if primary_file && locator
185
+ File.join(locator.Path, primary_file.Name, 'Manifest')
186
+ else
187
+ nil
150
188
  end
189
+ end
151
190
 
152
- def delete
153
- begin
154
- res = @request.delete("Assets('#{self.Id}')")
155
- clear_cache
156
- rescue => e
157
- raise MediaServiceError.new(e.message)
158
- end
159
- res
191
+ def delete
192
+ begin
193
+ res = @request.delete("Assets('#{self.Id}')")
194
+ clear_cache
195
+ rescue => e
196
+ raise MediaServiceError.new(e.message)
160
197
  end
198
+ res
199
+ end
161
200
 
162
- private
201
+ def content_key_link(content_key)
202
+ @request.post("Assets('#{CGI.escape(self.Id)}')/$links/ContentKeys", {uri: content_key.__metadata['uri']})
203
+ end
163
204
 
164
- def clear_cache
165
- @locators = nil
166
- @files = nil
167
- self
168
- end
205
+ def delivery_policy_link(asset_delivery_policy)
206
+ @request.post("Assets('#{CGI.escape(self.Id)}')/$links/DeliveryPolicies", {uri: asset_delivery_policy.__metadata['uri']})
207
+ end
169
208
 
170
- def job_and_output_name(asset_name:, conf:)
171
- job_names = []
172
- job_names << asset_name
173
- job_names << 'EncodeJob'
174
- job_names << conf
175
- job_name = job_names.join('-')
209
+ private
176
210
 
177
- output_names = []
178
- output_names << asset_name
179
- output_names << conf
180
- output_names << 'Output'
181
- output_name = output_names.join('-')
211
+ def clear_cache
212
+ @locators = nil
213
+ @files = nil
214
+ @content_keys = nil
215
+ @delivery_policies = nil
216
+ self
217
+ end
182
218
 
183
- [job_name, output_name]
184
- end
219
+ def job_and_output_name(asset_name:, conf:)
220
+ job_names = []
221
+ job_names << asset_name
222
+ job_names << 'EncodeJob'
223
+ job_names << conf
224
+ job_name = job_names.join('-')
185
225
 
186
- def put_blob(url:, blob:)
187
- res = @request.put(url, blob) do |headers|
188
- headers['x-ms-blob-type'] = 'BlockBlob'
189
- headers['x-ms-version'] = '2014-02-14' # Storage API Version
190
- headers['Content-Type'] = 'application/octet-stream'
191
- headers['Content-Length'] = blob.size.to_s
192
- end
193
- end
226
+ output_names = []
227
+ output_names << asset_name
228
+ output_names << conf
229
+ output_names << 'Output'
230
+ output_name = output_names.join('-')
231
+
232
+ [job_name, output_name]
194
233
  end
195
234
 
235
+ def put_blob(url:, blob:)
236
+ res = @request.put_row(url, blob) do |headers|
237
+ headers['x-ms-blob-type'] = 'BlockBlob'
238
+ headers['x-ms-version'] = '2014-02-14' # Storage API Version
239
+ headers['Content-Type'] = 'application/octet-stream'
240
+ headers['Content-Length'] = blob.size.to_s
241
+ end
242
+ end
196
243
  end
244
+
197
245
  end
@@ -0,0 +1,57 @@
1
+ module AzureMediaService
2
+ class AssetDeliveryPolicy < Model::Base
3
+
4
+ Protocol = {
5
+ None: 0x0,
6
+ SmoothStreaming: 0x1,
7
+ Dash: 0x2,
8
+ HLS: 0x4,
9
+ Hds: 0x8,
10
+ All: 0xFFFF
11
+ }
12
+
13
+ PolicyType = {
14
+ None: 0,
15
+ Blocked: 1,
16
+ NoDynamicEncryption: 2,
17
+ DynamicEnvelopeEncryption: 3,
18
+ DynamicCommonEncryption: 4
19
+ }
20
+
21
+ ConfigurationKey = {
22
+ None: 0,
23
+ EnvelopeKeyAcquisitionUrl: 1,
24
+ EnvelopeBaseKeyAcquisitionUrl: 2,
25
+ EnvelopeEncryptionIVAsBase64: 3,
26
+ PlayReadyLicenseAcquisitionUrl: 4,
27
+ PlayReadyCustomAttributes: 5,
28
+ EnvelopeEncryptionIV: 6
29
+ }
30
+
31
+
32
+ class << self
33
+ def create(name:, protocol:, policy_type:, configuration:)
34
+ body = {
35
+ "Name" => name,
36
+ "AssetDeliveryProtocol" => protocol,
37
+ "AssetDeliveryPolicyType" => policy_type,
38
+ "AssetDeliveryConfiguration" => configuration
39
+ }
40
+ create_response(service.post("AssetDeliveryPolicies", body))
41
+ end
42
+
43
+ def get(asset_delivery_policy_id=nil)
44
+ service.get("AssetDeliveryPolicies", AssetDeliveryPolicy, asset_delivery_policy_id)
45
+ end
46
+ end
47
+
48
+ def delete
49
+ begin
50
+ res = @request.delete("AssetDeliveryPolicies('#{self.Id}')")
51
+ rescue => e
52
+ raise MediaServiceError.new(e.message)
53
+ end
54
+ res
55
+ end
56
+ end
57
+ end
@@ -1,7 +1,5 @@
1
1
  module AzureMediaService
2
- module Model
3
- class AssetFile < Base
2
+ class AssetFile < Model::Base
4
3
 
5
- end
6
4
  end
7
5
  end
@@ -11,6 +11,22 @@ module AzureMediaService
11
11
  @request = AzureMediaService.request
12
12
  @service = AzureMediaService.service
13
13
  end
14
+
15
+ class << self
16
+
17
+ def service
18
+ AzureMediaService.service
19
+ end
20
+
21
+ def create_response(res)
22
+ if res["d"]
23
+ self.new(res["d"])
24
+ else
25
+ raise MediaServiceError.new(res["error"]["message"]["value"])
26
+ end
27
+ end
28
+
29
+ end
14
30
  end
15
31
  end
16
32
  end
@@ -0,0 +1,71 @@
1
+ module AzureMediaService
2
+ class ContentKey < Model::Base
3
+
4
+ ContentKeyTypes = {
5
+ CommonEncryption: 0,
6
+ StorageEncryption: 1,
7
+ ConfigurationEncryption: 2,
8
+ UrlEncryption: 3,
9
+ EnvelopeEncryption: 4
10
+ }
11
+
12
+ class << self
13
+ def create(content_key:, content_key_type: 4,protection_key_type: 0, name: nil )
14
+ id = "nb:kid:UUID:#{SecureRandom.uuid.upcase}"
15
+ # content_key = SecureRandom.random_bytes(16)
16
+ protection_key_id = service.get_protection_key_id(content_key_type)
17
+ protection_key = service.get_protection_key(protection_key_id) # X.509
18
+ x509 = OpenSSL::X509::Certificate.new(Base64.decode64(protection_key))
19
+ public_key = x509.public_key
20
+ encrypted_content_key = Base64.strict_encode64(public_key.public_encrypt(content_key, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING))
21
+
22
+ # create checksum
23
+ cipher = OpenSSL::Cipher.new('AES-128-ECB')
24
+ cipher.encrypt
25
+ cipher.key = content_key
26
+ cipher.padding = 0
27
+ encrypt_data = ""
28
+ encrypt_data << cipher.update(protection_key_id[0,16])
29
+ encrypt_data << cipher.final
30
+ check_sum = Base64.strict_encode64(encrypt_data[0,8])
31
+
32
+ post_body = {
33
+ "Id" => id,
34
+ "ContentKeyType" => content_key_type,
35
+ "EncryptedContentKey" => encrypted_content_key,
36
+ "ProtectionKeyId" => protection_key_id,
37
+ "ProtectionKeyType" => protection_key_type,
38
+ "Checksum" => check_sum,
39
+ "Name" => name
40
+ }
41
+ create_response(service.post("ContentKeys", post_body))
42
+ end
43
+
44
+ def get(content_key_id=nil)
45
+ service.get('ContentKeys', ContentKey, content_key_id)
46
+ end
47
+ end
48
+
49
+ def add_authorization_policy(policy_id)
50
+ res = @request.put("ContentKeys('#{CGI.escape(self.Id)}')", {AuthorizationPolicyId: policy_id})
51
+ end
52
+
53
+ # GetKeyDeliveryUrl
54
+ #
55
+ # @params key_delivery_type 1: PlayReady license 2: EnvelopeEncryption
56
+ #
57
+ def get_key_delivery_url(key_delivery_type)
58
+ @request.post("ContentKeys('#{CGI.escape(self.Id)}')/GetKeyDeliveryUrl", {KeyDeliveryType: key_delivery_type})
59
+ end
60
+
61
+ def delete
62
+ begin
63
+ res = @request.delete("ContentKeys('#{self.Id}')")
64
+ clear_cache
65
+ rescue => e
66
+ raise MediaServiceError.new(e.message)
67
+ end
68
+ res
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,27 @@
1
+ module AzureMediaService
2
+ class ContentKeyAuthorizationPolicy < Model::Base
3
+
4
+ class << self
5
+ def create(name)
6
+ create_response(service.post("ContentKeyAuthorizationPolicies", {Name: name}))
7
+ end
8
+
9
+ def get(content_key_authorization_policy_id=nil)
10
+ service.get("ContentKeyAuthorizationPolicies", ContentKeyAuthorizationPolicy, content_key_authorization_policy_id)
11
+ end
12
+ end
13
+
14
+ def option_link(options)
15
+ @request.post("ContentKeyAuthorizationPolicies('#{CGI.escape(self.Id)}')/$links/Options", {uri: options.__metadata['uri']})
16
+ end
17
+
18
+ def delete
19
+ begin
20
+ res = @request.delete("ContentKeyAuthorizationPolicies('#{self.Id}')")
21
+ rescue => e
22
+ raise MediaServiceError.new(e.message)
23
+ end
24
+ res
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,44 @@
1
+ module AzureMediaService
2
+ class ContentKeyAuthorizationPolicyOption < Model::Base
3
+
4
+ KeyDeliveryTypes = {
5
+ None: 0,
6
+ PlayReadyLicense: 1,
7
+ BaselineHttp: 2
8
+ }
9
+
10
+ KeyRestrictionTypes = {
11
+ Open: 0,
12
+ TokenRestricted: 1,
13
+ IPRestricted: 2
14
+ }
15
+
16
+ class << self
17
+ def create(name:, key_delivery_type:, key_delivery_configuration: nil, restrictions:)
18
+ post_body = {
19
+ "Name" => name,
20
+ "KeyDeliveryType" => key_delivery_type,
21
+ "Restrictions" => {"results" => restrictions}
22
+ }
23
+ if key_delivery_configuration
24
+ post_body["KeyDeliveryConfiguration"] = key_delivery_configuration
25
+ end
26
+ create_response(service.post("ContentKeyAuthorizationPolicyOptions", post_body))
27
+ end
28
+
29
+ def get(content_key_authorization_policy_option_id=nil)
30
+ service.get("ContentKeyAuthorizationPolicyOptions", ContentKeyAuthorizationPolicyOption, content_key_authorization_policy_option_id)
31
+ end
32
+ end
33
+
34
+ def delete
35
+ begin
36
+ res = @request.delete("ContentKeyAuthorizationPolicyOptions('#{self.Id}')")
37
+ rescue => e
38
+ raise MediaServiceError.new(e.message)
39
+ end
40
+ res
41
+ end
42
+ end
43
+ end
44
+
@@ -1,32 +1,41 @@
1
1
  module AzureMediaService
2
- module Model
3
- class Job < Base
2
+ class Job < Model::Base
4
3
 
5
- def output_assets
6
- @output_assets ||= []
7
- if @output_assets.empty?
8
- _uri = URI.parse(self.OutputMediaAssets["__deferred"]["uri"])
9
- url = _uri.path.gsub('/api/','')
10
- res = @request.get(url)
11
- res["d"]["results"].each do |v|
12
- @output_assets << Model::Asset.new(v)
13
- end
4
+ class << self
5
+ def create(asset_id, encode_configuration)
6
+ asset = Asset.get(asset_id)
7
+ asset.encode_job(encode_configuration)
8
+ end
9
+
10
+ def get(job_id=nil)
11
+ service.get('Jobs', Job, job_id)
12
+ end
13
+ end
14
+
15
+ def output_assets
16
+ @output_assets ||= []
17
+ if @output_assets.empty?
18
+ _uri = URI.parse(self.OutputMediaAssets["__deferred"]["uri"])
19
+ url = _uri.path.gsub('/api/','')
20
+ res = @request.get(url)
21
+ res["d"]["results"].each do |v|
22
+ @output_assets << Asset.new(v)
14
23
  end
15
- @output_assets
16
24
  end
25
+ @output_assets
26
+ end
17
27
 
18
- def input_assets
19
- @input_assets ||= []
20
- if @input_assets.empty?
21
- _uri = URI.parse(self.InputMediaAssets["__deferred"]["uri"])
22
- url = _uri.path.gsub('/api/','')
23
- res = @request.get(url)
24
- res["d"]["results"].each do |v|
25
- @input_assets << Model::Asset.new(v)
26
- end
28
+ def input_assets
29
+ @input_assets ||= []
30
+ if @input_assets.empty?
31
+ _uri = URI.parse(self.InputMediaAssets["__deferred"]["uri"])
32
+ url = _uri.path.gsub('/api/','')
33
+ res = @request.get(url)
34
+ res["d"]["results"].each do |v|
35
+ @input_assets << Asset.new(v)
27
36
  end
28
- @input_assets
29
37
  end
38
+ @input_assets
30
39
  end
31
40
  end
32
41
  end
@@ -1,7 +1,17 @@
1
1
  module AzureMediaService
2
- module Model
3
- class Locator < Base
2
+ class Locator < Model::Base
4
3
 
4
+ class << self
5
+ def create(policy_id:,asset_id:,type:1)
6
+ post_body = {
7
+ "AccessPolicyId" => policy_id,
8
+ "AssetId" => asset_id,
9
+ "Type" => type,
10
+ "StartTime" => (Time.now - 5*60).gmtime.strftime('%Y-%m-%dT%H:%M:%SZ')
11
+ }
12
+ create_response(service.post("Locators", post_body))
13
+ end
5
14
  end
15
+
6
16
  end
7
17
  end
@@ -1,7 +1,5 @@
1
1
  module AzureMediaService
2
- module Model
3
- class MediaProcessor < Base
2
+ class MediaProcessor < Model::Base
4
3
 
5
- end
6
4
  end
7
5
  end
@@ -20,6 +20,9 @@ module AzureMediaService
20
20
  @config[:mediaURI] = res.headers['location']
21
21
  get(endpoint, params)
22
22
  else
23
+ if res.headers[:error]
24
+ raise MediaServiceError.new("#{res.headers[:error]}: #{res.headers[:error_description]}")
25
+ end
23
26
  res.body
24
27
  end
25
28
  end
@@ -38,11 +41,35 @@ module AzureMediaService
38
41
  @config[:mediaURI] = res.headers['location']
39
42
  post(endpoint, body)
40
43
  else
44
+ if res.headers[:error]
45
+ raise MediaServiceError.new("#{res.headers[:error]}: #{res.headers[:error_description]}")
46
+ end
41
47
  res.body
42
48
  end
43
49
  end
44
50
 
45
- def put(url, body)
51
+ def put(endpoint, body)
52
+ setToken if token_expire?
53
+
54
+ res = conn(@config[:mediaURI]).put do |req|
55
+ req.url endpoint
56
+ req.headers = @default_headers
57
+ req.headers[:Authorization] = "Bearer #{@access_token}"
58
+ req.body = body
59
+ end
60
+
61
+ if res.status == 301
62
+ @config[:mediaURI] = res.headers['location']
63
+ post(endpoint, body)
64
+ else
65
+ if res.headers[:error]
66
+ raise MediaServiceError.new("#{res.headers[:error]}: #{res.headers[:error_description]}")
67
+ end
68
+ res.body
69
+ end
70
+ end
71
+
72
+ def put_row(url, body)
46
73
 
47
74
  _conn = conn(url) do |builder|
48
75
  builder.request :multipart
@@ -62,6 +89,9 @@ module AzureMediaService
62
89
  @config[:mediaURI] = res.headers['location']
63
90
  put(url, body)
64
91
  else
92
+ if res.headers[:error]
93
+ raise MediaServiceError.new("#{res.headers[:error]}: #{res.headers[:error_description]}")
94
+ end
65
95
  res.body
66
96
  end
67
97
  end
@@ -81,6 +111,9 @@ module AzureMediaService
81
111
  @config[:mediaURI] = res.headers['location']
82
112
  delete(endpoint, params)
83
113
  else
114
+ if res.headers[:error]
115
+ raise MediaServiceError.new("#{res.headers[:error]}: #{res.headers[:error_description]}")
116
+ end
84
117
  res.body
85
118
  end
86
119
  end
@@ -100,7 +133,7 @@ module AzureMediaService
100
133
  "Accept" => "application/json;odata=verbose",
101
134
  "DataServiceVersion" => "3.0",
102
135
  "MaxDataServiceVersion" => "3.0",
103
- "x-ms-version" => "2.5"
136
+ "x-ms-version" => "2.9"
104
137
  }
105
138
  end
106
139
 
@@ -7,31 +7,35 @@ module AzureMediaService
7
7
 
8
8
  # assets
9
9
  def assets(asset_id=nil)
10
- get('Assets', Model::Asset, asset_id)
10
+ warn("DEPRECATION WARNING: Service#assets is deprecated. Use AzureMediaService::Asset.get() instead.")
11
+ get('Assets', Asset, asset_id)
11
12
  end
12
13
 
13
14
  # assets create
14
15
  def create_asset(name)
16
+ warn("DEPRECATION WARNING: Service#create_asset is deprecated. Use AzureMediaService::Asset.create() instead.")
15
17
  post_body = {
16
18
  "Name" => name
17
19
  }
18
20
  res = @request.post("Assets", post_body)
19
- Model::Asset.new(res["d"])
21
+ Asset.new(res["d"])
20
22
  end
21
23
 
22
24
  # access policy create
23
25
  def create_access_policy(name:'Policy', duration_minutes:300, permission:2)
26
+ warn("DEPRECATION WARNING: Service#create_access_policy is deprecated. Use AzureMediaService::AccessPolicy.create() instead.")
24
27
  post_body = {
25
28
  "Name" => name,
26
29
  "DurationInMinutes" => duration_minutes,
27
30
  "Permissions" => permission
28
31
  }
29
32
  res = @request.post("AccessPolicies", post_body)
30
- Model::AccessPolicy.new(res["d"])
33
+ AccessPolicy.new(res["d"])
31
34
  end
32
35
 
33
36
  # locator create
34
37
  def create_locator(policy_id:,asset_id:,type:1)
38
+ warn("DEPRECATION WARNING: Service#create_locator is deprecated. Use AzureMediaService::Locator.create() instead.")
35
39
  post_body = {
36
40
  "AccessPolicyId" => policy_id,
37
41
  "AssetId" => asset_id,
@@ -39,33 +43,38 @@ module AzureMediaService
39
43
  "StartTime" => (Time.now - 5*60).gmtime.strftime('%Y-%m-%dT%H:%M:%SZ')
40
44
  }
41
45
  res = @request.post("Locators", post_body)
42
- Model::Locator.new(res["d"])
46
+ Locator.new(res["d"])
43
47
  end
44
48
 
45
49
  def upload_media(filepath)
46
50
  basename = File.basename(filepath, '.*')
47
51
  asset_name = "#{basename}-Source-#{Time.now.strftime('%Y%m%d%H%M%S')}"
48
- asset = create_asset(asset_name)
52
+ asset = Asset.create(asset_name)
49
53
  asset.upload(filepath)
50
54
  end
51
55
 
52
56
  def create_encode_job(asset_id, encode_configuration)
57
+ warn("DEPRECATION WARNING: Service#create_encode_job is deprecated. Use AzureMediaService::Job.create() instead.")
53
58
  asset = assets(asset_id)
54
59
  asset.encode_job(encode_configuration)
55
60
  end
56
61
 
57
62
  def jobs(job_id=nil)
58
- get('Jobs', Model::Job, job_id)
63
+ warn("DEPRECATION WARNING: Service#jobs is deprecated. Use AzureMediaService::Job.get() instead.")
64
+ get('Jobs', Job, job_id)
59
65
  end
60
66
 
67
+
61
68
  # publish asset
62
69
  def publish(asset_id, expire_minutes=nil)
63
- asset = assets(asset_id)
70
+ warn("DEPRECATION WARNING: Service#publish is deprecated. Use AzureMediaService::Asset#publish() instead.")
71
+ asset = Asset.get(asset_id)
64
72
  asset.publish(expire_minutes)
65
73
  end
66
74
 
67
75
  def publish_url(asset_id)
68
- asset = assets(asset_id)
76
+ warn("DEPRECATION WARNING: Service#publish_url is deprecated. Use AzureMediaService::Asset#publish_url() instead.")
77
+ asset = Asset.get(asset_id)
69
78
  asset.publish_url
70
79
  end
71
80
 
@@ -76,22 +85,49 @@ module AzureMediaService
76
85
  }.sort{|a,b|
77
86
  b["Version"].to_i <=> a["Version"].to_i
78
87
  }.first
79
- Model::MediaProcessor.new(mp)
88
+ MediaProcessor.new(mp)
89
+ end
90
+
91
+ def get_protection_key_id(content_key_type)
92
+ res = @request.get("GetProtectionKeyId", contentKeyType: content_key_type)
93
+ if res["d"]
94
+ res["d"]["GetProtectionKeyId"]
95
+ else
96
+ raise MediaServiceError.new(res["error"]["message"]["value"])
97
+ end
98
+ end
99
+
100
+ def get_protection_key(protection_key_id)
101
+ res = @request.get("GetProtectionKey", ProtectionKeyId: "'#{protection_key_id}'")
102
+ if res["d"]
103
+ res["d"]["GetProtectionKey"]
104
+ else
105
+ raise MediaServiceError.new(res["error"]["message"]["value"])
106
+ end
80
107
  end
81
108
 
82
109
  def get(method, klass, id=nil)
83
110
  if id.nil?
84
111
  res = @request.get(method)
85
112
  results = []
86
- res["d"]["results"].each do |a|
87
- results << klass.new(a)
113
+ if res["d"]
114
+ res["d"]["results"].each do |a|
115
+ results << klass.new(a)
116
+ end
88
117
  end
89
118
  else
90
119
  res = @request.get("#{method}('#{id}')")
91
- results = klass.new(res["d"])
120
+ results = nil
121
+ if res["d"]
122
+ results = klass.new(res["d"])
123
+ end
92
124
  end
93
125
  results
94
126
  end
95
127
 
128
+ def post(method, body)
129
+ @request.post(method, body)
130
+ end
131
+
96
132
  end
97
133
  end
@@ -1,3 +1,3 @@
1
1
  module AzureMediaService
2
- VERSION = "0.1.3"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: azure_media_service
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - murayama
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-04 00:00:00.000000000 Z
11
+ date: 2015-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -127,8 +127,12 @@ files:
127
127
  - lib/azure_media_service/model.rb
128
128
  - lib/azure_media_service/model/access_policy.rb
129
129
  - lib/azure_media_service/model/asset.rb
130
+ - lib/azure_media_service/model/asset_delivery_policy.rb
130
131
  - lib/azure_media_service/model/asset_file.rb
131
132
  - lib/azure_media_service/model/base.rb
133
+ - lib/azure_media_service/model/content_key.rb
134
+ - lib/azure_media_service/model/content_key_authorization_policy.rb
135
+ - lib/azure_media_service/model/content_key_authorization_policy_option.rb
132
136
  - lib/azure_media_service/model/job.rb
133
137
  - lib/azure_media_service/model/locator.rb
134
138
  - lib/azure_media_service/model/media_processor.rb
@@ -157,7 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
157
161
  version: '0'
158
162
  requirements: []
159
163
  rubyforge_project:
160
- rubygems_version: 2.2.2
164
+ rubygems_version: 2.4.5
161
165
  signing_key:
162
166
  specification_version: 4
163
167
  summary: Azure Media Service SDK for ruby