vodpod 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2009 Kyle Kingsbury <aphyr@aphyr.com>
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ * Neither the name of this project nor the names of its contributors may be
13
+ used to endorse or promote products derived from this software without
14
+ specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README ADDED
@@ -0,0 +1,77 @@
1
+ Vodpod - Ruby bindings for the Vodpod API.
2
+ ==========================================
3
+
4
+ Vodpod is a web site that allows you to collect videos. This library lets you
5
+ interact with those collections and videos over their REST-style API, using
6
+ clean Ruby. Typically one interacts with the Vodpod API through javascript, but
7
+ maybe you've got bigger plans. Maybe you want to integrate with a content
8
+ management system, or copy videos automatically from a social bookmarking site.
9
+ Be creative. :-)
10
+
11
+ Right now you can search for videos across the site and in a specific pod,
12
+ retrieve details on videos and pods, and page through videos in a pod. You can
13
+ also post new videos to a pod, and update video attributes. Error handling is
14
+ spotty thus far.
15
+
16
+ Examples
17
+ --------
18
+
19
+ Vodpod.start(:api_key => '...', :auth => '...') do |v|
20
+ # Get a pod
21
+ pod = v.pod('aphyr')
22
+
23
+ # Basic information about a pod is loaded by default
24
+ pod.name # => "aphyr's videos"
25
+ pod.stats # => {"total_views"=>23, "weekly_pod_views"=>2, ...}
26
+
27
+ # Retrieve tags (also works on videos)
28
+ pod.tags # => [<Vodpod::Tag neotokyo (1)>, <Vodpod::Tag game (1)>, ...]
29
+
30
+ # Look at who's following this pod
31
+ pod.followers # => [<Vodpod::User foo>, <Vodpod::User bar>, ...]
32
+
33
+ # Get a full dump of an object's contents (works on Tags, Users, Videos, ...)
34
+ pod.store # => {"name"=>"aphyr's videos", "created_at" => ...}
35
+
36
+ # List some videos
37
+ pod.videos.map { |video| video.title }
38
+ # => ["Official Neotokyo Trailer", "Kittens Attack!"]
39
+
40
+ # You can page through results and filter by tags
41
+ pod.videos(:tags => 'music', :page => 2, :per_page => 16)
42
+ # => [<Vodpod::Video ...>, <Vodpod::Video ...>, ...]
43
+
44
+ # Find videos by searching (Also works on pods)
45
+ v.search('obama', :per_page => 48)
46
+ # => [<Vodpod::Video ...>, <Vodpod::Video ...>, ...]
47
+
48
+ # Get a specific video by ID
49
+ vid = v.video(1063027) # => <Vodpod::Video ...>
50
+
51
+ # Show the associated user
52
+ vid.user # => <Vodpod::User scarrfase>
53
+
54
+ # Post a new video to a pod. Returns the new video.
55
+ pod.post('http://www.youtube.com/watch?v=E0ewUBTSlvQ',
56
+ :title => 'Neotokyo Recon Demo',
57
+ :description => 'Demo footage of the in-development Neotokyo mod',
58
+ :tags => ['game', 'neotokyo', 'trailer']
59
+ )
60
+ # => <Vodpod::Video ...>
61
+
62
+ # Add a tag "sports" to every video in a pod about frisbee.
63
+ pod.search('frisbee').each do |video|
64
+ tags = "#{video.tags} sports"
65
+ video.update(:tags => tags)
66
+ end
67
+ end
68
+
69
+ Roadmap
70
+ -------
71
+
72
+ - Posting videos seems to work--the URL is correct in the returned video JSON,
73
+ but visiting the page doesn't seem to load. Perhaps a caching issue on
74
+ Vodpod's end?
75
+ - Automatic casting for datetimes.
76
+ - Better error handling
77
+ - Iterators for acting on all results without thinking about pagination
data/example/test.rb ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require '../lib/vodpod'
4
+ require 'pp'
5
+
6
+ api_key = '5c87948ac1979401'
7
+ auth = '5c91b8b53586434c'
8
+
9
+ Vodpod.start(:api_key => api_key, :auth => auth) do |v|
10
+ # pp v.pod('aphyr').post('http://www.youtube.com/watch?v=E0ewUBTSlvQ', :title => "Neotokyo Recon Demo", :description => "Excitement!")
11
+ # pp v.video(2465983).update(:title => 'Official Neotokyo Trailer')
12
+ #
13
+ pp v.pod('aphyr').videos(:tags => 'neotokyo')
14
+ end
data/lib/vodpod.rb ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # Vodpod API bindings for Ruby
4
+
5
+ require 'rubygems'
6
+ require 'json'
7
+ require 'uri'
8
+ require 'net/http'
9
+
10
+ module Vodpod
11
+ BASE_URI = 'http://api.vodpod.com/api/'
12
+ ROOT = File.dirname(__FILE__)
13
+
14
+ # Load library
15
+ require "#{ROOT}/vodpod/version"
16
+ require "#{ROOT}/vodpod/error"
17
+ require "#{ROOT}/vodpod/connection"
18
+ require "#{ROOT}/vodpod/record"
19
+ require "#{ROOT}/vodpod/user"
20
+ require "#{ROOT}/vodpod/tag"
21
+ require "#{ROOT}/vodpod/pod"
22
+ require "#{ROOT}/vodpod/video"
23
+
24
+ # Performs URI escaping so that you can construct proper
25
+ # query strings faster. Use this rather than the cgi.rb
26
+ # version since it's faster. (Stolen from Camping).
27
+ def escape(s)
28
+ s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
29
+ '%'+$1.unpack('H2'*$1.size).join('%').upcase
30
+ }.tr(' ', '+')
31
+ end
32
+ module_function :escape
33
+
34
+ # Creates a connection with the provided parameter hash, and yields it in a
35
+ # block. Example:
36
+ #
37
+ # Vodpod.start(:api_key => api_key, :auth => auth) do |v|
38
+ # pod = v.pod('aphyr')
39
+ # p pod.created_at
40
+ # end
41
+ def self.start(params)
42
+ yield Connection.new(params)
43
+ end
44
+ end
@@ -0,0 +1,95 @@
1
+ module Vodpod
2
+ # Connection to vodpod.com; retreives JSON data and handles API key/auth.
3
+ class Connection
4
+
5
+ attr_accessor :api
6
+ attr_accessor :auth
7
+
8
+ # Creates a new connection. Parameters:
9
+ #
10
+ # :api_key => API key
11
+ # :auth => Auth key
12
+ def initialize(params = {})
13
+ @api_key = params[:api_key]
14
+ @auth = params[:auth]
15
+ end
16
+
17
+ # Request via GET
18
+ def get(path, params = {})
19
+ request :get, path, params
20
+ end
21
+
22
+ # Returns a pod by ID.
23
+ def pod(id)
24
+ Pod.load(self, 'pod_id' => id)
25
+ end
26
+
27
+ # Request via POST
28
+ def post(path, params = {})
29
+ request :post, path, params
30
+ end
31
+
32
+ # Perform a JSON request to the Vodpod API for a given path and parameter
33
+ # hash. Returns a parsed JSON document. Automatically provides api_key and
34
+ # auth params if you do not specify them. Method should be one of :get or
35
+ # :post--you should use the #get or #post methods for convenience.
36
+ def request(method, path, params = {})
37
+ defaults = {
38
+ :api_key => @api_key,
39
+ :auth => @auth
40
+ }
41
+
42
+ # Construct query fragment
43
+ query = defaults.merge(params).inject('?') { |s, (k, v)|
44
+ s << "#{Vodpod::escape(k)}=#{Vodpod::escape(v)}&"
45
+ }[0..-2]
46
+
47
+ begin
48
+ # Get URI
49
+ case method
50
+ when :get
51
+ # GET request
52
+ uri = URI.parse(Vodpod::BASE_URI + path + '.js' + query)
53
+ JSON.parse Net::HTTP.get(uri)
54
+ when :post
55
+ # POST request
56
+ uri = URI.parse(Vodpod::BASE_URI + path + '.js')
57
+ res = Net::HTTP.start(uri.host, uri.port) do |http|
58
+ http.post(uri.path, query[1..-1])
59
+ end
60
+ JSON.parse res.body
61
+ else
62
+ # Don't know how to do that kind of request
63
+ raise Error.new("Unsupported request method #{method.inspect}; should be one of :get, :post.")
64
+ end
65
+ rescue => e
66
+ # Error somewhere in the request/parse process.
67
+ raise Error.new("Error retrieving #{uri.path}#{query}: #{e.message}")
68
+ end
69
+ end
70
+
71
+ # Searches for videos. Optionally specify :per_page and :page.
72
+ def search(query, params = {})
73
+ list = get('video/search', params.merge(:query => query))['videos']['items']
74
+ return [] unless list
75
+
76
+ # Map results to Videos
77
+ list.map do |item|
78
+ # These results use Video.1234... as the ID, so we need to strip.
79
+ store = item['video']
80
+ store['video_id'] = store['video_id'].sub(/^Video\./, '').to_i
81
+ Video.new(self, store)
82
+ end
83
+ end
84
+
85
+ # Returns a user by ID.
86
+ def user(id)
87
+ User.new(self, 'user_id' => id)
88
+ end
89
+
90
+ # Returns a video by ID.
91
+ def video(id)
92
+ Video.load(self, 'video_id' => id)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,2 @@
1
+ class Error < RuntimeError
2
+ end
data/lib/vodpod/pod.rb ADDED
@@ -0,0 +1,119 @@
1
+ module Vodpod
2
+ # Represents a pod.
3
+ class Pod < Record
4
+ # Administrative users
5
+ def admins
6
+ if items = @store['users']['admins']
7
+ case items
8
+ when {}
9
+ # No results
10
+ []
11
+ when Array
12
+ # More than one result
13
+ items.map do |item|
14
+ User.new(@connection, item['user'])
15
+ end
16
+ else
17
+ # One result
18
+ [User.new(@connection, items['user'])]
19
+ end
20
+ else
21
+ []
22
+ end
23
+ end
24
+
25
+ # Following users
26
+ def followers
27
+ if items = @store['users']['followers']
28
+ case items
29
+ when {}
30
+ # No results
31
+ []
32
+ when Array
33
+ # More than one result
34
+ items.map do |item|
35
+ User.new(@connection, item['user'])
36
+ end
37
+ else
38
+ # One result
39
+ [User.new(@connection, items['user'])]
40
+ end
41
+ else
42
+ []
43
+ end
44
+ end
45
+
46
+ # Loads information for this pod from the API.
47
+ def load!
48
+ if pod_id
49
+ @store.merge! @connection.get('pod/details', :pod_id => pod_id)["pod"]
50
+ end
51
+ end
52
+
53
+ # Posts a new video to a pod. Returns the video posted.
54
+ #
55
+ # Optional parameters:
56
+ # :title => 'Cats with captions!'
57
+ # :description => 'Ahh the internet...'
58
+ # :tags => 'foo bar baz' or ['foo', 'bar', 'baz']
59
+ def post(url, params = {})
60
+ new_params = params.merge(
61
+ :pod_id => @store['pod_id'],
62
+ :url => url
63
+ )
64
+ # Convert tags to string if necessary
65
+ if new_params[:tags].kind_of? Array
66
+ new_params[:tags] = new_params[:tags].join(' ')
67
+ end
68
+
69
+ # Post
70
+ Video.new(@connection.post('video/post', new_params)['video'])
71
+ end
72
+
73
+ # Searches for videos. Optionally specify :per_page and :page.
74
+ def search(query, params = {})
75
+ # Get list of videos
76
+ params = params.merge(:pod_id => @store['pod_id'], :query => query)
77
+ list = @connection.get('pod/search', params)['videos']['items']
78
+
79
+ return [] unless list
80
+
81
+ # Map results to Videos
82
+ list.map do |item|
83
+ store = item['video']
84
+ #store['video_id'].sub!(/^Video\./, '')
85
+ Video.new(@connection, store)
86
+ end
87
+ end
88
+
89
+ # Returns an array of Tags associated with this pod, by frequency of use.
90
+ def tags
91
+ list = @connection.get('pod/tags', :pod_id => pod_id)['tags']['items']
92
+ list.map do |item|
93
+ Tag.new(@connection, item['t'])
94
+ end
95
+ end
96
+
97
+ # Returns the associated user for this pod.
98
+ def user
99
+ return nil unless @store['user']
100
+
101
+ User.new(@connection, @store['user'])
102
+ end
103
+
104
+ # Videos in a pod. You can use :sort, :per_page, :page, and :tag_id to
105
+ # paginate and filter.
106
+ def videos(params = {})
107
+ # Get list of videos
108
+ params = params.merge(:pod_id => @store['pod_id'])
109
+ list = @connection.get('pod/videos', params)['videos']['items']
110
+
111
+ return [] unless list
112
+
113
+ # Map to objects
114
+ list.map do |item|
115
+ Video.new(@connection, item['video'])
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,34 @@
1
+ module Vodpod
2
+ # Represents a generic Vodpod API record.
3
+ #
4
+ # Vodpod objects like Video, Pod, and Tag inherit from this class. It wraps a
5
+ # store (usually the deserialized JSON hash from an API call) with automatic
6
+ # accessors, so you can call video.title instead of video.store['title'].
7
+ # Records are instantiated with a connection object and a default store of an
8
+ # empty hash.
9
+ class Record
10
+ attr_accessor :store
11
+
12
+ # Like Record.new, but also calls load!
13
+ def self.load(*params)
14
+ record = new(*params)
15
+ record.load! if record.respond_to? :load!
16
+ record
17
+ end
18
+
19
+ # Create a new Record. Takes two parameters: a Connection object so the
20
+ # record can perform further requests, and an optional default value for
21
+ # the store.
22
+ def initialize(connection, store = {})
23
+ @connection = connection
24
+ @store = store
25
+ end
26
+
27
+ # Pass requests to store by default.
28
+ def method_missing(meth, *args)
29
+ if @store.include? meth.to_s
30
+ @store[meth.to_s]
31
+ end
32
+ end
33
+ end
34
+ end
data/lib/vodpod/tag.rb ADDED
@@ -0,0 +1,13 @@
1
+ module Vodpod
2
+ # A Tag, attached to a video. There isn't a way yet to go from tags to videos
3
+ # that I'm aware of, but it might happen in the future.
4
+ class Tag < Record
5
+ def inspect
6
+ "<Vodpod::Tag #{@store['_value']} (#{count})>"
7
+ end
8
+
9
+ def to_s
10
+ @store['_value']
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ module Vodpod
2
+ # A Vodpod user, associated with a pod and with videos.
3
+ class User < Record
4
+ # Returns recent activity by people related to this user. Not working
5
+ # yet--maybe a Vodpod bug?
6
+ def network_activity
7
+ @connection.get('user/network_activity', :user_id => user_id)
8
+ end
9
+
10
+ def inspect
11
+ if @store
12
+ "<Vodpod::User #{@store['username']}>"
13
+ else
14
+ "<Vodpod::User>"
15
+ end
16
+ end
17
+
18
+ def to_s
19
+ @store['username']
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,8 @@
1
+ module Vodpod
2
+ APP_NAME = 'Vodpod'
3
+ APP_VERSION = '0.0.1'
4
+ APP_AUTHOR = 'Kyle Kingsbury'
5
+ APP_EMAIL = 'aphyr@aphyr.com'
6
+ APP_URL = 'http://aphyr.com/projects/ruby-vodpod'
7
+ APP_COPYRIGHT = 'Copyright (c) 2009 Kyle Kingsbury <aphyr@aphyr.com>. All rights reserved.'
8
+ end
@@ -0,0 +1,34 @@
1
+ module Vodpod
2
+ # A video.
3
+ class Video < Record
4
+ # Loads information on this video by video_id
5
+ def load!
6
+ if video_id
7
+ @store.merge! @connection.get('video/details', :video_id => video_id)["video"]
8
+ end
9
+ end
10
+
11
+ def to_s
12
+ @store['title']
13
+ end
14
+
15
+ # Update the title, description, and/or tags for this video. Returns
16
+ # the updated video. Seems to create video records okay, but they aren't
17
+ # viewable and don't appear in collections for editing immediately.
18
+ def update(params)
19
+ new_params = params.merge(
20
+ :video_id => @store['video_id']
21
+ )
22
+
23
+ # Post
24
+ Video.new(@connection.post('video/update', new_params)['video'])
25
+ end
26
+
27
+ # Returns the User for this video.
28
+ def user
29
+ return nil unless @store['user']
30
+
31
+ User.new(@connection, @store['user'])
32
+ end
33
+ end
34
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vodpod
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Kyle Kingsbury
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-08 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: json
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 1.1.4
24
+ version:
25
+ description:
26
+ email: aphyr@aphyr.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - lib/vodpod.rb
35
+ - lib/vodpod
36
+ - lib/vodpod/record.rb
37
+ - lib/vodpod/tag.rb
38
+ - lib/vodpod/pod.rb
39
+ - lib/vodpod/version.rb
40
+ - lib/vodpod/user.rb
41
+ - lib/vodpod/video.rb
42
+ - lib/vodpod/error.rb
43
+ - lib/vodpod/connection.rb
44
+ - example/test.rb
45
+ - LICENSE
46
+ - README
47
+ has_rdoc: true
48
+ homepage: http://aphyr.com/projects/ruby-vodpod
49
+ post_install_message:
50
+ rdoc_options: []
51
+
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 1.8.5
59
+ version:
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ requirements: []
67
+
68
+ rubyforge_project: vodpod
69
+ rubygems_version: 1.3.1
70
+ signing_key:
71
+ specification_version: 2
72
+ summary: Ruby bindings for the Vodpod API.
73
+ test_files: []
74
+