diff --git a/README.rdoc b/README.rdoc
index 837e4c1..7b16781 100644
--- a/README.rdoc
+++ b/README.rdoc
@@ -2,7 +2,7 @@
A Ruby gem for accessing the blip.tv API (http://wiki.blip.tv/index.php/REST_Upload_API)
-== Install
+== Install
gem sources -a http://gems.github.com
sudo gem install kellysutton-bliptv
@@ -15,12 +15,12 @@ While the blip.tv API is extremely simple to use, sometimes it's nice to have a
library to make life even easier. The BlipTV Ruby gem is just that.
Let's say you want to upload a video:
-
+
require 'rubygems'
require 'bliptv'
-
+
client = BlipTV::Base.new
-
+
options = {
:username => "barack_obama",
:password => "michellexoxo",
@@ -28,9 +28,9 @@ Let's say you want to upload a video:
:title => "Ordering Hamburgers in DC",
:description => "I love this one burger joint, but the press keeps following me."
}
-
+
video = client.upload_video(options) #=> BlipTV::Video
-
+
The upload_video method call returns a BlipTV::Video object
that you can play around with.
@@ -40,13 +40,13 @@ Or what if you wanted a list of all videos by a user? Also easy:
require 'bliptv'
client = BlipTV::Base.new
-
- video_list = client.find_all_videos_by_user("barack_obama")
-
+
+ video_list = client.find_all_videos_by_user("barack_obama")
+
find_all_videos_by_user will return a list of BlipTV::Video objects.
More usage coming soon.
-
+
== Authors
Kelly Sutton (http://michaelkellysutton.com)
@@ -54,15 +54,15 @@ Kelly Sutton (http://michaelkellysutton.com)
== Features
Provides an easy way to interact with the blip.tv API in Ruby.
-
+
== Special Thanks
This gem is extensively based on Shane Vitrana's Viddler
gem as well as the YouTubeG gem. Much of the code was simply
copied and then tweaked to fit the blip.tv nomenclature
-of certain calls.
+of certain calls.
-== License
+== License
Copyright (c) 2009 Michael Kelly Sutton
diff --git a/lib/bliptv.rb b/lib/bliptv.rb
index 122e446..82f9289 100644
--- a/lib/bliptv.rb
+++ b/lib/bliptv.rb
@@ -1,6 +1,6 @@
#
# This is the main entry point for the library. All files in the project are
-# included here, as well as anything required across the project.
+# included here, as well as anything required across the project.
#
$:.unshift(File.dirname(__FILE__)) unless
diff --git a/lib/bliptv/api_spec.rb b/lib/bliptv/api_spec.rb
index 4ba075b..c654677 100644
--- a/lib/bliptv/api_spec.rb
+++ b/lib/bliptv/api_spec.rb
@@ -6,7 +6,7 @@ class ApiSpec
:file,
:userlogin,
:password
- ],
+ ],
:optional => [
:thumbnail,
:nsfw,
@@ -17,7 +17,7 @@ class ApiSpec
:interactive_post
]
}
-
+
VIDEOS_DELETE_ATTRS = {
:required => [
:userlogin,
@@ -27,24 +27,24 @@ class ApiSpec
:username # kind of sloppy, because a user is unlikely to specify both a userlogin AND a username
]
}
-
+
def self.check_attributes(bliptv_method, attributes)
valid_attributes = bliptv_method_to_const(bliptv_method)
required = valid_attributes[:required] || Array.new
optional = valid_attributes[:optional] || Array.new
-
+
# blip calls it a "userlogin" instead of a "username"
- if attributes[:username] != nil
+ if attributes[:username] != nil
attributes[:userlogin] = attributes[:username]
attributes.delete(:username)
end
-
+
attributes.assert_valid_keys(required + optional)
attributes.assert_required_keys(required)
end
-
+
protected
-
+
def self.bliptv_method_to_const(method)
const_name = method.gsub('.', '_').upcase
const_get("#{const_name}_ATTRS")
diff --git a/lib/bliptv/base.rb b/lib/bliptv/base.rb
index e7bfd1f..80eaa3b 100644
--- a/lib/bliptv/base.rb
+++ b/lib/bliptv/base.rb
@@ -16,17 +16,17 @@ def message
'This method is not yet implemented.'
end
end
-
+
#
# This is the class that should be instantiated for basic
# communication with the Blip.tv API
#
class Base
-
+
# TODO allow user to specify userlogin and password on intialize
def initialize
end
-
+
# Implements the Blip.tv REST Upload API
#
# new_attributes hash should contain next required keys:
@@ -48,18 +48,18 @@ def initialize
#
# bliptv.upload_video(:title => 'Check out this guy getting kicked in the nuts!', :file => File.open('/movies/nuts.mov'))
#
- # Returns BlipTV::Video instance.
+ # Returns BlipTV::Video instance.
#
def upload_video(new_attributes={})
BlipTV::ApiSpec.check_attributes('videos.upload', new_attributes)
-
+
new_attributes = {
:post => "1",
:item_type => "file",
:skin => "xmlhttprequest",
:file_role => "Web"
}.merge(new_attributes) # blip.tv requires the "post" param to be set to 1
-
+
request = BlipTV::Request.new(:post, 'videos.upload')
request.run do |p|
for param, value in new_attributes
@@ -69,8 +69,8 @@ def upload_video(new_attributes={})
BlipTV::Video.new(request.response['post_url'].to_s)
end
-
-
+
+
# Looks up all videos on Blip.tv with a given username
#
# Options hash could contain next values:
@@ -92,8 +92,8 @@ def find_all_videos_by_user(username, options={})
hash = Hash.from_xml(request)
hash == nil ? [] : parse_videos_list(hash)
end
-
-
+
+
# Searches through and returns videos based on the search_string.
#
# This method is a direct call of Blip.tv's search method. You get what you get. No guarantees are made.
@@ -109,13 +109,13 @@ def search_videos(search_string)
hash = Hash.from_xml(request)
parse_videos_list(hash)
end
-
+
private
-
+
def parse_videos_list(hash)
list = []
begin
- hash["response"]["payload"]["asset"].each do |entry|
+ hash["response"]["payload"]["asset"].each do |entry|
list << Video.new(entry)
end
rescue NoMethodError
diff --git a/lib/bliptv/multipart_params.rb b/lib/bliptv/multipart_params.rb
index 444e091..9b930bc 100644
--- a/lib/bliptv/multipart_params.rb
+++ b/lib/bliptv/multipart_params.rb
@@ -2,27 +2,27 @@
class MultipartParams #:nodoc:
attr_accessor :content_type, :body
-
+
def initialize(param_hash={})
- @boundary_token = generate_boundary_token
- self.content_type = "multipart/form-data; boundary=#{@boundary_token}"
- self.body = pack_params(param_hash)
+ @boundary_token = generate_boundary_token
+ self.content_type = "multipart/form-data; boundary=#{@boundary_token}"
+ self.body = pack_params(param_hash)
end
protected
-
+
def generate_boundary_token
[Array.new(8) {rand(256)}].join
end
-
+
def pack_params(hash)
marker = "--#{@boundary_token}\r\n"
files_params = hash.find_all{|k,v| v.is_a?(File)}.to_h
text_params = hash - files_params
-
+
pack_hash(text_params, marker) + marker + pack_hash(files_params, marker) + "--#{@boundary_token}--\r\n"
end
-
+
def pack_hash(hash, marker)
hash.map do |name, value|
marker + case value
@@ -33,7 +33,7 @@ def pack_hash(hash, marker)
end
end.join('')
end
-
+
def file_to_multipart(key,file)
filename = File.basename(file.path)
mime_types = MIME::Types.of(filename)
diff --git a/lib/bliptv/request.rb b/lib/bliptv/request.rb
index 7347702..abf3d23 100644
--- a/lib/bliptv/request.rb
+++ b/lib/bliptv/request.rb
@@ -1,34 +1,34 @@
require 'rest_client'
module BlipTV
-
+
# Raised when response from Blip.tv contains absolutely no data
class EmptyResponseError < BlipTVError #:nodoc:
end
-
+
# Raised when response from Blip.tv contains an error
class ResponseError < BlipTVError #:nodoc:
def initialize(message)
super message
end
end
-
+
# Class used to send requests over http to Viddler API.
class Request #:nodoc:
-
+
API_URL = 'http://uploads.blip.tv/'
DEFAULT_HEADERS = {:accept => 'application/xml', :content_type => 'multi-part/form-data'}
-
+
attr_accessor :url, :http_method, :response, :body
attr_reader :headers, :params
-
+
def initialize(http_method, method) #:nodoc:
@http_method = http_method.to_s
@url = API_URL
- self.params = {} #{:method => viddlerize(method)}
+ self.params = {} #{:method => viddlerize(method)}
self.headers = DEFAULT_HEADERS
end
-
+
# Use this method to setup your request's payload and headers.
#
# Example:
@@ -41,13 +41,13 @@ def initialize(http_method, method) #:nodoc:
# p.sessionid = '12323'
# p.api_key = '13123
# end
- #
+ #
def set(container, &declarations)
struct = OpenStruct.new
declarations.call(struct)
send("#{container}=", struct.table)
end
-
+
# Send http request to Viddler API.
def run(&block)
if block_given?
@@ -58,19 +58,19 @@ def run(&block)
put_multipart_params_into_body
else
put_params_into_url
- end
-
+ end
+
request = RestClient::Request.execute(
- :method => http_method,
- :url => url,
- :headers => headers,
+ :method => http_method,
+ :url => url,
+ :headers => headers,
:payload => body
)
self.response = parse_response(request)
end
-
+
private
-
+
def parse_response(raw_response)
raise EmptyResponseError if raw_response.blank?
response_hash = Hash.from_xml(raw_response)
@@ -83,17 +83,17 @@ def parse_response(raw_response)
response_hash["post_url"] = raw_response.match(/\d{3,12}/)[0] # extracts the post_url, since from_xml isn't grabbing it
response_hash
end
-
+
def put_multipart_params_into_body
multiparams = MultipartParams.new(params)
self.body = multiparams.body
self.headers = {:content_type => multiparams.content_type}
end
-
+
def put_params_into_url
self.url = API_URL + '?' + params.to_query
end
-
+
def viddlerize(name)
if name.include?('viddler.')
name
@@ -101,35 +101,35 @@ def viddlerize(name)
'viddler.' + name
end
end
-
+
def params=(hash) #:nodoc:
@params ||= Hash.new
@params.update(hash)
end
-
+
def headers=(hash) #:nodoc:
@headers ||= Hash.new
@headers.update(hash)
end
-
+
def multipart? #:nodoc:
# TOOD let's be nice and do a File.exists?(v)
if params.find{|k,v| v.is_a?(File)} then true else false end
end
-
+
def post? #:nodoc:
http_method == 'post'
end
-
+
def bliptv_error_message(response_error)
description = response_error['description'] || ''
- details = response_error['details'] || ''
+ details = response_error['details'] || ''
code = response_error['code'] || ''
-
+
details = ": #{details};" unless details.empty?
code = " [code: #{code}]" unless code.empty?
%Q[#{description}#{details}#{code}]
end
-
+
end
end
\ No newline at end of file
diff --git a/lib/bliptv/video.rb b/lib/bliptv/video.rb
index 5c86ceb..c231b2d 100644
--- a/lib/bliptv/video.rb
+++ b/lib/bliptv/video.rb
@@ -4,23 +4,23 @@
module BlipTV
BLIP_TV_ID_EXPR = /\d{3,12}/
-
+
# Raised when pinging Blip.tv for video information results in an error
class VideoResponseError < BlipTVError #:nodoc:
def initialize(message)
super message
end
end
-
+
class VideoDeleteError < BlipTVError
def intialize(message)
super message
end
end
-
+
# This class wraps Blip.tv's video's information.
class Video
-
+
attr_accessor :id,
:title,
:description,
@@ -36,26 +36,26 @@ class Video
:license,
:embed_url,
:embed_code
-
+
def initialize(blip_id) #:nodoc:
blip_id = blip_id.to_s if blip_id.class == Fixnum
-
+
if blip_id.class == String && blip_id.match(BLIP_TV_ID_EXPR)
update_attributes_from_id(blip_id)
elsif blip_id.class == Hash
update_attributes_from_hash(blip_id)
end
end
-
+
def update_attributes_from_id(blip_id)
@id = blip_id
-
+
a = get_attributes
update_attributes_from_hash(a)
end
-
+
def update_attributes_from_hash(a)
-
+
@id = a['item_id'] if @id == nil
@title = a['title']
@description = a['description']
@@ -73,33 +73,33 @@ def update_attributes_from_hash(a)
@embed_url = a['embed_url']
@embed_code = a['embed_code']
end
-
+
#
# fire off a HTTP GET response to Blip.tv
#
- # In the future, this should probably be rolled into the
- # BlipTV::Request class, so that all exception raising and
+ # In the future, this should probably be rolled into the
+ # BlipTV::Request class, so that all exception raising and
# network communication exists in instances of that class.
#
- def get_attributes
- url = URI.parse('http://www.blip.tv/')
- res = Net::HTTP.start(url.host, url.port) {|http|
+ def get_attributes
+ url = URI.parse('http://www.blip.tv/')
+ res = Net::HTTP.start(url.host, url.port) {|http|
http.get("http://www.blip.tv/file/#{@id.to_s}?skin=api")
- }
-
+ }
+
hash = Hash.from_xml(res.body)
-
+
if hash["response"]["status"] != "OK"
raise VideoResponseError.new(hash["response"]["notice"])
end
-
- if hash["response"]["payload"]["asset"].is_a?(Array)
+
+ if hash["response"]["payload"]["asset"].is_a?(Array)
return hash["response"]["payload"]["asset"][0] # there may be several assets. In that case, read the first one
else
return hash["response"]["payload"]["asset"]
end
end
-
+
#
# Refresh the current video object. Useful to check up on encoding progress,
# etc.
@@ -107,27 +107,27 @@ def get_attributes
def refresh
update_attributes_from_id(@id)
end
-
+
#
# delete! will delete the file from Blip.tv
#
def delete!(creds = {}, section = "file", reason = "because")
BlipTV::ApiSpec.check_attributes('videos.delete', creds)
-
+
reason = reason.gsub(" ", "%20") # TODO write a method to handle this and other illegalities of URL
-
+
if creds[:username] && !creds[:userlogin]
creds[:userlogin] = creds[:username]
end
-
+
url, path = "www.blip.tv", "/?userlogin=#{creds[:userlogin]}&password=#{creds[:password]}&cmd=delete&s=file&id=#{@id}&reason=#{reason}&skin=api"
request = Net::HTTP.get(url, path)
hash = Hash.from_xml(request)
make_sure_video_was_deleted(hash)
end
-
+
private
-
+
#
# Makes sense out of Blip.tv's strucutre of the tag element
#
@@ -137,14 +137,14 @@ def parse_tags(element)
if element.class == Hash && element['string']
if element['string'].class == Array
return element['string'].join(", ")
- elsif element['string'].class == String
+ elsif element['string'].class == String
return element['string']
end
else
return ""
end
end
-
+
#
# make_sure_video_was_deleted analyzes the response hash
# to make sure it was a success
@@ -155,7 +155,7 @@ def make_sure_video_was_deleted(hash)
# TODO have a special case for authentication required?
if hash["response"]["status"] != "OK"
begin
- raise VideoDeleteError.new("#{hash['response']['error']['code']}: #{hash['response']['error']['message']} ")
+ raise VideoDeleteError.new("#{hash['response']['error']['code']}: #{hash['response']['error']['message']} ")
rescue NoMethodError # TODO irony!
raise VideoDeleteError.new(hash.to_yaml)
end
diff --git a/lib/ext/array.rb b/lib/ext/array.rb
index 4a35e5e..2878ce9 100644
--- a/lib/ext/array.rb
+++ b/lib/ext/array.rb
@@ -1,5 +1,5 @@
class Array #:nodoc:
-
+
# Extraceted from Ruby Facets:
# Converts a two-element associative array into a hash.
def to_h(arrayed=nil)
diff --git a/lib/ext/hash.rb b/lib/ext/hash.rb
index 1833338..e24ea5b 100644
--- a/lib/ext/hash.rb
+++ b/lib/ext/hash.rb
@@ -1,12 +1,12 @@
class Hash #:nodoc:
-
+
def assert_required_keys(keys)
for key in keys
raise(ArgumentError, "Missing required key(s): #{key}") unless self.keys.include?(key)
end
true
end
-
+
# Extracted from Ruby Facets:
# Operator for remove hash paris. If another hash is given the pairs are only removed if both key and value are equal. If an array is given then matching keys are removed.
def -(other)
@@ -24,5 +24,5 @@ def -(other)
end
h
end
-
+
end
\ No newline at end of file
diff --git a/lib/ext/open_struct.rb b/lib/ext/open_struct.rb
index 0ba52f6..c0d5ef6 100644
--- a/lib/ext/open_struct.rb
+++ b/lib/ext/open_struct.rb
@@ -1,7 +1,7 @@
class OpenStruct #:nodoc:
-
+
def table
@table
end
-
+
end
\ No newline at end of file
diff --git a/test/test_base.rb b/test/test_base.rb
index ffa2929..bbc0ae6 100644
--- a/test/test_base.rb
+++ b/test/test_base.rb
@@ -4,18 +4,18 @@ class TC_BaseTest < Test::Unit::TestCase
def setup
@base = BlipTV::Base.new
end
-
+
def teardown
end
-
+
def test_find_all_videos_by_user
-
+
videos = @base.find_all_videos_by_user("onemonthhere")
-
+
assert_not_equal nil, videos
assert_instance_of Array, videos
assert videos.size >= 12 # at the time of the writing of the test
-
+
videos.each do |video|
assert_not_equal "", video.title # all videos must have a title
assert_equal "onemonthhere", video.author
@@ -24,19 +24,19 @@ def test_find_all_videos_by_user
end
def test_find_all_videos_by_user_retrieve_100
-
+
videos = @base.find_all_videos_by_user("verycocinar", {:page => 1, :pagelen => 100})
-
+
assert_not_equal nil, videos
assert_instance_of Array, videos
- assert videos.size == 100
+ assert videos.size == 100
end
def test_find_all_videos_by_user_more_than_one_page
-
+
videos_1 = @base.find_all_videos_by_user("verycocinar", {:page => 2, :pagelen => 30})
videos_2 = @base.find_all_videos_by_user("verycocinar", {:page => 3, :pagelen => 30})
-
+
assert_instance_of Array, videos_1
assert_instance_of Array, videos_2
assert videos_1.size == 30
@@ -46,11 +46,11 @@ def test_find_all_videos_by_user_more_than_one_page
def test_search_videos
videos = @base.search_videos("cool")
-
+
assert_not_equal nil, videos # unless Blip.tv is having a bad day :(
assert_instance_of Array, videos
assert videos.size > 10 # assumption
-
+
videos.each do |video|
assert_not_equal "", video.title # all videos must have a title
end
diff --git a/test/test_video.rb b/test/test_video.rb
index 8d33bb2..39fb26d 100644
--- a/test/test_video.rb
+++ b/test/test_video.rb
@@ -5,31 +5,31 @@
class TC_VideoTest < Test::Unit::TestCase
def setup
end
-
+
def teardown
end
-
+
def test_video_initialize_with_int_and_string
video1 = BlipTV::Video.new(2193230)
video2 = BlipTV::Video.new("2193230")
-
+
a = [video1, video2]
-
+
a.each do |video|
assert_not_equal nil, video
assert_instance_of BlipTV::Video, video
-
-
+
+
assert_equal "Super Mario Galaxy 2", video.title
-
+
h = { "mode" => "escaped", "type" => "text/html" }
assert_equal h, video.description
-
- assert_equal "D2215402-5017-11DE-9B2F-C1BCBB520399", video.guid
- assert_equal "false", video.deleted
+
+ assert_equal "D2215402-5017-11DE-9B2F-C1BCBB520399", video.guid
+ assert_equal "false", video.deleted
assert_equal nil, video.view_count # because we don't have the user login info
assert_equal "", video.tags
-
+
links = [{"href"=>"http://blip.tv/file/2193230",
"rel"=>"alternate",
"type"=>"text/html"},
@@ -48,34 +48,34 @@ def test_video_initialize_with_int_and_string
{"href"=>"http://blip.tv/file/post/2193230/?skin=api",
"rel"=>"service.edit",
"type"=>"text/xml"}]
-
- assert_equal links, video.links
- assert_equal "kotaku", video.author
+
+ assert_equal links, video.links
+ assert_equal "kotaku", video.author
assert_equal "Thu Jan 01 01:00:00 +0100 1970", video.update_time.to_s # not sure why this is the epoch
- assert_equal "false", video.explicit
-
+ assert_equal "false", video.explicit
+
license = {"name"=>"No license (All rights reserved)"}
assert_equal license, video.license
-
+
notes = {"mode"=>"escaped", "type"=>"text/html"}
- assert_equal notes, video.notes
-
+ assert_equal notes, video.notes
+
assert_equal "http://blip.tv/play/g4Q9gYbEEY35ZA", video.embed_url
assert_equal "", video.embed_code
end
end
-
+
def test_video_with_more_data
video = BlipTV::Video.new(2141730)
-
+
assert_match /\d{3,12}/, video.id
- assert_equal "Field Recon - One Month Here - Episode 9", video.title
- assert_equal "I spend most of today out in the field, scoping out challenge locations. Berghain looks eerie and deserted. It's likely the exact opposite at night. I need some swimming trunks...
Tweets read today from @iMuesli , @andrewseely , @JDFirst , @grasp183 and @mxchickmagnet86
Thanks for watching!", video.description
- assert_equal "DB14423E-460F-11DE-B85A-FF0EAE6B9387", video.guid
- assert_equal "false", video.deleted
- assert_equal nil, video.view_count
- assert_equal "bergain, badeschiff, kelly sutton, berlin, germany, kreuzberg", video.tags
-
+ assert_equal "Field Recon - One Month Here - Episode 9", video.title
+ assert_equal "I spend most of today out in the field, scoping out challenge locations. Berghain looks eerie and deserted. It's likely the exact opposite at night. I need some swimming trunks...
Tweets read today from @iMuesli , @andrewseely , @JDFirst , @grasp183 and @mxchickmagnet86
Thanks for watching!", video.description
+ assert_equal "DB14423E-460F-11DE-B85A-FF0EAE6B9387", video.guid
+ assert_equal "false", video.deleted
+ assert_equal nil, video.view_count
+ assert_equal "bergain, badeschiff, kelly sutton, berlin, germany, kreuzberg", video.tags
+
links = [{"href"=>"http://blip.tv/file/2141730",
"rel"=>"alternate",
"type"=>"text/html"},
@@ -94,25 +94,25 @@ def test_video_with_more_data
{"href"=>"http://blip.tv/file/post/2141730/?skin=api",
"rel"=>"service.edit",
"type"=>"text/xml"}]
- assert_equal links, video.links
- assert_equal "onemonthhere", video.author
+ assert_equal links, video.links
+ assert_equal "onemonthhere", video.author
assert_equal 0, video.update_time.to_i
assert_equal "false", video.explicit
-
+
licensce = {"name"=>"Creative Commons Attribution 3.0",
"link"=>
{"href"=>"http://creativecommons.org/licenses/by/3.0/", "type"=>"text/html"}}
- assert_equal licensce, video.license
-
- notes = {"mode"=>"escaped", "type"=>"text/html"}
- assert_equal notes, video.notes
- assert_equal "http://blip.tv/play/AYGDsCSV5jE", video.embed_url
+ assert_equal licensce, video.license
+
+ notes = {"mode"=>"escaped", "type"=>"text/html"}
+ assert_equal notes, video.notes
+ assert_equal "http://blip.tv/play/AYGDsCSV5jE", video.embed_url
assert_equal "", video.embed_code
end
-
+
def test_video_delete
base = BlipTV::Base.new
-
+
options = {
:userlogin => "bliptv_ruby_gem",
:password => "thisissosecret",
@@ -122,12 +122,12 @@ def test_video_delete
}
video = base.upload_video(options) #=> BlipTV::Video
-
+
options = {
:userlogin => "bliptv_ruby_gem",
:password => "thisissosecret"
}
-
+
video.delete!(options)
end
end
\ No newline at end of file