bliptv 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/License.txt +20 -0
- data/Manifest +16 -0
- data/README.rdoc +86 -0
- data/Rakefile +14 -0
- data/bliptv.gemspec +32 -0
- data/lib/bliptv.rb +27 -0
- data/lib/bliptv/api_spec.rb +53 -0
- data/lib/bliptv/base.rb +127 -0
- data/lib/bliptv/multipart_params.rb +49 -0
- data/lib/bliptv/request.rb +135 -0
- data/lib/bliptv/video.rb +165 -0
- data/lib/ext/array.rb +18 -0
- data/lib/ext/hash.rb +28 -0
- data/lib/ext/open_struct.rb +7 -0
- data/test/test_base.rb +58 -0
- data/test/test_suite.rb +16 -0
- data/test/test_video.rb +133 -0
- metadata +87 -0
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Michael Kelly Sutton
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
lib/bliptv/api_spec.rb
|
2
|
+
lib/bliptv/base.rb
|
3
|
+
lib/bliptv/multipart_params.rb
|
4
|
+
lib/bliptv/request.rb
|
5
|
+
lib/bliptv/video.rb
|
6
|
+
lib/bliptv.rb
|
7
|
+
lib/ext/array.rb
|
8
|
+
lib/ext/hash.rb
|
9
|
+
lib/ext/open_struct.rb
|
10
|
+
License.txt
|
11
|
+
Manifest
|
12
|
+
Rakefile
|
13
|
+
README.rdoc
|
14
|
+
test/test_base.rb
|
15
|
+
test/test_suite.rb
|
16
|
+
test/test_video.rb
|
data/README.rdoc
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
= Blip.tv Ruby Library
|
2
|
+
|
3
|
+
A Ruby gem for accessing the blip.tv API (http://wiki.blip.tv/index.php/REST_Upload_API)
|
4
|
+
|
5
|
+
== Install
|
6
|
+
|
7
|
+
gem sources -a http://gems.github.com
|
8
|
+
sudo gem install kellysutton-bliptv
|
9
|
+
sudo gem install rest-client
|
10
|
+
sudo gem install mime-types
|
11
|
+
|
12
|
+
== Usage
|
13
|
+
|
14
|
+
While the blip.tv API is extremely simple to use, sometimes it's nice to have a wrapper
|
15
|
+
library to make life even easier. The BlipTV Ruby gem is just that.
|
16
|
+
|
17
|
+
Let's say you want to upload a video:
|
18
|
+
|
19
|
+
require 'rubygems'
|
20
|
+
require 'bliptv'
|
21
|
+
|
22
|
+
client = BlipTV::Base.new
|
23
|
+
|
24
|
+
options = {
|
25
|
+
:username => "barack_obama",
|
26
|
+
:password => "michellexoxo",
|
27
|
+
:file => File.open('movie.mov'),
|
28
|
+
:title => "Ordering Hamburgers in DC",
|
29
|
+
:description => "I love this one burger joint, but the press keeps following me."
|
30
|
+
}
|
31
|
+
|
32
|
+
video = client.upload_video(options) #=> BlipTV::Video
|
33
|
+
|
34
|
+
The upload_video method call returns a BlipTV::Video object
|
35
|
+
that you can play around with.
|
36
|
+
|
37
|
+
Or what if you wanted a list of all videos by a user? Also easy:
|
38
|
+
|
39
|
+
require 'rubygems'
|
40
|
+
require 'bliptv'
|
41
|
+
|
42
|
+
client = BlipTV::Base.new
|
43
|
+
|
44
|
+
video_list = client.find_all_videos_by_user("barack_obama")
|
45
|
+
|
46
|
+
find_all_videos_by_user will return a list of BlipTV::Video objects.
|
47
|
+
|
48
|
+
More usage coming soon.
|
49
|
+
|
50
|
+
== Authors
|
51
|
+
|
52
|
+
Kelly Sutton (http://michaelkellysutton.com)
|
53
|
+
|
54
|
+
== Features
|
55
|
+
|
56
|
+
Provides an easy way to interact with the blip.tv API in Ruby.
|
57
|
+
|
58
|
+
== Special Thanks
|
59
|
+
|
60
|
+
This gem is extensively based on Shane Vitrana's Viddler
|
61
|
+
gem as well as the YouTubeG gem. Much of the code was simply
|
62
|
+
copied and then tweaked to fit the blip.tv nomenclature
|
63
|
+
of certain calls.
|
64
|
+
|
65
|
+
== License
|
66
|
+
|
67
|
+
Copyright (c) 2009 Michael Kelly Sutton
|
68
|
+
|
69
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
70
|
+
a copy of this software and associated documentation files (the
|
71
|
+
"Software"), to deal in the Software without restriction, including
|
72
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
73
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
74
|
+
permit persons to whom the Software is furnished to do so, subject to
|
75
|
+
the following conditions:
|
76
|
+
|
77
|
+
The above copyright notice and this permission notice shall be
|
78
|
+
included in all copies or substantial portions of the Software.
|
79
|
+
|
80
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
81
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
82
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
83
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
84
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
85
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
86
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'echoe'
|
4
|
+
|
5
|
+
Echoe.new('bliptv', '0.1.1') do |p|
|
6
|
+
p.description = "A Ruby library from Blip.tv"
|
7
|
+
p.url = "http://github.com/kellysutton/bliptv"
|
8
|
+
p.author = "Michael Kelly Sutton"
|
9
|
+
p.email = "michael.k.sutton@gmail.com"
|
10
|
+
p.ignore_pattern = ["tmp/*", "script/*"]
|
11
|
+
p.development_dependencies = []
|
12
|
+
end
|
13
|
+
|
14
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
|
data/bliptv.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{bliptv}
|
5
|
+
s.version = "0.1.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Michael Kelly Sutton"]
|
9
|
+
s.date = %q{2009-06-05}
|
10
|
+
s.description = %q{A Ruby library from Blip.tv}
|
11
|
+
s.email = %q{michael.k.sutton@gmail.com}
|
12
|
+
s.extra_rdoc_files = ["lib/bliptv/api_spec.rb", "lib/bliptv/base.rb", "lib/bliptv/multipart_params.rb", "lib/bliptv/request.rb", "lib/bliptv/video.rb", "lib/bliptv.rb", "lib/ext/array.rb", "lib/ext/hash.rb", "lib/ext/open_struct.rb", "README.rdoc"]
|
13
|
+
s.files = ["lib/bliptv/api_spec.rb", "lib/bliptv/base.rb", "lib/bliptv/multipart_params.rb", "lib/bliptv/request.rb", "lib/bliptv/video.rb", "lib/bliptv.rb", "lib/ext/array.rb", "lib/ext/hash.rb", "lib/ext/open_struct.rb", "License.txt", "Manifest", "Rakefile", "README.rdoc", "test/test_base.rb", "test/test_suite.rb", "test/test_video.rb", "bliptv.gemspec"]
|
14
|
+
s.has_rdoc = true
|
15
|
+
s.homepage = %q{http://github.com/kellysutton/bliptv}
|
16
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Bliptv", "--main", "README.rdoc"]
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.rubyforge_project = %q{bliptv}
|
19
|
+
s.rubygems_version = %q{1.3.2}
|
20
|
+
s.summary = %q{A Ruby library from Blip.tv}
|
21
|
+
s.test_files = ["test/test_base.rb", "test/test_suite.rb", "test/test_video.rb"]
|
22
|
+
|
23
|
+
if s.respond_to? :specification_version then
|
24
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
25
|
+
s.specification_version = 3
|
26
|
+
|
27
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
28
|
+
else
|
29
|
+
end
|
30
|
+
else
|
31
|
+
end
|
32
|
+
end
|
data/lib/bliptv.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#
|
2
|
+
# This is the main entry point for the library. All files in the project are
|
3
|
+
# included here, as well as anything required across the project.
|
4
|
+
#
|
5
|
+
|
6
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
7
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'active_support'
|
11
|
+
require 'ostruct'
|
12
|
+
require 'net/http'
|
13
|
+
require 'uri'
|
14
|
+
|
15
|
+
require 'ext/array'
|
16
|
+
require 'ext/hash'
|
17
|
+
require 'ext/open_struct'
|
18
|
+
|
19
|
+
require 'bliptv/base'
|
20
|
+
require 'bliptv/video'
|
21
|
+
require 'bliptv/api_spec'
|
22
|
+
require 'bliptv/multipart_params'
|
23
|
+
require 'bliptv/request'
|
24
|
+
|
25
|
+
|
26
|
+
module BlipTV
|
27
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module BlipTV
|
2
|
+
class ApiSpec
|
3
|
+
VIDEOS_UPLOAD_ATTRS = {
|
4
|
+
:required => [
|
5
|
+
:title,
|
6
|
+
:file,
|
7
|
+
:userlogin,
|
8
|
+
:password
|
9
|
+
],
|
10
|
+
:optional => [
|
11
|
+
:thumbnail,
|
12
|
+
:nsfw,
|
13
|
+
:description,
|
14
|
+
:keywords,
|
15
|
+
:categories,
|
16
|
+
:license,
|
17
|
+
:interactive_post
|
18
|
+
]
|
19
|
+
}
|
20
|
+
|
21
|
+
VIDEOS_DELETE_ATTRS = {
|
22
|
+
:required => [
|
23
|
+
:userlogin,
|
24
|
+
:password
|
25
|
+
],
|
26
|
+
:optional => [
|
27
|
+
:username # kind of sloppy, because a user is unlikely to specify both a userlogin AND a username
|
28
|
+
]
|
29
|
+
}
|
30
|
+
|
31
|
+
def self.check_attributes(bliptv_method, attributes)
|
32
|
+
valid_attributes = bliptv_method_to_const(bliptv_method)
|
33
|
+
required = valid_attributes[:required] || Array.new
|
34
|
+
optional = valid_attributes[:optional] || Array.new
|
35
|
+
|
36
|
+
# blip calls it a "userlogin" instead of a "username"
|
37
|
+
if attributes[:username] != nil
|
38
|
+
attributes[:userlogin] = attributes[:username]
|
39
|
+
attributes.delete(:username)
|
40
|
+
end
|
41
|
+
|
42
|
+
attributes.assert_valid_keys(required + optional)
|
43
|
+
attributes.assert_required_keys(required)
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def self.bliptv_method_to_const(method)
|
49
|
+
const_name = method.gsub('.', '_').upcase
|
50
|
+
const_get("#{const_name}_ATTRS")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/bliptv/base.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
module BlipTV
|
2
|
+
# Generic BlipTV exception class.
|
3
|
+
class BlipTVError < StandardError #:nodoc:
|
4
|
+
end
|
5
|
+
|
6
|
+
# Raised when username and password has not been set.
|
7
|
+
class AuthenticationRequiredError < BlipTVError #:nodoc:
|
8
|
+
def message
|
9
|
+
"Method that you're trying to execute requires username and password."
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Raised when calling not yet implemented API methods.
|
14
|
+
class NotImplementedError < BlipTVError #:nodoc:
|
15
|
+
def message
|
16
|
+
'This method is not yet implemented.'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# This is the class that should be instantiated for basic
|
22
|
+
# communication with the Blip.tv API
|
23
|
+
#
|
24
|
+
class Base
|
25
|
+
|
26
|
+
# TODO allow user to specify userlogin and password on intialize
|
27
|
+
def initialize
|
28
|
+
end
|
29
|
+
|
30
|
+
# Implements the Blip.tv REST Upload API
|
31
|
+
#
|
32
|
+
# <tt>new_attributes</tt> hash should contain next required keys:
|
33
|
+
# * <tt>title:</tt> The video title;
|
34
|
+
# * <tt>file:</tt> The video file;
|
35
|
+
#
|
36
|
+
# and optionally:
|
37
|
+
# * <tt>thumbnail:</tt> A thumbnail file;
|
38
|
+
# * <tt>nsfw:</tt> true if explicit, false otherwise. Defaults to false;
|
39
|
+
# * <tt>description:</tt> A description of the video
|
40
|
+
# * <tt>username:</tt> Username
|
41
|
+
# * <tt>password:</tt> Password
|
42
|
+
# * <tt>keywords:</tt> A comma-separated string of keywords # TODO this should be nice and also accept Arrays
|
43
|
+
# * <tt>categories:</tt> A Hash of categories
|
44
|
+
# * <tt>license:</tt> A license for the video
|
45
|
+
# * <tt>interactive_post:</tt> Specify whether or not a post is interactive. More here[http://wiki.blip.tv/index.php/API_2.0:_Post_Interactivity]
|
46
|
+
#
|
47
|
+
# Example:
|
48
|
+
#
|
49
|
+
# bliptv.upload_video(:title => 'Check out this guy getting kicked in the nuts!', :file => File.open('/movies/nuts.mov'))
|
50
|
+
#
|
51
|
+
# Returns BlipTV::Video instance.
|
52
|
+
#
|
53
|
+
def upload_video(new_attributes={})
|
54
|
+
BlipTV::ApiSpec.check_attributes('videos.upload', new_attributes)
|
55
|
+
|
56
|
+
new_attributes = {
|
57
|
+
:post => "1",
|
58
|
+
:item_type => "file",
|
59
|
+
:skin => "xmlhttprequest",
|
60
|
+
:file_role => "Web"
|
61
|
+
}.merge(new_attributes) # blip.tv requires the "post" param to be set to 1
|
62
|
+
|
63
|
+
request = BlipTV::Request.new(:post, 'videos.upload')
|
64
|
+
request.run do |p|
|
65
|
+
for param, value in new_attributes
|
66
|
+
p.send("#{param}=", value)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
BlipTV::Video.new(request.response['post_url'].to_s)
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
# Looks up all videos on Blip.tv with a given <tt>username</tt>
|
75
|
+
#
|
76
|
+
# Options hash could contain next values:
|
77
|
+
# * <tt>page</tt>: The "page number" of results to retrieve (e.g. 1, 2, 3); if not specified, the default value equals 1.
|
78
|
+
# * <tt>pagelen</tt>: The number of results to retrieve per page (maximum 100). If not specified, the default value equals 20.
|
79
|
+
#
|
80
|
+
# Example:
|
81
|
+
#
|
82
|
+
# bliptv.find_all_videos_by_user("username")
|
83
|
+
# or
|
84
|
+
# bliptv.find_all_videos_by_user("username", {:page => 1, :pagelen => 20})
|
85
|
+
#
|
86
|
+
# Returns array of BlipTV::Video objects.
|
87
|
+
#
|
88
|
+
def find_all_videos_by_user(username, options={})
|
89
|
+
options[:page] ||= 1; options[:pagelen] ||= 20
|
90
|
+
url, path = "#{username}.blip.tv", "/posts/?skin=api&page=#{options[:page]}&pagelen=#{options[:pagelen]}"
|
91
|
+
request = Net::HTTP.get(url, path)
|
92
|
+
hash = Hash.from_xml(request)
|
93
|
+
hash == nil ? [] : parse_videos_list(hash)
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
# Searches through and returns videos based on the <tt>search_string</tt>.
|
98
|
+
#
|
99
|
+
# This method is a direct call of Blip.tv's search method. You get what you get. No guarantees are made.
|
100
|
+
#
|
101
|
+
# Example:
|
102
|
+
#
|
103
|
+
# bliptv.search_videos("cool stuff")
|
104
|
+
#
|
105
|
+
# Returns an array of BlipTV::Video objects
|
106
|
+
#
|
107
|
+
def search_videos(search_string)
|
108
|
+
request = Net::HTTP.get(URI.parse("http://www.blip.tv/search/?search=#{search_string}&skin=api"))
|
109
|
+
hash = Hash.from_xml(request)
|
110
|
+
parse_videos_list(hash)
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def parse_videos_list(hash)
|
116
|
+
list = []
|
117
|
+
begin
|
118
|
+
hash["response"]["payload"]["asset"].each do |entry|
|
119
|
+
list << Video.new(entry)
|
120
|
+
end
|
121
|
+
rescue NoMethodError
|
122
|
+
list = []
|
123
|
+
end
|
124
|
+
list
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'mime/types'
|
2
|
+
|
3
|
+
class MultipartParams #:nodoc:
|
4
|
+
attr_accessor :content_type, :body
|
5
|
+
|
6
|
+
def initialize(param_hash={})
|
7
|
+
@boundary_token = generate_boundary_token
|
8
|
+
self.content_type = "multipart/form-data; boundary=#{@boundary_token}"
|
9
|
+
self.body = pack_params(param_hash)
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def generate_boundary_token
|
15
|
+
[Array.new(8) {rand(256)}].join
|
16
|
+
end
|
17
|
+
|
18
|
+
def pack_params(hash)
|
19
|
+
marker = "--#{@boundary_token}\r\n"
|
20
|
+
files_params = hash.find_all{|k,v| v.is_a?(File)}.to_h
|
21
|
+
text_params = hash - files_params
|
22
|
+
|
23
|
+
pack_hash(text_params, marker) + marker + pack_hash(files_params, marker) + "--#{@boundary_token}--\r\n"
|
24
|
+
end
|
25
|
+
|
26
|
+
def pack_hash(hash, marker)
|
27
|
+
hash.map do |name, value|
|
28
|
+
marker + case value
|
29
|
+
when String
|
30
|
+
text_to_multipart(name, value)
|
31
|
+
when File
|
32
|
+
file_to_multipart(name, value)
|
33
|
+
end
|
34
|
+
end.join('')
|
35
|
+
end
|
36
|
+
|
37
|
+
def file_to_multipart(key,file)
|
38
|
+
filename = File.basename(file.path)
|
39
|
+
mime_types = MIME::Types.of(filename)
|
40
|
+
mime_type = mime_types.empty? ? "application/octet-stream" : mime_types.first.content_type
|
41
|
+
part = %Q[Content-Disposition: form-data; name="#{key}"; filename="#{filename}"\r\n]
|
42
|
+
part += "Content-Transfer-Encoding: binary\r\n"
|
43
|
+
part += "Content-Type: video/mp4\r\n\r\n#{file.read}\r\n"
|
44
|
+
end
|
45
|
+
|
46
|
+
def text_to_multipart(key,value)
|
47
|
+
"Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n#{value.to_s}\r\n"
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
|
3
|
+
module BlipTV
|
4
|
+
|
5
|
+
# Raised when response from Blip.tv contains absolutely no data
|
6
|
+
class EmptyResponseError < BlipTVError #:nodoc:
|
7
|
+
end
|
8
|
+
|
9
|
+
# Raised when response from Blip.tv contains an error
|
10
|
+
class ResponseError < BlipTVError #:nodoc:
|
11
|
+
def initialize(message)
|
12
|
+
super message
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Class used to send requests over http to Viddler API.
|
17
|
+
class Request #:nodoc:
|
18
|
+
|
19
|
+
API_URL = 'http://uploads.blip.tv/'
|
20
|
+
DEFAULT_HEADERS = {:accept => 'application/xml', :content_type => 'multi-part/form-data'}
|
21
|
+
|
22
|
+
attr_accessor :url, :http_method, :response, :body
|
23
|
+
attr_reader :headers, :params
|
24
|
+
|
25
|
+
def initialize(http_method, method) #:nodoc:
|
26
|
+
@http_method = http_method.to_s
|
27
|
+
@url = API_URL
|
28
|
+
self.params = {} #{:method => viddlerize(method)}
|
29
|
+
self.headers = DEFAULT_HEADERS
|
30
|
+
end
|
31
|
+
|
32
|
+
# Use this method to setup your request's payload and headers.
|
33
|
+
#
|
34
|
+
# Example:
|
35
|
+
#
|
36
|
+
# request.set :headers do |h|
|
37
|
+
# h.content_type = 'application/ufo'
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# request.set :params do |p|
|
41
|
+
# p.sessionid = '12323'
|
42
|
+
# p.api_key = '13123
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
def set(container, &declarations)
|
46
|
+
struct = OpenStruct.new
|
47
|
+
declarations.call(struct)
|
48
|
+
send("#{container}=", struct.table)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Send http request to Viddler API.
|
52
|
+
def run(&block)
|
53
|
+
if block_given?
|
54
|
+
set(:params, &block)
|
55
|
+
end
|
56
|
+
|
57
|
+
if post? and multipart?
|
58
|
+
put_multipart_params_into_body
|
59
|
+
else
|
60
|
+
put_params_into_url
|
61
|
+
end
|
62
|
+
|
63
|
+
request = RestClient::Request.execute(
|
64
|
+
:method => http_method,
|
65
|
+
:url => url,
|
66
|
+
:headers => headers,
|
67
|
+
:payload => body
|
68
|
+
)
|
69
|
+
self.response = parse_response(request)
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def parse_response(raw_response)
|
75
|
+
raise EmptyResponseError if raw_response.blank?
|
76
|
+
response_hash = Hash.from_xml(raw_response)
|
77
|
+
begin
|
78
|
+
if response_error = response_hash["otter_responses"]["response"]["error"]
|
79
|
+
raise ResponseError.new(bliptv_error_message(response_error))
|
80
|
+
end
|
81
|
+
rescue # we don't care if it fails, that means it works
|
82
|
+
end
|
83
|
+
response_hash["post_url"] = raw_response.match(/\d{3,12}/)[0] # extracts the post_url, since from_xml isn't grabbing it
|
84
|
+
response_hash
|
85
|
+
end
|
86
|
+
|
87
|
+
def put_multipart_params_into_body
|
88
|
+
multiparams = MultipartParams.new(params)
|
89
|
+
self.body = multiparams.body
|
90
|
+
self.headers = {:content_type => multiparams.content_type}
|
91
|
+
end
|
92
|
+
|
93
|
+
def put_params_into_url
|
94
|
+
self.url = API_URL + '?' + params.to_query
|
95
|
+
end
|
96
|
+
|
97
|
+
def viddlerize(name)
|
98
|
+
if name.include?('viddler.')
|
99
|
+
name
|
100
|
+
else
|
101
|
+
'viddler.' + name
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def params=(hash) #:nodoc:
|
106
|
+
@params ||= Hash.new
|
107
|
+
@params.update(hash)
|
108
|
+
end
|
109
|
+
|
110
|
+
def headers=(hash) #:nodoc:
|
111
|
+
@headers ||= Hash.new
|
112
|
+
@headers.update(hash)
|
113
|
+
end
|
114
|
+
|
115
|
+
def multipart? #:nodoc:
|
116
|
+
# TOOD let's be nice and do a File.exists?(v)
|
117
|
+
if params.find{|k,v| v.is_a?(File)} then true else false end
|
118
|
+
end
|
119
|
+
|
120
|
+
def post? #:nodoc:
|
121
|
+
http_method == 'post'
|
122
|
+
end
|
123
|
+
|
124
|
+
def bliptv_error_message(response_error)
|
125
|
+
description = response_error['description'] || ''
|
126
|
+
details = response_error['details'] || ''
|
127
|
+
code = response_error['code'] || ''
|
128
|
+
|
129
|
+
details = ": #{details};" unless details.empty?
|
130
|
+
code = " [code: #{code}]" unless code.empty?
|
131
|
+
%Q[#{description}#{details}#{code}]
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
data/lib/bliptv/video.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module BlipTV
|
5
|
+
|
6
|
+
BLIP_TV_ID_EXPR = /\d{3,12}/
|
7
|
+
|
8
|
+
# Raised when pinging Blip.tv for video information results in an error
|
9
|
+
class VideoResponseError < BlipTVError #:nodoc:
|
10
|
+
def initialize(message)
|
11
|
+
super message
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class VideoDeleteError < BlipTVError
|
16
|
+
def intialize(message)
|
17
|
+
super message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# This class wraps Blip.tv's video's information.
|
22
|
+
class Video
|
23
|
+
|
24
|
+
attr_accessor :id,
|
25
|
+
:title,
|
26
|
+
:description,
|
27
|
+
:guid,
|
28
|
+
:deleted,
|
29
|
+
:view_count,
|
30
|
+
:tags,
|
31
|
+
:links,
|
32
|
+
:author,
|
33
|
+
:update_time,
|
34
|
+
:explicit,
|
35
|
+
:notes,
|
36
|
+
:license,
|
37
|
+
:embed_url,
|
38
|
+
:embed_code
|
39
|
+
|
40
|
+
def initialize(blip_id) #:nodoc:
|
41
|
+
blip_id = blip_id.to_s if blip_id.class == Fixnum
|
42
|
+
|
43
|
+
if blip_id.class == String && blip_id.match(BLIP_TV_ID_EXPR)
|
44
|
+
update_attributes_from_id(blip_id)
|
45
|
+
elsif blip_id.class == Hash
|
46
|
+
update_attributes_from_hash(blip_id)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def update_attributes_from_id(blip_id)
|
51
|
+
@id = blip_id
|
52
|
+
|
53
|
+
a = get_attributes
|
54
|
+
update_attributes_from_hash(a)
|
55
|
+
end
|
56
|
+
|
57
|
+
def update_attributes_from_hash(a)
|
58
|
+
|
59
|
+
@id = a['item_id'] if @id == nil
|
60
|
+
@title = a['title']
|
61
|
+
@description = a['description']
|
62
|
+
@guid = a['guid']
|
63
|
+
@deleted = a['deleted']
|
64
|
+
@view_count = a['views']
|
65
|
+
@tags = parse_tags a['tags']
|
66
|
+
@links = a['links']['link']
|
67
|
+
@thumbnail_url = a['thumbnail_url']
|
68
|
+
@author = a['created_by']['login'] if a['created_by']
|
69
|
+
@update_time = a['timestamp'] ? Time.at(a['update_time'].to_i) : nil
|
70
|
+
@explicit = a['explicit']
|
71
|
+
@license = a['license']
|
72
|
+
@notes = a['notes']
|
73
|
+
@embed_url = a['embed_url']
|
74
|
+
@embed_code = a['embed_code']
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# fire off a HTTP GET response to Blip.tv
|
79
|
+
#
|
80
|
+
# In the future, this should probably be rolled into the
|
81
|
+
# BlipTV::Request class, so that all exception raising and
|
82
|
+
# network communication exists in instances of that class.
|
83
|
+
#
|
84
|
+
def get_attributes
|
85
|
+
url = URI.parse('http://www.blip.tv/')
|
86
|
+
res = Net::HTTP.start(url.host, url.port) {|http|
|
87
|
+
http.get("http://www.blip.tv/file/#{@id.to_s}?skin=api")
|
88
|
+
}
|
89
|
+
|
90
|
+
hash = Hash.from_xml(res.body)
|
91
|
+
|
92
|
+
if hash["response"]["status"] != "OK"
|
93
|
+
raise VideoResponseError.new(hash["response"]["notice"])
|
94
|
+
end
|
95
|
+
|
96
|
+
if hash["response"]["payload"]["asset"].is_a?(Array)
|
97
|
+
return hash["response"]["payload"]["asset"][0] # there may be several assets. In that case, read the first one
|
98
|
+
else
|
99
|
+
return hash["response"]["payload"]["asset"]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Refresh the current video object. Useful to check up on encoding progress,
|
105
|
+
# etc.
|
106
|
+
#
|
107
|
+
def refresh
|
108
|
+
update_attributes_from_id(@id)
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# delete! will delete the file from Blip.tv
|
113
|
+
#
|
114
|
+
def delete!(creds = {}, section = "file", reason = "because")
|
115
|
+
BlipTV::ApiSpec.check_attributes('videos.delete', creds)
|
116
|
+
|
117
|
+
reason = reason.gsub(" ", "%20") # TODO write a method to handle this and other illegalities of URL
|
118
|
+
|
119
|
+
if creds[:username] && !creds[:userlogin]
|
120
|
+
creds[:userlogin] = creds[:username]
|
121
|
+
end
|
122
|
+
|
123
|
+
url, path = "www.blip.tv", "/?userlogin=#{creds[:userlogin]}&password=#{creds[:password]}&cmd=delete&s=file&id=#{@id}&reason=#{reason}&skin=api"
|
124
|
+
request = Net::HTTP.get(url, path)
|
125
|
+
hash = Hash.from_xml(request)
|
126
|
+
make_sure_video_was_deleted(hash)
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
#
|
132
|
+
# Makes sense out of Blip.tv's strucutre of the <tt>tag</tt> element
|
133
|
+
#
|
134
|
+
# returns a String
|
135
|
+
#
|
136
|
+
def parse_tags(element)
|
137
|
+
if element.class == Hash && element['string']
|
138
|
+
if element['string'].class == Array
|
139
|
+
return element['string'].join(", ")
|
140
|
+
elsif element['string'].class == String
|
141
|
+
return element['string']
|
142
|
+
end
|
143
|
+
else
|
144
|
+
return ""
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
#
|
149
|
+
# make_sure_video_was_deleted analyzes the response <tt>hash</tt>
|
150
|
+
# to make sure it was a success
|
151
|
+
#
|
152
|
+
# raises a descriptive BlipTV::VideoDeleteError
|
153
|
+
#
|
154
|
+
def make_sure_video_was_deleted(hash)
|
155
|
+
# TODO have a special case for authentication required?
|
156
|
+
if hash["response"]["status"] != "OK"
|
157
|
+
begin
|
158
|
+
raise VideoDeleteError.new("#{hash['response']['error']['code']}: #{hash['response']['error']['message']} ")
|
159
|
+
rescue NoMethodError # TODO irony!
|
160
|
+
raise VideoDeleteError.new(hash.to_yaml)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
data/lib/ext/array.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
class Array #:nodoc:
|
2
|
+
|
3
|
+
# Extraceted from Ruby Facets:
|
4
|
+
# Converts a two-element associative array into a hash.
|
5
|
+
def to_h(arrayed=nil)
|
6
|
+
h = {}
|
7
|
+
if arrayed
|
8
|
+
each{ |k,*v| h[k] = v }
|
9
|
+
else
|
10
|
+
ary = []
|
11
|
+
each do |a|
|
12
|
+
Array===a ? ary.concat(a) : ary << a
|
13
|
+
end
|
14
|
+
h = Hash[*ary]
|
15
|
+
end
|
16
|
+
h
|
17
|
+
end
|
18
|
+
end
|
data/lib/ext/hash.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
class Hash #:nodoc:
|
2
|
+
|
3
|
+
def assert_required_keys(keys)
|
4
|
+
for key in keys
|
5
|
+
raise(ArgumentError, "Missing required key(s): #{key}") unless self.keys.include?(key)
|
6
|
+
end
|
7
|
+
true
|
8
|
+
end
|
9
|
+
|
10
|
+
# Extracted from Ruby Facets:
|
11
|
+
# 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.
|
12
|
+
def -(other)
|
13
|
+
h = self.dup
|
14
|
+
if other.respond_to?(:to_ary)
|
15
|
+
other.to_ary.each do |k|
|
16
|
+
h.delete(k)
|
17
|
+
end
|
18
|
+
else
|
19
|
+
other.each do |k,v|
|
20
|
+
if h.key?(k)
|
21
|
+
h.delete(k) if v == h[k]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
h
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/test/test_base.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'lib/bliptv'
|
2
|
+
|
3
|
+
class TC_BaseTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@base = BlipTV::Base.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def teardown
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_find_all_videos_by_user
|
12
|
+
|
13
|
+
videos = @base.find_all_videos_by_user("onemonthhere")
|
14
|
+
|
15
|
+
assert_not_equal nil, videos
|
16
|
+
assert_instance_of Array, videos
|
17
|
+
assert videos.size >= 12 # at the time of the writing of the test
|
18
|
+
|
19
|
+
videos.each do |video|
|
20
|
+
assert_not_equal "", video.title # all videos must have a title
|
21
|
+
assert_equal "onemonthhere", video.author
|
22
|
+
assert_equal "false", video.explicit # I know for a fact that all videos are not explicit
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_find_all_videos_by_user_retrieve_100
|
27
|
+
|
28
|
+
videos = @base.find_all_videos_by_user("verycocinar", {:page => 1, :pagelen => 100})
|
29
|
+
|
30
|
+
assert_not_equal nil, videos
|
31
|
+
assert_instance_of Array, videos
|
32
|
+
assert videos.size == 100
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_find_all_videos_by_user_more_than_one_page
|
36
|
+
|
37
|
+
videos_1 = @base.find_all_videos_by_user("verycocinar", {:page => 2, :pagelen => 30})
|
38
|
+
videos_2 = @base.find_all_videos_by_user("verycocinar", {:page => 3, :pagelen => 30})
|
39
|
+
|
40
|
+
assert_instance_of Array, videos_1
|
41
|
+
assert_instance_of Array, videos_2
|
42
|
+
assert videos_1.size == 30
|
43
|
+
assert videos_2.size == 30
|
44
|
+
assert_not_equal videos_1, videos_2
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_search_videos
|
48
|
+
videos = @base.search_videos("cool")
|
49
|
+
|
50
|
+
assert_not_equal nil, videos # unless Blip.tv is having a bad day :(
|
51
|
+
assert_instance_of Array, videos
|
52
|
+
assert videos.size > 10 # assumption
|
53
|
+
|
54
|
+
videos.each do |video|
|
55
|
+
assert_not_equal "", video.title # all videos must have a title
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/test/test_suite.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test/unit/testsuite'
|
3
|
+
require 'test/unit/ui/console/testrunner'
|
4
|
+
|
5
|
+
require 'test/test_video'
|
6
|
+
require 'test/test_base'
|
7
|
+
|
8
|
+
class TS_BlipTVTests
|
9
|
+
def self.suite
|
10
|
+
suite = Test::Unit::TestSuite.new "Blip.tv gem tests"
|
11
|
+
suite << TC_VideoTest.suite
|
12
|
+
suite << TC_BaseTest.suite
|
13
|
+
return suite
|
14
|
+
end
|
15
|
+
end
|
16
|
+
Test::Unit::UI::Console::TestRunner.run(TS_BlipTVTests)
|
data/test/test_video.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'lib/bliptv'
|
2
|
+
|
3
|
+
NO_TAGS = "\n\t\t\n\t"
|
4
|
+
|
5
|
+
class TC_VideoTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
end
|
8
|
+
|
9
|
+
def teardown
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_video_initialize_with_int_and_string
|
13
|
+
video1 = BlipTV::Video.new(2193230)
|
14
|
+
video2 = BlipTV::Video.new("2193230")
|
15
|
+
|
16
|
+
a = [video1, video2]
|
17
|
+
|
18
|
+
a.each do |video|
|
19
|
+
assert_not_equal nil, video
|
20
|
+
assert_instance_of BlipTV::Video, video
|
21
|
+
|
22
|
+
|
23
|
+
assert_equal "Super Mario Galaxy 2", video.title
|
24
|
+
|
25
|
+
h = { "mode" => "escaped", "type" => "text/html" }
|
26
|
+
assert_equal h, video.description
|
27
|
+
|
28
|
+
assert_equal "D2215402-5017-11DE-9B2F-C1BCBB520399", video.guid
|
29
|
+
assert_equal "false", video.deleted
|
30
|
+
assert_equal nil, video.view_count # because we don't have the user login info
|
31
|
+
assert_equal "", video.tags
|
32
|
+
|
33
|
+
links = [{"href"=>"http://blip.tv/file/2193230",
|
34
|
+
"rel"=>"alternate",
|
35
|
+
"type"=>"text/html"},
|
36
|
+
{"href"=>"http://blip.tv/file/2193230/?skin=api",
|
37
|
+
"rel"=>"alternate",
|
38
|
+
"type"=>"text/xml"},
|
39
|
+
{"href"=>"http://blip.tv/file/post/2193230/",
|
40
|
+
"rel"=>"service.edit",
|
41
|
+
"type"=>"text/html"},
|
42
|
+
{"href"=>"http://blip.tv/rss/2204077",
|
43
|
+
"rel"=>"alternate",
|
44
|
+
"type"=>"application/rss+xml"},
|
45
|
+
{"href"=>"http://blip.tv/file/2193230/?skin=atom",
|
46
|
+
"rel"=>"alternate",
|
47
|
+
"type"=>"application/atom+xml"},
|
48
|
+
{"href"=>"http://blip.tv/file/post/2193230/?skin=api",
|
49
|
+
"rel"=>"service.edit",
|
50
|
+
"type"=>"text/xml"}]
|
51
|
+
|
52
|
+
assert_equal links, video.links
|
53
|
+
assert_equal "kotaku", video.author
|
54
|
+
assert_equal "Thu Jan 01 01:00:00 +0100 1970", video.update_time.to_s # not sure why this is the epoch
|
55
|
+
assert_equal "false", video.explicit
|
56
|
+
|
57
|
+
license = {"name"=>"No license (All rights reserved)"}
|
58
|
+
assert_equal license, video.license
|
59
|
+
|
60
|
+
notes = {"mode"=>"escaped", "type"=>"text/html"}
|
61
|
+
assert_equal notes, video.notes
|
62
|
+
|
63
|
+
assert_equal "http://blip.tv/play/g4Q9gYbEEY35ZA", video.embed_url
|
64
|
+
assert_equal "<embed src=\"http://blip.tv/play/g4Q9gYbEEY35ZA\" type=\"application/x-shockwave-flash\" width=\"854\" height=\"510\" allowscriptaccess=\"always\" allowfullscreen=\"true\"></embed>", video.embed_code
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_video_with_more_data
|
69
|
+
video = BlipTV::Video.new(2141730)
|
70
|
+
|
71
|
+
assert_match /\d{3,12}/, video.id
|
72
|
+
assert_equal "Field Recon - One Month Here - Episode 9", video.title
|
73
|
+
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...<br /><br /> Tweets read today from @<a href=\"http://twitter.com/iMuesli\">iMuesli</a> , @<a href=\"http://twitter.com/andrewseely\">andrewseely</a> , @<a href=\"http://twitter.com/JDFirst\">JDFirst</a> , @<a href=\"http://twitter.com/grasp183\">grasp183</a> and @<a href=\"http://twitter.com/mxchickmagnet86\">mxchickmagnet86</a><br /><br /> Thanks for watching!", video.description
|
74
|
+
assert_equal "DB14423E-460F-11DE-B85A-FF0EAE6B9387", video.guid
|
75
|
+
assert_equal "false", video.deleted
|
76
|
+
assert_equal nil, video.view_count
|
77
|
+
assert_equal "bergain, badeschiff, kelly sutton, berlin, germany, kreuzberg", video.tags
|
78
|
+
|
79
|
+
links = [{"href"=>"http://blip.tv/file/2141730",
|
80
|
+
"rel"=>"alternate",
|
81
|
+
"type"=>"text/html"},
|
82
|
+
{"href"=>"http://blip.tv/file/2141730/?skin=api",
|
83
|
+
"rel"=>"alternate",
|
84
|
+
"type"=>"text/xml"},
|
85
|
+
{"href"=>"http://blip.tv/file/post/2141730/",
|
86
|
+
"rel"=>"service.edit",
|
87
|
+
"type"=>"text/html"},
|
88
|
+
{"href"=>"http://blip.tv/rss/2152384",
|
89
|
+
"rel"=>"alternate",
|
90
|
+
"type"=>"application/rss+xml"},
|
91
|
+
{"href"=>"http://blip.tv/file/2141730/?skin=atom",
|
92
|
+
"rel"=>"alternate",
|
93
|
+
"type"=>"application/atom+xml"},
|
94
|
+
{"href"=>"http://blip.tv/file/post/2141730/?skin=api",
|
95
|
+
"rel"=>"service.edit",
|
96
|
+
"type"=>"text/xml"}]
|
97
|
+
assert_equal links, video.links
|
98
|
+
assert_equal "onemonthhere", video.author
|
99
|
+
assert_equal 0, video.update_time.to_i
|
100
|
+
assert_equal "false", video.explicit
|
101
|
+
|
102
|
+
licensce = {"name"=>"Creative Commons Attribution 3.0",
|
103
|
+
"link"=>
|
104
|
+
{"href"=>"http://creativecommons.org/licenses/by/3.0/", "type"=>"text/html"}}
|
105
|
+
assert_equal licensce, video.license
|
106
|
+
|
107
|
+
notes = {"mode"=>"escaped", "type"=>"text/html"}
|
108
|
+
assert_equal notes, video.notes
|
109
|
+
assert_equal "http://blip.tv/play/AYGDsCSV5jE", video.embed_url
|
110
|
+
assert_equal "<embed src=\"http://blip.tv/play/AYGDsCSV5jE\" type=\"application/x-shockwave-flash\" width=\"640\" height=\"510\" allowscriptaccess=\"always\" allowfullscreen=\"true\"></embed>", video.embed_code
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_video_delete
|
114
|
+
base = BlipTV::Base.new
|
115
|
+
|
116
|
+
options = {
|
117
|
+
:userlogin => "bliptv_ruby_gem",
|
118
|
+
:password => "thisissosecret",
|
119
|
+
:file => File.open('/Users/msutton/Desktop/output.mp4'), # change this to a file of your own
|
120
|
+
:title => "test title",
|
121
|
+
:description => "test description"
|
122
|
+
}
|
123
|
+
|
124
|
+
video = base.upload_video(options) #=> BlipTV::Video
|
125
|
+
|
126
|
+
options = {
|
127
|
+
:userlogin => "bliptv_ruby_gem",
|
128
|
+
:password => "thisissosecret"
|
129
|
+
}
|
130
|
+
|
131
|
+
video.delete!(options)
|
132
|
+
end
|
133
|
+
end
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bliptv
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Kelly Sutton
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-06-05 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: A Ruby library from Blip.tv
|
17
|
+
email: michael.k.sutton@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- lib/bliptv/api_spec.rb
|
24
|
+
- lib/bliptv/base.rb
|
25
|
+
- lib/bliptv/multipart_params.rb
|
26
|
+
- lib/bliptv/request.rb
|
27
|
+
- lib/bliptv/video.rb
|
28
|
+
- lib/bliptv.rb
|
29
|
+
- lib/ext/array.rb
|
30
|
+
- lib/ext/hash.rb
|
31
|
+
- lib/ext/open_struct.rb
|
32
|
+
- README.rdoc
|
33
|
+
files:
|
34
|
+
- lib/bliptv/api_spec.rb
|
35
|
+
- lib/bliptv/base.rb
|
36
|
+
- lib/bliptv/multipart_params.rb
|
37
|
+
- lib/bliptv/request.rb
|
38
|
+
- lib/bliptv/video.rb
|
39
|
+
- lib/bliptv.rb
|
40
|
+
- lib/ext/array.rb
|
41
|
+
- lib/ext/hash.rb
|
42
|
+
- lib/ext/open_struct.rb
|
43
|
+
- License.txt
|
44
|
+
- Manifest
|
45
|
+
- Rakefile
|
46
|
+
- README.rdoc
|
47
|
+
- test/test_base.rb
|
48
|
+
- test/test_suite.rb
|
49
|
+
- test/test_video.rb
|
50
|
+
- bliptv.gemspec
|
51
|
+
has_rdoc: true
|
52
|
+
homepage: http://github.com/kellysutton/bliptv
|
53
|
+
licenses: []
|
54
|
+
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options:
|
57
|
+
- --line-numbers
|
58
|
+
- --inline-source
|
59
|
+
- --title
|
60
|
+
- Bliptv
|
61
|
+
- --main
|
62
|
+
- README.rdoc
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0"
|
70
|
+
version:
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "1.2"
|
76
|
+
version:
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project: bliptv
|
80
|
+
rubygems_version: 1.3.5
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: A Ruby library from Blip.tv
|
84
|
+
test_files:
|
85
|
+
- test/test_base.rb
|
86
|
+
- test/test_suite.rb
|
87
|
+
- test/test_video.rb
|