module Vzaar # You can use Vzaar::Base class for accessing and managing your resources on vzaar. class Base # When creating a Vzaar::Base instance you can (but don't have to) specify # login and application_token. However if you don't specify them you # won't be able to perform authenticated calls. # # You can also specify server different from live server, e.g. sandbox.vzaar.com, # if you're just doing testing. Additionally you can pass your logger as the # :logger option. By default the log/debug info is written to the standard output. # # The options can be read from environment variables. Just set VZAAR_LOGIN, # VZAAR_APPLICATION_TOKEN and/or VZAAR_SERVER and you don't have to worry about # passing the options to the initializer. # # Usage: # * vzaar = Vzaar::Base.new # * vzaar = Vzaar::Base.new :login => 'your_vzaar_login', :application_token => 'your_very_long_application_token' # * vzaar = Vzaar::Base.new :login => 'your_vzaar_login', :application_token => 'your_app_token', :server => 'sandbox.vzaar.com' # * vzaar = Vzaar::Base.new :server => 'sandbox.vzaar.com', :logger => your_logger # * vzaar = Vzaar::Base.new :logger => your_logger def initialize(options= {}) login = options[:login] || ENV['VZAAR_LOGIN'] || '' application_token = options[:application_token] || ENV['VZAAR_APPLICATION_TOKEN'] || '' server = options[:server] || ENV['VZAAR_SERVER'] || VZAAR_LIVE_SERVER @logger = options[:logger] || Logger.new(STDOUT) server.gsub! 'http://', '' server.gsub! 'https://', '' consumer = OAuth::Consumer.new '', '', { :site => "http://#{server}" } @public_connection = OAuth::AccessToken.new consumer, '', '' consumer = OAuth::Consumer.new '', '', { :site => "https://#{server}" } if login.length > 0 and application_token.length > 0 @auth_connection = OAuth::AccessToken.new consumer, login, application_token else # Authenticated requests won't be possible @auth_connection = nil log_info "Authenticated calls won't be possible" end end # Test method for authentication. Returns a login of an authenticated user. # # Usage: # * my_login = vzaar.whoami def whoami result = nil auth_connection(HTTP_GET, '/api/test/whoami') do |xml| doc = REXML::Document.new xml result = doc.elements['vzaar-api/test/login'].text end result end # Gets the details of an account type. # # Usage: # * account_type = vzaar.account_type 1 # * title = vzaar.account_type(1).title # * bandwidth = vzaar.account_type(1).bandwidth def account_type(account_type_id) result = nil public_connection(HTTP_GET, "/api/accounts/#{account_type_id}.xml") do |xml| result = AccountType.new xml end result end # Gets a user public details. Whitelabel users can retrive their details by # using the method with 'authenticated' option on. # # Usage: # * me = vzaar.user_details 'some_login' (this works only if 'some_login' is not a protected resource) # * me = vzaar.user_details 'your_login', true ('your_login' must be the same as the one provided for Vzaar::Base.new method in order to authorize on server.) # # Note: even if you created an authorized instance of Vzaar::Base class # (by specifying login and application token in Vzaar::Base.new), you # need to set the 'authenticated' param to true in order to perform # authenticated call. def user_details(login, authenticated = false) result = nil if authenticated auth_connection(HTTP_GET, "/api/users/#{login}.xml") do |xml| result = User.new xml end else public_connection(HTTP_GET, "/api/users/#{login}.xml") do |xml| result = User.new xml end end result end # Gets a list of a user's active videos along with it's relevant metadata. # Set 'authenticated' option to true to retrieve private videos. # # Usage: # * videos = vzaar.video_list 'your_login' (gets your public videos) # * videos = vzaar.video_list 'some_other_login' (gets public videos of some_other_login) # * videos = vzaar.video_list 'your_login', true (gets all your videos, provided your_login is the one you provided for Vzaar::Base initializer) # * videos = vzaar.video_list 'some_other_login', true (gets public videos of some_other_login - you cannot access other users' private videos) # # Note: even if you created an authorized instance of Vzaar::Base class # if you don't set the 'authenticated' param to true you will receive # only public videos. def video_list(login, authenticated = false) result = [] response = nil if authenticated response = auth_connection(HTTP_GET, "/api/#{login}/videos.xml") else response = public_connection(HTTP_GET, "/api/#{login}/videos.xml") end if response and response.body doc = REXML::Document.new response.body videos = doc.elements['videos'] videos.elements.each('video') do |video| result << Video.new(video.to_s) end end result end # Gets video details, inlcuding embed code. Use 'authenticated' option to # retrieve details of private video. # # Usage: # * video = vzaar.video_details 1234 (1234 must be a public video) # * video = vzaar.video_details 1234, true (1234 can be a private video but you must the owner) # # Note: even if you create an authorized instance of Vzaar::Base class # if you don't set the 'authenticated' param to true you will not be able # to retrieve data for private video. def video_details(video_id, authenticated = false) result = nil if authenticated auth_connection(HTTP_GET, "/api/videos/#{video_id}.xml") do |xml| result = VideoDetails.new xml end else public_connection(HTTP_GET, "/api/videos/#{video_id}.xml") do |xml| result = VideoDetails.new xml end end result end # Deletes a video from a users account. Use either 'DELETE' or 'POST' method. # You must be the owner of the video in order to authorize on the server. # # Usage: # * vzaar.delete_video 1234 (uses 'DELETE' method) # * vzaar.delete_video 1234, 'POST' def delete_video(video_id, method = HTTP_DELETE) if method == HTTP_DELETE auth_connection method, "/api/videos/#{video_id}.xml" else request_xml = %{ <?xml version="1.0" encoding="UTF-8"?> <vzaar-api> <_method>delete</_method> </vzaar-api> } auth_connection method, "/api/videos/#{video_id}.xml", request_xml end end # Edits a video title and description. Use either 'PUT' or 'POST' method. # # Usage: # * vzaar.edit_video 1234, 'new title', 'new desc' (uses 'PUT' method) # * vzaar.edit_video 1234, 'new title', 'new desc', 'POST' def edit_video(video_id, title, description, method = HTTP_PUT) request_xml = %{ <?xml version="1.0" encoding="UTF-8"?> <vzaar-api> } request_xml += %{<_method>put</_method>} if method != HTTP_PUT request_xml += %{ <video> <title>#{title}</title> <description>#{description}</description > </video> </vzaar-api> } auth_connection HTTP_PUT, "/api/videos/#{video_id}.xml", request_xml end # Provides a signature which is required to upload a video directly to S3 bucket. # Options: # * success_action_redirect - when sending files to S3 you can be redirected to a given url on success. You'll need to specify the url when requesting a signature. Vzaar API server will attach a guid to it and return full url in the response. You'll need to specify the full url later when uploading a video in order to get authorized on S3. # * include_metadata - if you set the param to true, then when uploading a video you can and have to(!) send metadata to S3 along with your video. The names of the metadata must be: 'x-amz-meta-title' and 'x-amz-meta-profile'. None of them can be omitted even if empty. Vzaar doesn't restric the values of the metadata in any way. If include_metadata is false, which is the default behaviour, no metadata can be send to S3. # * flash_request - adds flash specific params to the signature # # Usage: # * vzaar.signature # * vzaar.signature :success_action_redirect => 'http://my.domain.com/using_vzaar' # * vzaar.signature :success_action_redirect => 'http://my.domain.com/using_vzaar', :include_metadata => true # * vzaar.signature :include_metadata => true # * vzaar.signature :flash_request => true def signature(options = {}) signature = nil url = '/api/videos/signature' if options[:success_action_redirect] url += "?success_action_redirect=#{options[:success_action_redirect]}" end if options[:include_metadata] url += url.include?('?') ? '&' : '?' url += "include_metadata=yes" end if options[:flash_request] url += url.include?('?') ? '&' : '?' url += "flash_request=yes" end auth_connection HTTP_GET, url do |xml| signature = Signature.new xml end signature end # Tells vzaar that you have uploaded a video to S3 and now you want to # register it in vzaar. This method is called automatically from within # the upload_video method. # # Usage: # * vzaar.process_video :guid => signature.guid, :title => 'Some title', :description => 'Some description', :profile => 1 def process_video(options = {}) request_xml = %{ <?xml version="1.0" encoding="UTF-8"?> <vzaar-api> <video> <guid>#{options[:guid]}</guid> <title>#{options[:title]}</title> <description>#{options[:description]}</description> <profile>#{options[:profile]}</profile> </video> </vzaar-api> } auth_connection HTTP_POST, '/api/videos', request_xml end # Uploads a video to vzaar. # # Usage: # * vzaar.upload_video '/home/me/video.mp4', 'some title', 'some desc', '1' def upload_video(path, title, description, profile) # Get signature sig = signature @logger.debug "Uploading..." # Upload to S3 res = upload_to_s3 sig.acl, sig.bucket, sig.policy, sig.aws_access_key, sig.signature, sig.key, path if res @logger.debug "Upload complete" # And process in vzaar process_video :guid => sig.guid, :title => title, :description => description, :profile => profile else @logger.debug "Upload to s3 failed" return nil end end private # Performs the public connection def public_connection(method, url, xml = '', &block) res = nil begin case method when "GET" res = @public_connection.get url when "POST" if xml and xml.length > 0 res = @public_connection.post url, xml, { 'Content-Type' => 'application/xml' } else res = @public_connection.post url end when "PUT" if xml and xml.length > 0 res = @public_connection.put url, xml, { 'Content-Type' => 'application/xml' } else res = @public_connection.put url end when "DELETE" if xml and xml.length > 0 res = @public_connection.delete url, xml, { 'Content-Type' => 'application/xml' } else res = @public_connection.delete url end else handle_exception 'unknown_method' end case res.code when HTTP_OK yield res.body if block_given? when HTTP_CREATED yield res.body if block_given? when HTTP_FORBIDDEN handle_exception 'protected_resource' when HTTP_NOT_FOUND handle_exception 'resource_not_found' when HTTP_BAD_GATEWAY handle_exception 'server_not_responding' else handle_exception 'unknown' end rescue Exception => e raise e if e.is_a? VzaarError handle_exception 'unknown', e.message end res end # Performs the authenticated connection def auth_connection(method, url, xml = '', &block) res = nil begin if @auth_connection case method when "GET" res = @auth_connection.get url when "POST" if xml and xml.length > 0 res = @auth_connection.post url, xml, { 'Content-Type' => 'application/xml' } else res = @auth_connection.post url end when "PUT" if xml and xml.length > 0 res = @auth_connection.put url, xml, { 'Content-Type' => 'application/xml' } else res = @auth_connection.put url end when "DELETE" if xml and xml.length > 0 res = @auth_connection.delete url, xml, { 'Content-Type' => 'application/xml' } else res = @auth_connection.delete url end else unknown_method end case res.code when HTTP_OK yield res.body if block_given? when HTTP_CREATED yield res.body if block_given? when HTTP_BAD_GATEWAY handle_exception 'server_not_responding' else handle_exception 'not_authorized' end else handle_exception 'authorization_info_not_provided' end rescue Exception => e raise e if e.is_a? VzaarError handle_exception 'unknown', e.message end res end def upload_to_s3(acl, bucket, policy, aws_access_key, signature, key, file_path) client = HTTPClient.new client.send_timeout = 1800 url = "https://#{bucket}.s3.amazonaws.com/" begin file = File.open file_path res = client.post url, [ ['acl', acl], ['bucket', bucket], ['success_action_status', '201'], ['policy', policy], ['AWSAccessKeyId', aws_access_key], ['signature', signature], ['key', key], ['file', file] ] rescue Exception => e file.close if file handle_exception 'unknown', e.message end file.close if file if res.status_code == 201 return true else return false end end def upload_to_s3_curl(acl, bucket, policy, aws_access_key, signature, key, file_path) require 'curb' acl_field = Curl::PostField.content 'acl', acl bucket_field = Curl::PostField.content 'bucket', bucket success_action_status_field = Curl::PostField.content 'success_action_status', '201' policy_field = Curl::PostField.content 'policy', policy aws_access_key_field = Curl::PostField.content 'AWSAccessKeyId', aws_access_key signature_field = Curl::PostField.content 'signature', signature key_field = Curl::PostField.content 'key', key file_field = Curl::PostField.file 'file', file_path curl = Curl::Easy.new "https://#{bucket}.s3.amazonaws.com/" curl.multipart_form_post = true begin curl.http_post acl_field, bucket_field, success_action_status_field, policy_field, aws_access_key_field, signature_field, key_field, file_field rescue Exception => e handle_exception 'unknown', e.message end if curl.response_code == 201 return true else return false end end def log_info(message) @logger.info message end def handle_exception(type, message = '') case type when 'not_authorized': message = "You have not been authorized on the server. " + "Please check your login and application token." when 'authorization_info_not_provided': message = 'You need to provide login and application token to perform ' + 'to perform this action.' when 'server_not_responding': message = "The server you're trying to connect to is not responding." when 'protected_resource': message = "The resource is protected and you have not been authorized " + "to access it." when 'resource_not_found': message = "The resource has not been found on the server." when 'unknown_method': message = "The method used for connecting is not a proper HTTP method." else message = "Unknown error occured when accessing the server: " + message end @logger.error message raise VzaarError.new message end end end