beef-youtube-g 0.4.9.9
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/History.txt +41 -0
- data/Manifest.txt +28 -0
- data/README.txt +84 -0
- data/TODO.txt +16 -0
- data/lib/youtube_g.rb +29 -0
- data/lib/youtube_g/client.rb +85 -0
- data/lib/youtube_g/logger.rb +25 -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 +43 -0
- data/lib/youtube_g/request/standard_search.rb +40 -0
- data/lib/youtube_g/request/user_search.rb +39 -0
- data/lib/youtube_g/request/video_search.rb +93 -0
- data/lib/youtube_g/request/video_upload.rb +130 -0
- data/lib/youtube_g/response/video_search.rb +41 -0
- data/test/test_client.rb +262 -0
- data/test/test_video.rb +42 -0
- data/test/test_video_search.rb +138 -0
- data/youtube-g.gemspec +52 -0
- metadata +87 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
class YouTubeG
|
2
|
+
module Request #:nodoc:
|
3
|
+
class UserSearch < BaseSearch #:nodoc:
|
4
|
+
attr_reader :max_results # max_results
|
5
|
+
attr_reader :order_by # orderby, ([relevance], viewCount, published, rating)
|
6
|
+
attr_reader :offset # start-index
|
7
|
+
|
8
|
+
def initialize(params, options={})
|
9
|
+
@max_results, @order_by, @offset = nil
|
10
|
+
@url = base_url
|
11
|
+
|
12
|
+
if params == :favorites
|
13
|
+
@url << "#{options[:user]}/favorites"
|
14
|
+
set_instance_variables(options)
|
15
|
+
elsif params[:user]
|
16
|
+
@url << "#{params[:user]}/uploads"
|
17
|
+
set_instance_variables(params)
|
18
|
+
end
|
19
|
+
|
20
|
+
@url << build_query_params(to_youtube_params)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def base_url #:nodoc:
|
26
|
+
super << "users/"
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_youtube_params #:nodoc:
|
30
|
+
{
|
31
|
+
'max-results' => @max_results,
|
32
|
+
'orderby' => @order_by,
|
33
|
+
'start-index' => @offset
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
class YouTubeG
|
2
|
+
module Request #:nodoc:
|
3
|
+
class VideoSearch < BaseSearch #:nodoc:
|
4
|
+
# From here: http://code.google.com/apis/youtube/reference.html#yt_format
|
5
|
+
ONLY_EMBEDDABLE = 5
|
6
|
+
|
7
|
+
attr_reader :max_results # max_results
|
8
|
+
attr_reader :order_by # orderby, ([relevance], viewCount, published, rating)
|
9
|
+
attr_reader :offset # start-index
|
10
|
+
attr_reader :query # vq
|
11
|
+
attr_reader :response_format # alt, ([atom], rss, json)
|
12
|
+
attr_reader :tags # /-/tag1/tag2
|
13
|
+
attr_reader :categories # /-/Category1/Category2
|
14
|
+
attr_reader :video_format # format (1=mobile devices)
|
15
|
+
attr_reader :racy # racy ([exclude], include)
|
16
|
+
attr_reader :author
|
17
|
+
|
18
|
+
def initialize(params={})
|
19
|
+
# Initialize our various member data to avoid warnings and so we'll
|
20
|
+
# automatically fall back to the youtube api defaults
|
21
|
+
@max_results, @order_by,
|
22
|
+
@offset, @query,
|
23
|
+
@response_format, @video_format,
|
24
|
+
@racy, @author = nil
|
25
|
+
@url = base_url
|
26
|
+
|
27
|
+
# Return a single video (base_url + /T7YazwP8GtY)
|
28
|
+
return @url << "/" << params[:video_id] if params[:video_id]
|
29
|
+
|
30
|
+
@url << "/-/" if (params[:categories] || params[:tags])
|
31
|
+
@url << categories_to_params(params.delete(:categories)) if params[:categories]
|
32
|
+
@url << tags_to_params(params.delete(:tags)) if params[:tags]
|
33
|
+
|
34
|
+
set_instance_variables(params)
|
35
|
+
|
36
|
+
if( params[ :only_embeddable ] )
|
37
|
+
@video_format = ONLY_EMBEDDABLE
|
38
|
+
end
|
39
|
+
|
40
|
+
@url << build_query_params(to_youtube_params)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def base_url #:nodoc:
|
46
|
+
super << "videos"
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_youtube_params #:nodoc:
|
50
|
+
{
|
51
|
+
'max-results' => @max_results,
|
52
|
+
'orderby' => @order_by,
|
53
|
+
'start-index' => @offset,
|
54
|
+
'vq' => @query,
|
55
|
+
'alt' => @response_format,
|
56
|
+
'format' => @video_format,
|
57
|
+
'racy' => @racy,
|
58
|
+
'author' => @author
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
# Convert category symbols into strings and build the URL. GData requires categories to be capitalized.
|
63
|
+
# Categories defined like: categories => { :include => [:news], :exclude => [:sports], :either => [..] }
|
64
|
+
# or like: categories => [:news, :sports]
|
65
|
+
def categories_to_params(categories) #:nodoc:
|
66
|
+
if categories.respond_to?(:keys) and categories.respond_to?(:[])
|
67
|
+
s = ""
|
68
|
+
s << categories[:either].map { |c| c.to_s.capitalize }.join("%7C") << '/' if categories[:either]
|
69
|
+
s << categories[:include].map { |c| c.to_s.capitalize }.join("/") << '/' if categories[:include]
|
70
|
+
s << ("-" << categories[:exclude].map { |c| c.to_s.capitalize }.join("/-")) << '/' if categories[:exclude]
|
71
|
+
s
|
72
|
+
else
|
73
|
+
categories.map { |c| c.to_s.capitalize }.join("/") << '/'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Tags defined like: tags => { :include => [:football], :exclude => [:soccer], :either => [:polo, :tennis] }
|
78
|
+
# or tags => [:football, :soccer]
|
79
|
+
def tags_to_params(tags) #:nodoc:
|
80
|
+
if tags.respond_to?(:keys) and tags.respond_to?(:[])
|
81
|
+
s = ""
|
82
|
+
s << tags[:either].map { |t| CGI.escape(t.to_s) }.join("%7C") << '/' if tags[:either]
|
83
|
+
s << tags[:include].map { |t| CGI.escape(t.to_s) }.join("/") << '/' if tags[:include]
|
84
|
+
s << ("-" << tags[:exclude].map { |t| CGI.escape(t.to_s) }.join("/-")) << '/' if tags[:exclude]
|
85
|
+
s
|
86
|
+
else
|
87
|
+
tags.map { |t| CGI.escape(t.to_s) }.join("/") << '/'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
class YouTubeG
|
2
|
+
|
3
|
+
module Upload
|
4
|
+
class UploadError < Exception; end
|
5
|
+
class AuthenticationError < Exception; end
|
6
|
+
|
7
|
+
# require 'youtube_g'
|
8
|
+
#
|
9
|
+
# uploader = YouTubeG::Upload::VideoUpload.new("user", "pass", "dev-key")
|
10
|
+
# uploader.upload File.open("test.m4v"), :title => 'test',
|
11
|
+
# :description => 'cool vid d00d',
|
12
|
+
# :category => 'People',
|
13
|
+
# :keywords => %w[cool blah test]
|
14
|
+
|
15
|
+
class VideoUpload
|
16
|
+
|
17
|
+
def initialize user, pass, dev_key, client_id = 'youtube_g'
|
18
|
+
@user, @pass, @dev_key, @client_id = user, pass, dev_key, client_id
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Upload "data" to youtube, where data is either an IO object or
|
23
|
+
# raw file data.
|
24
|
+
# The hash keys for opts (which specify video info) are as follows:
|
25
|
+
# :mime_type
|
26
|
+
# :filename
|
27
|
+
# :title
|
28
|
+
# :description
|
29
|
+
# :category
|
30
|
+
# :keywords
|
31
|
+
# :private
|
32
|
+
# Specifying :private will make the video private, otherwise it will be public.
|
33
|
+
#
|
34
|
+
# When one of the fields is invalid according to YouTube,
|
35
|
+
# an UploadError will be returned. Its message contains a list of newline separated
|
36
|
+
# errors, containing the key and its error code.
|
37
|
+
#
|
38
|
+
# When the authentication credentials are incorrect, an AuthenticationError will be raised.
|
39
|
+
def upload data, opts = {}
|
40
|
+
data = data.respond_to?(:read) ? data.read : data
|
41
|
+
@opts = { :mime_type => 'video/mp4',
|
42
|
+
:filename => Digest::MD5.hexdigest(data),
|
43
|
+
:title => '',
|
44
|
+
:description => '',
|
45
|
+
:category => '',
|
46
|
+
:keywords => [] }.merge(opts)
|
47
|
+
|
48
|
+
uploadBody = generate_upload_body(boundary, video_xml, data)
|
49
|
+
|
50
|
+
uploadHeader = {
|
51
|
+
"Authorization" => "GoogleLogin auth=#{auth_token}",
|
52
|
+
"X-GData-Client" => "#{@client_id}",
|
53
|
+
"X-GData-Key" => "key=#{@dev_key}",
|
54
|
+
"Slug" => "#{@opts[:filename]}",
|
55
|
+
"Content-Type" => "multipart/related; boundary=#{boundary}",
|
56
|
+
"Content-Length" => "#{uploadBody.length}"
|
57
|
+
}
|
58
|
+
|
59
|
+
Net::HTTP.start(base_url) do |upload|
|
60
|
+
response = upload.post('/feeds/api/users/' << @user << '/uploads', uploadBody, uploadHeader)
|
61
|
+
if response.code.to_i == 403
|
62
|
+
raise AuthenticationError, response.body[/<TITLE>(.+)<\/TITLE>/, 1]
|
63
|
+
elsif response.code.to_i != 201
|
64
|
+
upload_error = ''
|
65
|
+
xml = REXML::Document.new(response.body)
|
66
|
+
errors = xml.elements["//errors"]
|
67
|
+
errors.each do |error|
|
68
|
+
location = error.elements["location"].text[/media:group\/media:(.*)\/text\(\)/,1]
|
69
|
+
code = error.elements["code"].text
|
70
|
+
upload_error << sprintf("%s: %s\r\n", location, code)
|
71
|
+
end
|
72
|
+
raise UploadError, upload_error
|
73
|
+
end
|
74
|
+
xml = REXML::Document.new(response.body)
|
75
|
+
return xml.elements["//id"].text[/videos\/(.+)/, 1]
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def base_url #:nodoc:
|
83
|
+
"uploads.gdata.youtube.com"
|
84
|
+
end
|
85
|
+
|
86
|
+
def boundary #:nodoc:
|
87
|
+
"An43094fu"
|
88
|
+
end
|
89
|
+
|
90
|
+
def auth_token #:nodoc:
|
91
|
+
unless @auth_token
|
92
|
+
http = Net::HTTP.new("www.google.com", 443)
|
93
|
+
http.use_ssl = true
|
94
|
+
body = "Email=#{CGI::escape @user}&Passwd=#{CGI::escape @pass}&service=youtube&source=#{CGI::escape @client_id}"
|
95
|
+
response = http.post("/youtube/accounts/ClientLogin", body, "Content-Type" => "application/x-www-form-urlencoded")
|
96
|
+
raise UploadError, response.body[/Error=(.+)/,1] if response.code.to_i != 200
|
97
|
+
@auth_token = response.body[/Auth=(.+)/, 1]
|
98
|
+
|
99
|
+
end
|
100
|
+
@auth_token
|
101
|
+
end
|
102
|
+
|
103
|
+
def video_xml #:nodoc:
|
104
|
+
video_xml = ''
|
105
|
+
video_xml << '<?xml version="1.0"?>'
|
106
|
+
video_xml << '<entry xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:yt="http://gdata.youtube.com/schemas/2007">'
|
107
|
+
video_xml << '<media:group>'
|
108
|
+
video_xml << '<media:title type="plain">%s</media:title>' % @opts[:title]
|
109
|
+
video_xml << '<media:description type="plain">%s</media:description>' % @opts[:description]
|
110
|
+
video_xml << '<media:keywords>%s</media:keywords>' % @opts[:keywords].join(",")
|
111
|
+
video_xml << '<media:category scheme="http://gdata.youtube.com/schemas/2007/categories.cat">%s</media:category>' % @opts[:category]
|
112
|
+
video_xml << '<yt:private/>' if @opts[:private]
|
113
|
+
video_xml << '</media:group>'
|
114
|
+
video_xml << '</entry>'
|
115
|
+
end
|
116
|
+
|
117
|
+
def generate_upload_body(boundary, video_xml, data) #:nodoc:
|
118
|
+
uploadBody = ""
|
119
|
+
uploadBody << "--#{boundary}\r\n"
|
120
|
+
uploadBody << "Content-Type: application/atom+xml; charset=UTF-8\r\n\r\n"
|
121
|
+
uploadBody << video_xml
|
122
|
+
uploadBody << "\r\n--#{boundary}\r\n"
|
123
|
+
uploadBody << "Content-Type: #{@opts[:mime_type]}\r\nContent-Transfer-Encoding: binary\r\n\r\n"
|
124
|
+
uploadBody << data
|
125
|
+
uploadBody << "\r\n--#{boundary}--\r\n"
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class YouTubeG
|
2
|
+
module Response
|
3
|
+
class VideoSearch < YouTubeG::Record
|
4
|
+
# *String*:: Unique feed identifying url.
|
5
|
+
attr_reader :feed_id
|
6
|
+
|
7
|
+
# *Fixnum*:: Number of results per page.
|
8
|
+
attr_reader :max_result_count
|
9
|
+
|
10
|
+
# *Fixnum*:: 1-based offset index into the full result set.
|
11
|
+
attr_reader :offset
|
12
|
+
|
13
|
+
# *Fixnum*:: Total number of results available for the original request.
|
14
|
+
attr_reader :total_result_count
|
15
|
+
|
16
|
+
# *Time*:: Date and time at which the feed was last updated
|
17
|
+
attr_reader :updated_at
|
18
|
+
|
19
|
+
# *Array*:: Array of YouTubeG::Model::Video records
|
20
|
+
attr_reader :videos
|
21
|
+
|
22
|
+
def current_page
|
23
|
+
((offset - 1) / max_result_count) + 1
|
24
|
+
end
|
25
|
+
|
26
|
+
# current_page + 1 or nil if there is no next page
|
27
|
+
def next_page
|
28
|
+
current_page < total_pages ? (current_page + 1) : nil
|
29
|
+
end
|
30
|
+
|
31
|
+
# current_page - 1 or nil if there is no previous page
|
32
|
+
def previous_page
|
33
|
+
current_page > 1 ? (current_page - 1) : nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def total_pages
|
37
|
+
(total_result_count / max_result_count.to_f).ceil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/test/test_client.rb
ADDED
@@ -0,0 +1,262 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
require 'youtube_g'
|
6
|
+
|
7
|
+
class TestClient < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
@client = YouTubeG::Client.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_should_respond_to_a_basic_query
|
13
|
+
response = @client.videos_by(:query => "penguin")
|
14
|
+
|
15
|
+
assert_equal "http://gdata.youtube.com/feeds/api/videos", response.feed_id
|
16
|
+
assert_equal 25, response.max_result_count
|
17
|
+
assert_equal 25, response.videos.length
|
18
|
+
assert_equal 1, response.offset
|
19
|
+
assert(response.total_result_count > 100)
|
20
|
+
assert_instance_of Time, response.updated_at
|
21
|
+
|
22
|
+
response.videos.each { |v| assert_valid_video v }
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_should_respond_to_a_basic_query_with_offset_and_max_results
|
26
|
+
response = @client.videos_by(:query => "penguin", :offset => 15, :max_results => 30)
|
27
|
+
|
28
|
+
assert_equal "http://gdata.youtube.com/feeds/api/videos", response.feed_id
|
29
|
+
assert_equal 30, response.max_result_count
|
30
|
+
assert_equal 30, response.videos.length
|
31
|
+
assert_equal 15, response.offset
|
32
|
+
assert(response.total_result_count > 100)
|
33
|
+
assert_instance_of Time, response.updated_at
|
34
|
+
|
35
|
+
response.videos.each { |v| assert_valid_video v }
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_should_respond_to_a_basic_query_with_paging
|
39
|
+
response = @client.videos_by(:query => "penguin")
|
40
|
+
assert_equal "http://gdata.youtube.com/feeds/api/videos", response.feed_id
|
41
|
+
assert_equal 25, response.max_result_count
|
42
|
+
assert_equal 1, response.offset
|
43
|
+
|
44
|
+
response = @client.videos_by(:query => "penguin", :page => 2)
|
45
|
+
assert_equal "http://gdata.youtube.com/feeds/api/videos", response.feed_id
|
46
|
+
assert_equal 25, response.max_result_count
|
47
|
+
assert_equal 26, response.offset
|
48
|
+
|
49
|
+
response2 = @client.videos_by(:query => "penguin", :page => 3)
|
50
|
+
assert_equal "http://gdata.youtube.com/feeds/api/videos", response2.feed_id
|
51
|
+
assert_equal 25, response2.max_result_count
|
52
|
+
assert_equal 51, response2.offset
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_should_get_videos_for_multiword_metasearch_query
|
56
|
+
response = @client.videos_by(:query => 'christina ricci')
|
57
|
+
|
58
|
+
assert_equal "http://gdata.youtube.com/feeds/api/videos", response.feed_id
|
59
|
+
assert_equal 25, response.max_result_count
|
60
|
+
assert_equal 25, response.videos.length
|
61
|
+
assert_equal 1, response.offset
|
62
|
+
assert(response.total_result_count > 100)
|
63
|
+
assert_instance_of Time, response.updated_at
|
64
|
+
|
65
|
+
response.videos.each { |v| assert_valid_video v }
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_should_handle_video_not_yet_viewed
|
69
|
+
response = @client.videos_by(:query => "YnqHZDh_t2Q")
|
70
|
+
|
71
|
+
assert_equal 1, response.videos.length
|
72
|
+
response.videos.each { |v| assert_valid_video v }
|
73
|
+
end
|
74
|
+
|
75
|
+
# TODO: this doesn't work because the returned feed is in an unknown format
|
76
|
+
# def test_should_get_video_for_search_by_video_id
|
77
|
+
# response = @client.videos_by(:video_id => "T7YazwP8GtY")
|
78
|
+
# response.videos.each { |v| assert_valid_video v }
|
79
|
+
# end
|
80
|
+
|
81
|
+
def test_should_get_videos_for_one_tag
|
82
|
+
response = @client.videos_by(:tags => ['panther'])
|
83
|
+
response.videos.each { |v| assert_valid_video v }
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_should_get_videos_for_multiple_tags
|
87
|
+
response = @client.videos_by(:tags => ['tiger', 'leopard'])
|
88
|
+
response.videos.each { |v| assert_valid_video v }
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_should_get_videos_for_one_category
|
92
|
+
response = @client.videos_by(:categories => [:news])
|
93
|
+
response.videos.each { |v| assert_valid_video v }
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_should_get_videos_for_multiple_categories
|
97
|
+
response = @client.videos_by(:categories => [:news, :sports])
|
98
|
+
response.videos.each { |v| assert_valid_video v }
|
99
|
+
end
|
100
|
+
|
101
|
+
# TODO: Need to do more specific checking in these tests
|
102
|
+
# Currently, if a URL is valid, and videos are found, the test passes regardless of search criteria
|
103
|
+
def test_should_get_videos_for_categories_and_tags
|
104
|
+
response = @client.videos_by(:categories => [:news, :sports], :tags => ['soccer', 'football'])
|
105
|
+
response.videos.each { |v| assert_valid_video v }
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_should_get_most_viewed_videos
|
109
|
+
response = @client.videos_by(:most_viewed)
|
110
|
+
response.videos.each { |v| assert_valid_video v }
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_should_get_top_rated_videos_for_today
|
114
|
+
response = @client.videos_by(:top_rated, :time => :today)
|
115
|
+
response.videos.each { |v| assert_valid_video v }
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_should_get_videos_for_categories_and_tags_with_category_boolean_operators
|
119
|
+
response = @client.videos_by(:categories => { :either => [:news, :sports], :exclude => [:comedy] },
|
120
|
+
:tags => { :include => ['football'], :exclude => ['soccer'] })
|
121
|
+
response.videos.each { |v| assert_valid_video v }
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_should_get_videos_for_categories_and_tags_with_tag_boolean_operators
|
125
|
+
response = @client.videos_by(:categories => { :either => [:news, :sports], :exclude => [:comedy] },
|
126
|
+
:tags => { :either => ['football', 'soccer', 'polo'] })
|
127
|
+
response.videos.each { |v| assert_valid_video v }
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_should_get_videos_by_user
|
131
|
+
response = @client.videos_by(:user => 'liz')
|
132
|
+
response.videos.each { |v| assert_valid_video v }
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_should_get_videos_by_user_with_pagination_and_ordering
|
136
|
+
response = @client.videos_by(:user => 'liz', :page => 2, :per_page => '2', :order_by => 'published')
|
137
|
+
response.videos.each { |v| assert_valid_video v }
|
138
|
+
assert_equal 3, response.offset
|
139
|
+
assert_equal 2, response.max_result_count
|
140
|
+
end
|
141
|
+
|
142
|
+
# HTTP 403 Error
|
143
|
+
# def test_should_get_favorite_videos_by_user
|
144
|
+
# response = @client.videos_by(:favorites, :user => 'liz')
|
145
|
+
# response.videos.each { |v| assert_valid_video v }
|
146
|
+
# end
|
147
|
+
|
148
|
+
def test_should_get_videos_for_query_search_with_categories_excluded
|
149
|
+
video = @client.video_by("EkF4JD2rO3Q")
|
150
|
+
assert_equal "<object width=\"425\" height=\"350\">\n <param name=\"movie\" value=\"http://www.youtube.com/v/EkF4JD2rO3Q\"></param>\n <param name=\"wmode\" value=\"transparent\"></param>\n <embed src=\"http://www.youtube.com/v/EkF4JD2rO3Q\" type=\"application/x-shockwave-flash\" \n wmode=\"transparent\" width=\"425\" height=\"350\"></embed>\n</object>\n", video.embed_html
|
151
|
+
assert_valid_video video
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_should_disable_debug_if_debug_is_set_to_false
|
155
|
+
@client = YouTubeG::Client.new
|
156
|
+
assert_nil @client.logger
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_should_enable_logger_if_debug_is_true
|
160
|
+
@client = YouTubeG::Client.new(true)
|
161
|
+
assert_not_nil @client.logger
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_should_determine_if_nonembeddable_video_is_embeddable
|
165
|
+
response = @client.videos_by(:query => "avril lavigne girlfriend")
|
166
|
+
|
167
|
+
video = response.videos.first
|
168
|
+
assert !video.embeddable?
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_should_determine_if_embeddable_video_is_embeddable
|
172
|
+
response = @client.videos_by(:query => "strongbad")
|
173
|
+
|
174
|
+
video = response.videos.first
|
175
|
+
assert video.embeddable?
|
176
|
+
end
|
177
|
+
|
178
|
+
def test_should_retrieve_video_by_id
|
179
|
+
video = @client.video_by("http://gdata.youtube.com/feeds/videos/EkF4JD2rO3Q")
|
180
|
+
assert_valid_video video
|
181
|
+
|
182
|
+
video = @client.video_by("EkF4JD2rO3Q")
|
183
|
+
assert_valid_video video
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
|
188
|
+
def assert_valid_video (video)
|
189
|
+
# pp video
|
190
|
+
|
191
|
+
# check general attributes
|
192
|
+
assert_instance_of YouTubeG::Model::Video, video
|
193
|
+
assert_instance_of Fixnum, video.duration
|
194
|
+
assert(video.duration > 0)
|
195
|
+
#assert_match(/^<div style=.*?<\/div>/m, video.html_content)
|
196
|
+
assert_instance_of String, video.html_content
|
197
|
+
|
198
|
+
# validate media content records
|
199
|
+
video.media_content.each do |media_content|
|
200
|
+
# http://www.youtube.com/v/IHVaXG1thXM
|
201
|
+
assert_valid_url media_content.url
|
202
|
+
assert(media_content.duration > 0)
|
203
|
+
assert_instance_of YouTubeG::Model::Video::Format, media_content.format
|
204
|
+
assert_instance_of String, media_content.mime_type
|
205
|
+
assert_match(/^[^\/]+\/[^\/]+$/, media_content.mime_type)
|
206
|
+
end
|
207
|
+
|
208
|
+
default_content = video.default_media_content
|
209
|
+
if default_content
|
210
|
+
assert_instance_of YouTubeG::Model::Content, default_content
|
211
|
+
assert default_content.is_default?
|
212
|
+
end
|
213
|
+
|
214
|
+
# validate keywords
|
215
|
+
video.keywords.each { |kw| assert_instance_of(String, kw) }
|
216
|
+
|
217
|
+
# http://www.youtube.com/watch?v=IHVaXG1thXM
|
218
|
+
assert_valid_url video.player_url
|
219
|
+
assert_instance_of Time, video.published_at
|
220
|
+
|
221
|
+
# validate optionally-present rating
|
222
|
+
if video.rating
|
223
|
+
assert_instance_of YouTubeG::Model::Rating, video.rating
|
224
|
+
assert_instance_of Float, video.rating.average
|
225
|
+
assert_instance_of Fixnum, video.rating.max
|
226
|
+
assert_instance_of Fixnum, video.rating.min
|
227
|
+
assert_instance_of Fixnum, video.rating.rater_count
|
228
|
+
end
|
229
|
+
|
230
|
+
# validate thumbnails
|
231
|
+
assert(video.thumbnails.size > 0)
|
232
|
+
|
233
|
+
assert_not_nil video.title
|
234
|
+
assert_instance_of String, video.title
|
235
|
+
assert(video.title.length > 0)
|
236
|
+
|
237
|
+
assert_instance_of Time, video.updated_at
|
238
|
+
# http://gdata.youtube.com/feeds/videos/IHVaXG1thXM
|
239
|
+
assert_valid_url video.video_id
|
240
|
+
assert_instance_of Fixnum, video.view_count
|
241
|
+
|
242
|
+
# validate author
|
243
|
+
assert_instance_of YouTubeG::Model::Author, video.author
|
244
|
+
assert_instance_of String, video.author.name
|
245
|
+
assert(video.author.name.length > 0)
|
246
|
+
assert_valid_url video.author.uri
|
247
|
+
|
248
|
+
# validate categories
|
249
|
+
video.categories.each do |cat|
|
250
|
+
assert_instance_of YouTubeG::Model::Category, cat
|
251
|
+
assert_instance_of String, cat.label
|
252
|
+
assert_instance_of String, cat.term
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def assert_valid_url (url)
|
257
|
+
URI::parse(url)
|
258
|
+
return true
|
259
|
+
rescue
|
260
|
+
return false
|
261
|
+
end
|
262
|
+
end
|