vodpod 0.0.1

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.
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
+