pius-youtube-g 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +52 -0
- data/Manifest.txt +31 -0
- data/README.txt +97 -0
- data/Rakefile +24 -0
- data/TODO.txt +16 -0
- data/lib/youtube_g.rb +67 -0
- data/lib/youtube_g/chain_io.rb +71 -0
- data/lib/youtube_g/client.rb +85 -0
- data/lib/youtube_g/model/author.rb +11 -0
- data/lib/youtube_g/model/category.rb +11 -0
- data/lib/youtube_g/model/contact.rb +16 -0
- data/lib/youtube_g/model/content.rb +18 -0
- data/lib/youtube_g/model/playlist.rb +8 -0
- data/lib/youtube_g/model/rating.rb +17 -0
- data/lib/youtube_g/model/thumbnail.rb +17 -0
- data/lib/youtube_g/model/user.rb +20 -0
- data/lib/youtube_g/model/video.rb +190 -0
- data/lib/youtube_g/parser.rb +169 -0
- data/lib/youtube_g/record.rb +12 -0
- data/lib/youtube_g/request/base_search.rb +26 -0
- data/lib/youtube_g/request/standard_search.rb +40 -0
- data/lib/youtube_g/request/user_search.rb +43 -0
- data/lib/youtube_g/request/video_search.rb +93 -0
- data/lib/youtube_g/request/video_upload.rb +218 -0
- data/lib/youtube_g/response/video_search.rb +41 -0
- data/lib/youtube_g/version.rb +3 -0
- data/test/helper.rb +6 -0
- data/test/test_chain_io.rb +63 -0
- data/test/test_client.rb +263 -0
- data/test/test_video.rb +38 -0
- data/test/test_video_search.rb +134 -0
- metadata +113 -0
data/History.txt
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
* Implement video update and video delete in Upload
|
2
|
+
* Refactor the uploader slightly
|
3
|
+
* Use Builder to generate XML packets
|
4
|
+
* Use a faster Camping-based URL escaper (also avoid cgi.rb)
|
5
|
+
* Removed the logger nightmare, use YouTubeG.logger for everything whatever that may be
|
6
|
+
* Use streams for file uploads instead of in-memory strings
|
7
|
+
|
8
|
+
== 0.5.0 / 2009-01-07
|
9
|
+
|
10
|
+
* Fixed bug in user favorites (thanks Pius Uzamere)
|
11
|
+
|
12
|
+
== 0.4.9.9 / 2008-09-01
|
13
|
+
|
14
|
+
* Add Geodata information (thanks Jose Galisteo)
|
15
|
+
* Added :page and :per_page options, this allows easier usage of the will_paginate
|
16
|
+
plugin with the library. The :offset and :max_results options are no longer available. [Daniel Insley]
|
17
|
+
* Added ability to get video responses on the instances of the YouTube::Model::Video object. [Daniel Insley]
|
18
|
+
* Added and improved the existing documentation [Daniel Insley]
|
19
|
+
* Fixed usage of deprecated yt:racy, now using media:rating [Daniel Insley]
|
20
|
+
* Renamed can_embed? method to embeddable? [Daniel Insley]
|
21
|
+
* Added ability for padingation and ordering on standard feeds. [Daniel Insley]
|
22
|
+
* Add error-handling for video upload errors. [FiXato]
|
23
|
+
* Add error-handling for authentication errors from YouTube during video upload. [FiXato]
|
24
|
+
* Add support for making videos private upon video upload. [FiXato]
|
25
|
+
* Fix issue with REXML parsing of video upload response. [FiXato]
|
26
|
+
* Fix issue with response code comparison. [FiXato]
|
27
|
+
* Authcode is now retrieved for video uploads. [FiXato]
|
28
|
+
* Add basic support for uploading videos [thanks Joe Damato]
|
29
|
+
* Add basic support for related videos [tmm1]
|
30
|
+
* Improve docs for order_by attribute [thanks Jason Arora]
|
31
|
+
* Added support for the "racy" parameter (choices are "include" or "exclude") [thanks Jason Arora]
|
32
|
+
* Add missing attribute reader for description [tmm1]
|
33
|
+
* Fix issue with missing yt:statistics and viewCount [tmm1]
|
34
|
+
* Allow Client#video_by to take either a url or a video id [tmm1]
|
35
|
+
|
36
|
+
== 0.4.1 / 2008-02-11
|
37
|
+
|
38
|
+
* Added 3GPP video format [shane]
|
39
|
+
* Fixed tests [shane]
|
40
|
+
|
41
|
+
== 0.4.0 / 2007-12-18
|
42
|
+
|
43
|
+
* Fixed API projection in search URL [Pete Higgins]
|
44
|
+
* Fixed embeddable video searching [Pete Higgins]
|
45
|
+
* Fixed video embeddable detection [Pete Higgins]
|
46
|
+
* Fixed unique id hyphen detection [Pete Higgins, Chris Taggart]
|
47
|
+
|
48
|
+
== 0.3.0 / 2007-09-17
|
49
|
+
|
50
|
+
* Initial public release
|
51
|
+
* Birthday!
|
52
|
+
|
data/Manifest.txt
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
TODO.txt
|
6
|
+
lib/youtube_g.rb
|
7
|
+
lib/youtube_g/chain_io.rb
|
8
|
+
lib/youtube_g/client.rb
|
9
|
+
lib/youtube_g/model/author.rb
|
10
|
+
lib/youtube_g/model/category.rb
|
11
|
+
lib/youtube_g/model/contact.rb
|
12
|
+
lib/youtube_g/model/content.rb
|
13
|
+
lib/youtube_g/model/playlist.rb
|
14
|
+
lib/youtube_g/model/rating.rb
|
15
|
+
lib/youtube_g/model/thumbnail.rb
|
16
|
+
lib/youtube_g/model/user.rb
|
17
|
+
lib/youtube_g/model/video.rb
|
18
|
+
lib/youtube_g/parser.rb
|
19
|
+
lib/youtube_g/record.rb
|
20
|
+
lib/youtube_g/request/base_search.rb
|
21
|
+
lib/youtube_g/request/standard_search.rb
|
22
|
+
lib/youtube_g/request/user_search.rb
|
23
|
+
lib/youtube_g/request/video_search.rb
|
24
|
+
lib/youtube_g/request/video_upload.rb
|
25
|
+
lib/youtube_g/response/video_search.rb
|
26
|
+
lib/youtube_g/version.rb
|
27
|
+
test/helper.rb
|
28
|
+
test/test_chain_io.rb
|
29
|
+
test/test_client.rb
|
30
|
+
test/test_video.rb
|
31
|
+
test/test_video_search.rb
|
data/README.txt
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
= youtube-g
|
2
|
+
|
3
|
+
http://youtube-g.rubyforge.org/
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
youtube-g is a pure Ruby client for the YouTube GData API. It provides an easy
|
8
|
+
way to access the latest YouTube video search results from your own programs.
|
9
|
+
In comparison with the earlier Youtube search interfaces, this new API and
|
10
|
+
library offers much-improved flexibility around executing complex search
|
11
|
+
queries to obtain well-targeted video search results.
|
12
|
+
|
13
|
+
More detail on the underlying source Google-provided API is available at:
|
14
|
+
|
15
|
+
http://code.google.com/apis/youtube/overview.html
|
16
|
+
|
17
|
+
== AUTHORS
|
18
|
+
|
19
|
+
Shane Vitarana and Walter Korman
|
20
|
+
|
21
|
+
== WHERE TO GET HELP
|
22
|
+
|
23
|
+
http://rubyforge.org/projects/youtube-g
|
24
|
+
http://groups.google.com/group/ruby-youtube-library
|
25
|
+
|
26
|
+
== FEATURES/PROBLEMS:
|
27
|
+
|
28
|
+
* Aims to be in parity with Google's YouTube GData API. Core functionality
|
29
|
+
is currently present -- work is in progress to fill in the rest.
|
30
|
+
|
31
|
+
== SYNOPSIS:
|
32
|
+
|
33
|
+
Create a client:
|
34
|
+
|
35
|
+
require 'youtube_g'
|
36
|
+
client = YouTubeG::Client.new
|
37
|
+
|
38
|
+
Basic queries:
|
39
|
+
|
40
|
+
client.videos_by(:query => "penguin")
|
41
|
+
client.videos_by(:query => "penguin", :page => 2, :per_page => 15)
|
42
|
+
client.videos_by(:tags => ['tiger', 'leopard'])
|
43
|
+
client.videos_by(:categories => [:news, :sports])
|
44
|
+
client.videos_by(:categories => [:news, :sports], :tags => ['soccer', 'football'])
|
45
|
+
client.videos_by(:user => 'liz')
|
46
|
+
client.videos_by(:favorites, :user => 'liz')
|
47
|
+
|
48
|
+
Standard feeds:
|
49
|
+
|
50
|
+
client.videos_by(:most_viewed)
|
51
|
+
client.videos_by(:most_linked, :page => 3)
|
52
|
+
client.videos_by(:top_rated, :time => :today)
|
53
|
+
|
54
|
+
Advanced queries (with boolean operators OR (either), AND (include), NOT (exclude)):
|
55
|
+
|
56
|
+
client.videos_by(:categories => { :either => [:news, :sports], :exclude => [:comedy] }, :tags => { :include => ['football'], :exclude => ['soccer'] })
|
57
|
+
|
58
|
+
== LOGGING
|
59
|
+
|
60
|
+
YouTubeG passes all logs through the logger variable on the class itself. In Rails context, assign the Rails logger to that variable to collect the messages
|
61
|
+
(don't forget to set the level to debug):
|
62
|
+
|
63
|
+
YouTubeG.logger = RAILS_DEFAULT_LOGGER
|
64
|
+
RAILS_DEFAULT_LOGGER.level = Logger::DEBUG
|
65
|
+
|
66
|
+
== REQUIREMENTS:
|
67
|
+
|
68
|
+
* builder gem
|
69
|
+
|
70
|
+
== INSTALL:
|
71
|
+
|
72
|
+
* sudo gem install youtube-g
|
73
|
+
|
74
|
+
== LICENSE:
|
75
|
+
|
76
|
+
MIT License
|
77
|
+
|
78
|
+
Copyright (c) 2007 Shane Vitarana and Walter Korman
|
79
|
+
|
80
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
81
|
+
a copy of this software and associated documentation files (the
|
82
|
+
'Software'), to deal in the Software without restriction, including
|
83
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
84
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
85
|
+
permit persons to whom the Software is furnished to do so, subject to
|
86
|
+
the following conditions:
|
87
|
+
|
88
|
+
The above copyright notice and this permission notice shall be
|
89
|
+
included in all copies or substantial portions of the Software.
|
90
|
+
|
91
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
92
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
93
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
94
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
95
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
96
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
97
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'hoe'
|
3
|
+
require 'lib/youtube_g/version'
|
4
|
+
|
5
|
+
Hoe.new('youtube-g', YouTubeG::VERSION) do |p|
|
6
|
+
p.rubyforge_name = 'youtube-g'
|
7
|
+
p.author = ["Shane Vitarana", "Walter Korman", "Aman Gupta", "Filip H.F. Slagter", "msp"]
|
8
|
+
p.email = 'shanev@gmail.com'
|
9
|
+
p.summary = 'Ruby client for the YouTube GData API'
|
10
|
+
p.url = 'http://rubyforge.org/projects/youtube-g/'
|
11
|
+
p.extra_deps << 'builder'
|
12
|
+
p.remote_rdoc_dir = ''
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Tag release'
|
16
|
+
task :tag do
|
17
|
+
svn_root = 'svn+ssh://drummr77@rubyforge.org/var/svn/youtube-g'
|
18
|
+
sh %(svn cp #{svn_root}/trunk #{svn_root}/tags/release-#{YouTubeG::VERSION} -m "Tag YouTubeG release #{YouTubeG::VERSION}")
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Load the library in an IRB session'
|
22
|
+
task :console do
|
23
|
+
sh %(irb -r lib/youtube_g.rb)
|
24
|
+
end
|
data/TODO.txt
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
[ ] stub out http request/response cycle for tests
|
2
|
+
[ ] allow specifying values as single items where you don't need to wrap in a list, e.g. :tags => :chickens instead of :tags => [ 'chickens' ]
|
3
|
+
[ ] make sure symbols will work as well as tags everywhere (again, :tags => :chickens is same as :tags => 'chickens')
|
4
|
+
[ ] figure out better structure for class/file (either rename request/video_search.rb or split into one class per file again)
|
5
|
+
[ ] restore spaces after method def names
|
6
|
+
[ ] use a proxy for testing with static sample result xml so we have repeatable tests
|
7
|
+
[ ] Clean up tests using Shoulda to define contexts
|
8
|
+
[ ] Allow :category and :categories for query DSL
|
9
|
+
[ ] Exception handling
|
10
|
+
|
11
|
+
== API Features TODO
|
12
|
+
|
13
|
+
[ ] Profile feed parsing
|
14
|
+
[ ] Playlist feeds
|
15
|
+
[ ] User subscriptions
|
16
|
+
[ ] Video comments
|
data/lib/youtube_g.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'net/https'
|
4
|
+
require 'digest/md5'
|
5
|
+
require 'rexml/document'
|
6
|
+
require 'builder'
|
7
|
+
|
8
|
+
class YouTubeG
|
9
|
+
|
10
|
+
# Base error class for the extension
|
11
|
+
class Error < RuntimeError
|
12
|
+
end
|
13
|
+
|
14
|
+
# URL-escape a string. Stolen from Camping (wonder how many Ruby libs in the wild can say the same)
|
15
|
+
def self.esc(s) #:nodoc:
|
16
|
+
s.to_s.gsub(/[^ \w.-]+/n){'%'+($&.unpack('H2'*$&.size)*'%').upcase}.tr(' ', '+')
|
17
|
+
end
|
18
|
+
|
19
|
+
# Set the logger for the library
|
20
|
+
def self.logger=(any_logger)
|
21
|
+
@logger = any_logger
|
22
|
+
end
|
23
|
+
|
24
|
+
# Get the logger for the library (by default will log to STDOUT). TODO: this is where we grab the Rails logger too
|
25
|
+
def self.logger
|
26
|
+
@logger ||= create_default_logger
|
27
|
+
end
|
28
|
+
|
29
|
+
# Gets mixed into the classes to provide the logger method
|
30
|
+
module Logging #:nodoc:
|
31
|
+
|
32
|
+
# Return the base logger set for the library
|
33
|
+
def logger
|
34
|
+
YouTubeG.logger
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def self.create_default_logger
|
40
|
+
logger = Logger.new(STDOUT)
|
41
|
+
logger.level = Logger::DEBUG
|
42
|
+
logger
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
%w(
|
47
|
+
version
|
48
|
+
client
|
49
|
+
record
|
50
|
+
parser
|
51
|
+
model/author
|
52
|
+
model/category
|
53
|
+
model/contact
|
54
|
+
model/content
|
55
|
+
model/playlist
|
56
|
+
model/rating
|
57
|
+
model/thumbnail
|
58
|
+
model/user
|
59
|
+
model/video
|
60
|
+
request/base_search
|
61
|
+
request/user_search
|
62
|
+
request/standard_search
|
63
|
+
request/video_upload
|
64
|
+
request/video_search
|
65
|
+
response/video_search
|
66
|
+
chain_io
|
67
|
+
).each{|m| require File.dirname(__FILE__) + '/youtube_g/' + m }
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
#:stopdoc:
|
3
|
+
|
4
|
+
# Stream wrapper that reads IOs in succession. Can be fed to Net::HTTP as post body stream. We use it internally to stream file content
|
5
|
+
# instead of reading whole video files into memory. Strings passed to the constructor will be wrapped in StringIOs. By default it will auto-close
|
6
|
+
# file handles when they have been read completely to prevent our uploader from leaking file handles
|
7
|
+
#
|
8
|
+
# chain = ChainIO.new(File.open(__FILE__), File.open('/etc/passwd'), "abcd")
|
9
|
+
class YouTubeG::ChainIO
|
10
|
+
attr_accessor :autoclose
|
11
|
+
|
12
|
+
def initialize(*any_ios)
|
13
|
+
@autoclose = true
|
14
|
+
@chain = any_ios.flatten.map{|e| e.respond_to?(:read) ? e : StringIO.new(e.to_s) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def read(buffer_size = 1024)
|
18
|
+
# Read off the first element in the stack
|
19
|
+
current_io = @chain.shift
|
20
|
+
return false if !current_io
|
21
|
+
|
22
|
+
buf = current_io.read(buffer_size)
|
23
|
+
if !buf && @chain.empty? # End of streams
|
24
|
+
release_handle(current_io) if @autoclose
|
25
|
+
false
|
26
|
+
elsif !buf # This IO is depleted, but next one is available
|
27
|
+
release_handle(current_io) if @autoclose
|
28
|
+
read(buffer_size)
|
29
|
+
elsif buf.length < buffer_size # This IO is depleted, but we were asked for more
|
30
|
+
release_handle(current_io) if @autoclose
|
31
|
+
buf + (read(buffer_size - buf.length) || '') # and recurse
|
32
|
+
else # just return the buffer
|
33
|
+
@chain.unshift(current_io) # put the current back
|
34
|
+
buf
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Predict the length of all embedded IOs. Will automatically send file size.
|
39
|
+
def expected_length
|
40
|
+
@chain.inject(0) do | len, io |
|
41
|
+
if io.respond_to?(:length)
|
42
|
+
len + (io.length - io.pos)
|
43
|
+
elsif io.is_a?(File)
|
44
|
+
len + File.size(io.path) - io.pos
|
45
|
+
else
|
46
|
+
raise "Cannot predict length of #{io.inspect}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def release_handle(io)
|
53
|
+
io.close if io.respond_to?(:close)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Net::HTTP only can send chunks of 1024 bytes. This is very inefficient, so we have a spare IO that will send more when asked for 1024.
|
58
|
+
# We use delegation because the read call is recursive.
|
59
|
+
class YouTubeG::GreedyChainIO < DelegateClass(YouTubeG::ChainIO)
|
60
|
+
BIG_CHUNK = 512 * 1024 # 500 kb
|
61
|
+
|
62
|
+
def initialize(*with_ios)
|
63
|
+
__setobj__(YouTubeG::ChainIO.new(with_ios))
|
64
|
+
end
|
65
|
+
|
66
|
+
def read(any_buffer_size)
|
67
|
+
__getobj__.read(BIG_CHUNK)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
#:startdoc:
|
@@ -0,0 +1,85 @@
|
|
1
|
+
class YouTubeG
|
2
|
+
class Client
|
3
|
+
include YouTubeG::Logging
|
4
|
+
|
5
|
+
# Previously this was a logger instance but we now do it globally
|
6
|
+
def initialize(legacy_debug_flag = nil)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Retrieves an array of standard feed, custom query, or user videos.
|
10
|
+
#
|
11
|
+
# === Parameters
|
12
|
+
# If fetching videos for a standard feed:
|
13
|
+
# params<Symbol>:: Accepts a symbol of :top_rated, :top_favorites, :most_viewed,
|
14
|
+
# :most_popular, :most_recent, :most_discussed, :most_linked,
|
15
|
+
# :most_responded, :recently_featured, and :watch_on_mobile.
|
16
|
+
#
|
17
|
+
# You can find out more specific information about what each standard feed provides
|
18
|
+
# by visiting: http://code.google.com/apis/youtube/reference.html#Standard_feeds
|
19
|
+
#
|
20
|
+
# options<Hash> (optional):: Accepts the options of :time, :page (default is 1),
|
21
|
+
# and :per_page (default is 25). :offset and :max_results
|
22
|
+
# can also be passed for a custom offset.
|
23
|
+
#
|
24
|
+
# If fetching videos by tags, categories, query:
|
25
|
+
# params<Hash>:: Accepts the keys :tags, :categories, :query, :order_by,
|
26
|
+
# :author, :racy, :response_format, :video_format, :page (default is 1),
|
27
|
+
# and :per_page(default is 25)
|
28
|
+
#
|
29
|
+
# options<Hash>:: Not used. (Optional)
|
30
|
+
#
|
31
|
+
# If fetching videos for a particular user:
|
32
|
+
# params<Hash>:: Key of :user with a value of the username.
|
33
|
+
# options<Hash>:: Not used. (Optional)
|
34
|
+
# === Returns
|
35
|
+
# YouTubeG::Response::VideoSearch
|
36
|
+
def videos_by(params, options={})
|
37
|
+
request_params = params.respond_to?(:to_hash) ? params : options
|
38
|
+
request_params[:page] = integer_or_default(request_params[:page], 1)
|
39
|
+
|
40
|
+
unless request_params[:max_results]
|
41
|
+
request_params[:max_results] = integer_or_default(request_params[:per_page], 25)
|
42
|
+
end
|
43
|
+
|
44
|
+
unless request_params[:offset]
|
45
|
+
request_params[:offset] = calculate_offset(request_params[:page], request_params[:max_results] )
|
46
|
+
end
|
47
|
+
|
48
|
+
if params.respond_to?(:to_hash) and not params[:user]
|
49
|
+
request = YouTubeG::Request::VideoSearch.new(request_params)
|
50
|
+
elsif (params.respond_to?(:to_hash) && params[:user]) || (params == :favorites)
|
51
|
+
request = YouTubeG::Request::UserSearch.new(params, request_params)
|
52
|
+
else
|
53
|
+
request = YouTubeG::Request::StandardSearch.new(params, request_params)
|
54
|
+
end
|
55
|
+
|
56
|
+
logger.debug "Submitting request [url=#{request.url}]."
|
57
|
+
parser = YouTubeG::Parser::VideosFeedParser.new(request.url)
|
58
|
+
parser.parse
|
59
|
+
end
|
60
|
+
|
61
|
+
# Retrieves a single YouTube video.
|
62
|
+
#
|
63
|
+
# === Parameters
|
64
|
+
# vid<String>:: The ID or URL of the video that you'd like to retrieve.
|
65
|
+
#
|
66
|
+
# === Returns
|
67
|
+
# YouTubeG::Model::Video
|
68
|
+
def video_by(vid)
|
69
|
+
video_id = vid =~ /^http/ ? vid : "http://gdata.youtube.com/feeds/videos/#{vid}"
|
70
|
+
parser = YouTubeG::Parser::VideoFeedParser.new(video_id)
|
71
|
+
parser.parse
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def calculate_offset(page, per_page)
|
77
|
+
page == 1 ? 1 : ((per_page * page) - per_page + 1)
|
78
|
+
end
|
79
|
+
|
80
|
+
def integer_or_default(value, default)
|
81
|
+
value = value.to_i
|
82
|
+
value > 0 ? value : default
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|