msp-youtube-g 0.4.6 → 0.4.7
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 +3 -1
- data/Manifest.txt +8 -3
- data/TODO.txt +3 -3
- data/lib/youtube_g.rb +3 -2
- data/lib/youtube_g/model/video.rb +10 -1
- data/lib/youtube_g/parser.rb +60 -13
- data/lib/youtube_g/request/video_upload.rb +12 -15
- metadata +1 -1
- data/test/test_client.rb +0 -226
- data/test/test_video.rb +0 -30
- data/test/test_video_search.rb +0 -118
data/History.txt
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
== trunk
|
2
|
-
|
2
|
+
* Move network dependent tests to integration-test [msp]
|
3
|
+
* Create a parser and a model for upload errors [msp]
|
4
|
+
* Stub driven tests for VideoFeedParser, VideosFeedParser, UploadErrorParser [msp]
|
3
5
|
* Add error-handling for video upload errors. [FiXato]
|
4
6
|
* Add error-handling for authentication errors from YouTube during video upload. [FiXato]
|
5
7
|
* Add support for making videos private upon video upload. [FiXato]
|
data/Manifest.txt
CHANGED
@@ -15,11 +15,16 @@ lib/youtube_g/model/rating.rb
|
|
15
15
|
lib/youtube_g/model/thumbnail.rb
|
16
16
|
lib/youtube_g/model/user.rb
|
17
17
|
lib/youtube_g/model/video.rb
|
18
|
+
lib/youtube_g/model/upload_error.rb
|
18
19
|
lib/youtube_g/parser.rb
|
19
20
|
lib/youtube_g/record.rb
|
20
21
|
lib/youtube_g/request/video_search.rb
|
21
22
|
lib/youtube_g/request/video_upload.rb
|
22
23
|
lib/youtube_g/response/video_search.rb
|
23
|
-
test/test_client.rb
|
24
|
-
test/test_video.rb
|
25
|
-
test/test_video_search.rb
|
24
|
+
integration-test/test_client.rb
|
25
|
+
integration-test/test_video.rb
|
26
|
+
integration-test/test_video_search.rb
|
27
|
+
test/test_parser.rb
|
28
|
+
test/test_upload.rb
|
29
|
+
test/search.xml
|
30
|
+
test/upload.xml
|
data/TODO.txt
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
[ ] stub out http request/response cycle for tests
|
1
|
+
[ ] stub out http request/response cycle for tests (partially done in test_parser, need to do the same for pre-existing tests [msp])
|
2
2
|
[ ] consider defaulting the client to no-logger, rather than outputting to STDOUT.
|
3
3
|
[ ] allow specifying values as single items where you don't need to wrap in a list, e.g. :tags => :chickens instead of :tags => [ 'chickens' ]
|
4
4
|
[ ] make sure symbols will work as well as tags everywhere (again, :tags => :chickens is same as :tags => 'chickens')
|
5
5
|
[ ] figure out better structure for class/file (either rename request/video_search.rb or split into one class per file again)
|
6
6
|
[ ] restore spaces after method def names
|
7
|
-
[ ] use a proxy for testing with static sample result xml so we have repeatable tests
|
7
|
+
[ ] use a proxy for testing with static sample result xml so we have repeatable tests (see above [msp])
|
8
8
|
[ ] Clean up tests using Shoulda to define contexts
|
9
9
|
[ ] Consolidate requires
|
10
10
|
[ ] Allow :category and :categories for query DSL
|
@@ -15,4 +15,4 @@
|
|
15
15
|
[ ] Profile feed parsing
|
16
16
|
[ ] Playlist feeds
|
17
17
|
[ ] User subscriptions
|
18
|
-
[ ] Video comments
|
18
|
+
[ ] Video comments
|
data/lib/youtube_g.rb
CHANGED
@@ -9,11 +9,12 @@ require File.dirname(__FILE__) + '/youtube_g/model/playlist'
|
|
9
9
|
require File.dirname(__FILE__) + '/youtube_g/model/rating'
|
10
10
|
require File.dirname(__FILE__) + '/youtube_g/model/thumbnail'
|
11
11
|
require File.dirname(__FILE__) + '/youtube_g/model/user'
|
12
|
-
require File.dirname(__FILE__) + '/youtube_g/model/video'
|
12
|
+
require File.dirname(__FILE__) + '/youtube_g/model/video'
|
13
|
+
require File.dirname(__FILE__) + '/youtube_g/model/upload_error'
|
13
14
|
require File.dirname(__FILE__) + '/youtube_g/request/video_upload'
|
14
15
|
require File.dirname(__FILE__) + '/youtube_g/request/video_search'
|
15
16
|
require File.dirname(__FILE__) + '/youtube_g/response/video_search'
|
16
17
|
|
17
18
|
class YouTubeG
|
18
|
-
VERSION = '0.4.
|
19
|
+
VERSION = '0.4.7'
|
19
20
|
end
|
@@ -34,14 +34,23 @@ class YouTubeG
|
|
34
34
|
SWF = YouTubeG::Model::Video::Format.new(5, :swf)
|
35
35
|
|
36
36
|
THREE_GPP = YouTubeG::Model::Video::Format.new(6, :three_gpp)
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# Used in video uploads only to check the state of the upload
|
41
|
+
class AppControl < YouTubeG::Record
|
42
|
+
attr_reader :draft
|
43
|
+
attr_reader :state
|
37
44
|
end
|
38
|
-
|
45
|
+
|
39
46
|
attr_reader :duration
|
40
47
|
attr_reader :noembed
|
41
48
|
attr_reader :position
|
42
49
|
attr_reader :racy
|
43
50
|
attr_reader :statistics
|
44
51
|
|
52
|
+
attr_reader :app_control
|
53
|
+
|
45
54
|
attr_reader :video_id
|
46
55
|
attr_reader :published_at
|
47
56
|
attr_reader :updated_at
|
data/lib/youtube_g/parser.rb
CHANGED
@@ -3,17 +3,55 @@ require 'open-uri'
|
|
3
3
|
require 'rexml/document'
|
4
4
|
|
5
5
|
class YouTubeG
|
6
|
-
module Parser
|
7
|
-
class
|
8
|
-
|
9
|
-
|
6
|
+
module Parser
|
7
|
+
class FeedParserError < Exception; end
|
8
|
+
|
9
|
+
class FeedParser
|
10
|
+
attr_reader :url_based
|
11
|
+
alias :url_based? :url_based
|
12
|
+
|
13
|
+
def initialize(arg)
|
14
|
+
@url_based = assert_valid_url(arg)
|
15
|
+
@content = arg
|
10
16
|
end
|
11
17
|
|
18
|
+
def parse
|
19
|
+
if @url_based
|
20
|
+
parse_content open(@content).read
|
21
|
+
else
|
22
|
+
parse_content @content
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def assert_valid_url (url)
|
28
|
+
URI::parse(url)
|
29
|
+
return true
|
30
|
+
rescue
|
31
|
+
return false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class UploadErrorParser
|
36
|
+
def initialize(xml)
|
37
|
+
raise YouTubeG::Parser::FeedParserError.new("You must pass some xml") if xml == ''
|
38
|
+
@doc = REXML::Document.new(xml)
|
39
|
+
end
|
40
|
+
|
12
41
|
def parse
|
13
|
-
|
14
|
-
|
42
|
+
upload_errors = []
|
43
|
+
|
44
|
+
@doc.elements.each("//error") do |error|
|
45
|
+
location = error.elements["location"].text #[/media:group\/media:(.*)\/text\(\)/,1]
|
46
|
+
code = error.elements["code"].text
|
47
|
+
domain = error.elements["domain"].text
|
48
|
+
upload_errors << YouTubeG::Model::UploadError.new(:location => location, :code => code, :domain => domain)
|
49
|
+
end
|
50
|
+
|
51
|
+
return upload_errors
|
52
|
+
end
|
15
53
|
end
|
16
|
-
|
54
|
+
|
17
55
|
class VideoFeedParser < FeedParser
|
18
56
|
|
19
57
|
def parse_content(content)
|
@@ -27,7 +65,15 @@ class YouTubeG
|
|
27
65
|
def parse_entry(entry)
|
28
66
|
video_id = entry.elements["id"].text
|
29
67
|
published_at = Time.parse(entry.elements["published"].text)
|
30
|
-
updated_at = Time.parse(entry.elements["updated"].text)
|
68
|
+
updated_at = Time.parse(entry.elements["updated"].text)
|
69
|
+
|
70
|
+
app_control_element = entry.elements["app:control"]
|
71
|
+
app_contrlol = nil
|
72
|
+
if app_control_element
|
73
|
+
app_control = YouTubeG::Model::Video::AppControl.new(
|
74
|
+
:draft => app_control_element.elements["app:draft"].text,
|
75
|
+
:state => app_control_element.elements["yt:state"].attributes["name"])
|
76
|
+
end
|
31
77
|
|
32
78
|
# parse the category and keyword lists
|
33
79
|
categories = []
|
@@ -61,14 +107,14 @@ class YouTubeG
|
|
61
107
|
|
62
108
|
media_group = entry.elements["media:group"]
|
63
109
|
description = media_group.elements["media:description"].text
|
64
|
-
duration = media_group.elements["yt:duration"].attributes["seconds"].to_i
|
110
|
+
duration = media_group.elements["yt:duration"].attributes["seconds"].to_i if media_group.elements["yt:duration"]
|
65
111
|
|
66
112
|
media_content = []
|
67
113
|
media_group.elements.each("media:content") do |mce|
|
68
114
|
media_content << parse_media_content(mce)
|
69
115
|
end
|
70
116
|
|
71
|
-
player_url = media_group.elements["media:player"].attributes["url"]
|
117
|
+
player_url = media_group.elements["media:player"].attributes["url"] if media_group.elements["media:player"]
|
72
118
|
|
73
119
|
# parse thumbnails
|
74
120
|
thumbnails = []
|
@@ -99,7 +145,8 @@ class YouTubeG
|
|
99
145
|
YouTubeG::Model::Video.new(
|
100
146
|
:video_id => video_id,
|
101
147
|
:published_at => published_at,
|
102
|
-
:updated_at => updated_at,
|
148
|
+
:updated_at => updated_at,
|
149
|
+
:app_control => app_control,
|
103
150
|
:categories => categories,
|
104
151
|
:keywords => keywords,
|
105
152
|
:title => title,
|
@@ -131,7 +178,7 @@ class YouTubeG
|
|
131
178
|
:mime_type => mime_type,
|
132
179
|
:default => default)
|
133
180
|
end
|
134
|
-
end
|
181
|
+
end
|
135
182
|
|
136
183
|
class VideosFeedParser < VideoFeedParser
|
137
184
|
|
@@ -160,6 +207,6 @@ class YouTubeG
|
|
160
207
|
:videos => videos)
|
161
208
|
end
|
162
209
|
end
|
163
|
-
|
210
|
+
|
164
211
|
end
|
165
212
|
end
|
@@ -20,6 +20,7 @@ class YouTubeG
|
|
20
20
|
class VideoUpload
|
21
21
|
|
22
22
|
attr_accessor :auth_token
|
23
|
+
|
23
24
|
def initialize user, pass, dev_key, client_id = 'youtube_g', auth_token = nil
|
24
25
|
@user, @pass, @dev_key, @client_id, @auth_token = user, pass, dev_key, client_id, auth_token
|
25
26
|
end
|
@@ -30,7 +31,7 @@ class YouTubeG
|
|
30
31
|
Logger.new(STDOUT)
|
31
32
|
else
|
32
33
|
eval(get_rails_default_logger_name)
|
33
|
-
end
|
34
|
+
end
|
34
35
|
end
|
35
36
|
|
36
37
|
def get_rails_default_logger_name
|
@@ -81,22 +82,18 @@ class YouTubeG
|
|
81
82
|
|
82
83
|
Net::HTTP.start(base_url) do |upload|
|
83
84
|
response = upload.post(direct_upload_url, upload_body, upload_header)
|
84
|
-
|
85
|
+
# todo parse this out also
|
86
|
+
if response.code.to_i == 403
|
85
87
|
raise AuthenticationError, response.body[/<TITLE>(.+)<\/TITLE>/, 1]
|
86
|
-
elsif response.code.to_i != 201
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
location = error.elements["location"].text[/media:group\/media:(.*)\/text\(\)/,1]
|
92
|
-
code = error.elements["code"].text
|
93
|
-
upload_error << sprintf("%s: %s\r\n", location, code)
|
94
|
-
end
|
95
|
-
raise UploadError, upload_error
|
96
|
-
end
|
88
|
+
elsif response.code.to_i != 201
|
89
|
+
upload_errors = YouTubeG::Parser::UploadErrorParser.new(response.body).parse
|
90
|
+
raise UploadError, upload_errors.inspect
|
91
|
+
end
|
92
|
+
return YouTubeG::Parser::VideoFeedParser.new(response.body).parse
|
97
93
|
end
|
98
94
|
|
99
|
-
end
|
95
|
+
end
|
96
|
+
|
100
97
|
|
101
98
|
private
|
102
99
|
|
@@ -115,7 +112,7 @@ class YouTubeG
|
|
115
112
|
body = "Email=#{CGI::escape @user}&Passwd=#{CGI::escape @pass}&service=youtube&source=#{CGI::escape @client_id}"
|
116
113
|
logger.debug("auth body [#{body}]")
|
117
114
|
response = http.post("/youtube/accounts/ClientLogin", body, "Content-Type" => "application/x-www-form-urlencoded")
|
118
|
-
raise UploadError,
|
115
|
+
raise UploadError, response.body[/Error=(.+)/,1] if response.code.to_i != 200
|
119
116
|
logger.debug("response.body [#{response.body}]")
|
120
117
|
@auth_token = response.body[/Auth=(.+)/, 1]
|
121
118
|
|
metadata
CHANGED
data/test/test_client.rb
DELETED
@@ -1,226 +0,0 @@
|
|
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?start-index=1&max-results=25&vq=penguin", 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_get_videos_for_multiword_metasearch_query
|
26
|
-
response = @client.videos_by(:query => 'christina ricci')
|
27
|
-
|
28
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos?start-index=1&max-results=25&vq=christina+ricci", response.feed_id
|
29
|
-
assert_equal 25, response.max_result_count
|
30
|
-
assert_equal 25, response.videos.length
|
31
|
-
assert_equal 1, 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_handle_video_not_yet_viewed
|
39
|
-
response = @client.videos_by(:query => "YnqHZDh_t2Q")
|
40
|
-
|
41
|
-
assert_equal 1, response.videos.length
|
42
|
-
response.videos.each { |v| assert_valid_video v }
|
43
|
-
end
|
44
|
-
|
45
|
-
# TODO: this doesn't work because the returned feed is in an unknown format
|
46
|
-
# def test_should_get_video_for_search_by_video_id
|
47
|
-
# response = @client.videos_by(:video_id => "T7YazwP8GtY")
|
48
|
-
# response.videos.each { |v| assert_valid_video v }
|
49
|
-
# end
|
50
|
-
|
51
|
-
def test_should_get_videos_for_one_tag
|
52
|
-
response = @client.videos_by(:tags => ['panther'])
|
53
|
-
response.videos.each { |v| assert_valid_video v }
|
54
|
-
end
|
55
|
-
|
56
|
-
def test_should_get_videos_for_multiple_tags
|
57
|
-
response = @client.videos_by(:tags => ['tiger', 'leopard'])
|
58
|
-
response.videos.each { |v| assert_valid_video v }
|
59
|
-
end
|
60
|
-
|
61
|
-
def test_should_get_videos_for_one_category
|
62
|
-
response = @client.videos_by(:categories => [:news])
|
63
|
-
response.videos.each { |v| assert_valid_video v }
|
64
|
-
end
|
65
|
-
|
66
|
-
def test_should_get_videos_for_multiple_categories
|
67
|
-
response = @client.videos_by(:categories => [:news, :sports])
|
68
|
-
response.videos.each { |v| assert_valid_video v }
|
69
|
-
end
|
70
|
-
|
71
|
-
# TODO: Need to do more specific checking in these tests
|
72
|
-
# Currently, if a URL is valid, and videos are found, the test passes regardless of search criteria
|
73
|
-
def test_should_get_videos_for_categories_and_tags
|
74
|
-
response = @client.videos_by(:categories => [:news, :sports], :tags => ['soccer', 'football'])
|
75
|
-
response.videos.each { |v| assert_valid_video v }
|
76
|
-
end
|
77
|
-
|
78
|
-
def test_should_get_most_viewed_videos
|
79
|
-
response = @client.videos_by(:most_viewed)
|
80
|
-
response.videos.each { |v| assert_valid_video v }
|
81
|
-
end
|
82
|
-
|
83
|
-
def test_should_get_top_rated_videos_for_today
|
84
|
-
response = @client.videos_by(:top_rated, :time => :today)
|
85
|
-
response.videos.each { |v| assert_valid_video v }
|
86
|
-
end
|
87
|
-
|
88
|
-
def test_should_get_videos_for_categories_and_tags_with_category_boolean_operators
|
89
|
-
response = @client.videos_by(:categories => { :either => [:news, :sports], :exclude => [:comedy] },
|
90
|
-
:tags => { :include => ['football'], :exclude => ['soccer'] })
|
91
|
-
response.videos.each { |v| assert_valid_video v }
|
92
|
-
end
|
93
|
-
|
94
|
-
def test_should_get_videos_for_categories_and_tags_with_tag_boolean_operators
|
95
|
-
response = @client.videos_by(:categories => { :either => [:news, :sports], :exclude => [:comedy] },
|
96
|
-
:tags => { :either => ['football', 'soccer', 'polo'] })
|
97
|
-
response.videos.each { |v| assert_valid_video v }
|
98
|
-
end
|
99
|
-
|
100
|
-
def test_should_get_videos_by_user
|
101
|
-
response = @client.videos_by(:user => 'liz')
|
102
|
-
response.videos.each { |v| assert_valid_video v }
|
103
|
-
end
|
104
|
-
|
105
|
-
# HTTP 403 Error
|
106
|
-
# def test_should_get_favorite_videos_by_user
|
107
|
-
# response = @client.videos_by(:favorites, :user => 'liz')
|
108
|
-
# response.videos.each { |v| assert_valid_video v }
|
109
|
-
# end
|
110
|
-
|
111
|
-
def test_should_get_videos_for_query_search_with_categories_excluded
|
112
|
-
response = @client.videos_by(:query => 'bench press', :categories => { :exclude => [:comedy, :entertainment] },
|
113
|
-
:max_results => 10)
|
114
|
-
assert_equal "<object width=\"425\" height=\"350\">\n <param name=\"movie\" value=\"http://www.youtube.com/v/BlDWdfTAx8o\"></param>\n <param name=\"wmode\" value=\"transparent\"></param>\n <embed src=\"http://www.youtube.com/v/BlDWdfTAx8o\" type=\"application/x-shockwave-flash\" \n wmode=\"transparent\" width=\"425\" height=\"350\"></embed>\n</object>\n", response.videos.first.embed_html
|
115
|
-
response.videos.each { |v| assert_valid_video v }
|
116
|
-
end
|
117
|
-
|
118
|
-
def test_should_be_able_to_pass_in_logger
|
119
|
-
@client = YouTubeG::Client.new(Logger.new(STDOUT))
|
120
|
-
assert_not_nil @client.logger
|
121
|
-
end
|
122
|
-
|
123
|
-
def test_should_create_logger_if_not_passed_in
|
124
|
-
@client = YouTubeG::Client.new
|
125
|
-
assert_not_nil @client.logger
|
126
|
-
end
|
127
|
-
|
128
|
-
def test_should_determine_if_nonembeddable_video_is_embeddable
|
129
|
-
response = @client.videos_by(:query => "avril lavigne girlfriend")
|
130
|
-
|
131
|
-
video = response.videos.first
|
132
|
-
assert !video.can_embed?
|
133
|
-
end
|
134
|
-
|
135
|
-
def test_should_determine_if_embeddable_video_is_embeddable
|
136
|
-
response = @client.videos_by(:query => "strongbad")
|
137
|
-
|
138
|
-
video = response.videos.first
|
139
|
-
assert video.can_embed?
|
140
|
-
end
|
141
|
-
|
142
|
-
def test_should_retrieve_video_by_id
|
143
|
-
video = @client.video_by("http://gdata.youtube.com/feeds/videos/EkF4JD2rO3Q")
|
144
|
-
assert_valid_video video
|
145
|
-
|
146
|
-
video = @client.video_by("EkF4JD2rO3Q")
|
147
|
-
assert_valid_video video
|
148
|
-
end
|
149
|
-
|
150
|
-
private
|
151
|
-
|
152
|
-
def assert_valid_video (video)
|
153
|
-
# pp video
|
154
|
-
|
155
|
-
# check general attributes
|
156
|
-
assert_instance_of YouTubeG::Model::Video, video
|
157
|
-
assert_instance_of Fixnum, video.duration
|
158
|
-
assert(video.duration > 0)
|
159
|
-
#assert_match(/^<div style=.*?<\/div>/m, video.html_content)
|
160
|
-
assert_instance_of String, video.html_content
|
161
|
-
|
162
|
-
# validate media content records
|
163
|
-
video.media_content.each do |media_content|
|
164
|
-
# http://www.youtube.com/v/IHVaXG1thXM
|
165
|
-
assert_valid_url media_content.url
|
166
|
-
assert(media_content.duration > 0)
|
167
|
-
assert_instance_of YouTubeG::Model::Video::Format, media_content.format
|
168
|
-
assert_instance_of String, media_content.mime_type
|
169
|
-
assert_match(/^[^\/]+\/[^\/]+$/, media_content.mime_type)
|
170
|
-
end
|
171
|
-
|
172
|
-
default_content = video.default_media_content
|
173
|
-
if default_content
|
174
|
-
assert_instance_of YouTubeG::Model::Content, default_content
|
175
|
-
assert default_content.is_default?
|
176
|
-
end
|
177
|
-
|
178
|
-
# validate keywords
|
179
|
-
video.keywords.each { |kw| assert_instance_of(String, kw) }
|
180
|
-
|
181
|
-
# http://www.youtube.com/watch?v=IHVaXG1thXM
|
182
|
-
assert_valid_url video.player_url
|
183
|
-
assert_instance_of Time, video.published_at
|
184
|
-
|
185
|
-
# validate optionally-present rating
|
186
|
-
if video.rating
|
187
|
-
assert_instance_of YouTubeG::Model::Rating, video.rating
|
188
|
-
assert_instance_of Float, video.rating.average
|
189
|
-
assert_instance_of Fixnum, video.rating.max
|
190
|
-
assert_instance_of Fixnum, video.rating.min
|
191
|
-
assert_instance_of Fixnum, video.rating.rater_count
|
192
|
-
end
|
193
|
-
|
194
|
-
# validate thumbnails
|
195
|
-
assert(video.thumbnails.size > 0)
|
196
|
-
|
197
|
-
assert_not_nil video.title
|
198
|
-
assert_instance_of String, video.title
|
199
|
-
assert(video.title.length > 0)
|
200
|
-
|
201
|
-
assert_instance_of Time, video.updated_at
|
202
|
-
# http://gdata.youtube.com/feeds/videos/IHVaXG1thXM
|
203
|
-
assert_valid_url video.video_id
|
204
|
-
assert_instance_of Fixnum, video.view_count
|
205
|
-
|
206
|
-
# validate author
|
207
|
-
assert_instance_of YouTubeG::Model::Author, video.author
|
208
|
-
assert_instance_of String, video.author.name
|
209
|
-
assert(video.author.name.length > 0)
|
210
|
-
assert_valid_url video.author.uri
|
211
|
-
|
212
|
-
# validate categories
|
213
|
-
video.categories.each do |cat|
|
214
|
-
assert_instance_of YouTubeG::Model::Category, cat
|
215
|
-
assert_instance_of String, cat.label
|
216
|
-
assert_instance_of String, cat.term
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
def assert_valid_url (url)
|
221
|
-
URI::parse(url)
|
222
|
-
return true
|
223
|
-
rescue
|
224
|
-
return false
|
225
|
-
end
|
226
|
-
end
|
data/test/test_video.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'test/unit'
|
3
|
-
require 'pp'
|
4
|
-
|
5
|
-
require 'youtube_g'
|
6
|
-
|
7
|
-
class TestVideo < Test::Unit::TestCase
|
8
|
-
def test_should_extract_unique_id_from_video_id
|
9
|
-
video = YouTubeG::Model::Video.new(:video_id => "http://gdata.youtube.com/feeds/videos/ZTUVgYoeN_o")
|
10
|
-
assert_equal "ZTUVgYoeN_o", video.unique_id
|
11
|
-
end
|
12
|
-
|
13
|
-
def test_should_extract_unique_id_with_hypen_from_video_id
|
14
|
-
video = YouTubeG::Model::Video.new(:video_id => "http://gdata.youtube.com/feeds/videos/BDqs-OZWw9o")
|
15
|
-
assert_equal "BDqs-OZWw9o", video.unique_id
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_should_have_related_videos
|
19
|
-
video = YouTubeG::Model::Video.new(:video_id => "http://gdata.youtube.com/feeds/videos/BDqs-OZWw9o")
|
20
|
-
response = video.related
|
21
|
-
|
22
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos/BDqs-OZWw9o/related", response.feed_id
|
23
|
-
assert_equal 25, response.max_result_count
|
24
|
-
assert_equal 25, response.videos.length
|
25
|
-
assert_equal 1, response.offset
|
26
|
-
puts response.total_result_count
|
27
|
-
assert(response.total_result_count > 0)
|
28
|
-
assert_instance_of Time, response.updated_at
|
29
|
-
end
|
30
|
-
end
|
data/test/test_video_search.rb
DELETED
@@ -1,118 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'test/unit'
|
3
|
-
require 'pp'
|
4
|
-
|
5
|
-
require 'youtube_g'
|
6
|
-
|
7
|
-
class TestVideoSearch < Test::Unit::TestCase
|
8
|
-
|
9
|
-
def test_should_build_basic_query_url
|
10
|
-
request = YouTubeG::Request::VideoSearch.new(:query => "penguin")
|
11
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos?vq=penguin", request.url
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_should_build_multiword_metasearch_query_url
|
15
|
-
request = YouTubeG::Request::VideoSearch.new(:query => 'christina ricci')
|
16
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos?vq=christina+ricci", request.url
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_should_build_video_id_url
|
20
|
-
request = YouTubeG::Request::VideoSearch.new(:video_id => 'T7YazwP8GtY')
|
21
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos/T7YazwP8GtY", request.url
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_should_build_one_tag_querl_url
|
25
|
-
request = YouTubeG::Request::VideoSearch.new(:tags => ['panther'])
|
26
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos/-/panther/", request.url
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_should_build_multiple_tags_query_url
|
30
|
-
request = YouTubeG::Request::VideoSearch.new(:tags => ['tiger', 'leopard'])
|
31
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos/-/tiger/leopard/", request.url
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_should_build_one_category_query_url
|
35
|
-
request = YouTubeG::Request::VideoSearch.new(:categories => [:news])
|
36
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos/-/News/", request.url
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_should_build_multiple_categories_query_url
|
40
|
-
request = YouTubeG::Request::VideoSearch.new(:categories => [:news, :sports])
|
41
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos/-/News/Sports/", request.url
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_should_build_categories_and_tags_query_url
|
45
|
-
request = YouTubeG::Request::VideoSearch.new(:categories => [:news, :sports], :tags => ['soccer', 'football'])
|
46
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos/-/News/Sports/soccer/football/", request.url
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_should_build_categories_and_tags_url_with_max_results
|
50
|
-
request = YouTubeG::Request::VideoSearch.new(:categories => [:music], :tags => ['classic', 'rock'], :max_results => 2)
|
51
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos/-/Music/classic/rock/?max-results=2", request.url
|
52
|
-
end
|
53
|
-
|
54
|
-
def test_should_build_author_query_url
|
55
|
-
request = YouTubeG::Request::VideoSearch.new(:author => "davidguetta")
|
56
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos?author=davidguetta", request.url
|
57
|
-
end
|
58
|
-
# -- Standard Feeds --------------------------------------------------------------------------------
|
59
|
-
|
60
|
-
def test_should_build_url_for_most_viewed
|
61
|
-
request = YouTubeG::Request::StandardSearch.new(:most_viewed)
|
62
|
-
assert_equal "http://gdata.youtube.com/feeds/api/standardfeeds/most_viewed", request.url
|
63
|
-
end
|
64
|
-
|
65
|
-
def test_should_raise_exception_for_invalid_type
|
66
|
-
assert_raise RuntimeError do
|
67
|
-
request = YouTubeG::Request::StandardSearch.new(:most_viewed_yo)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def test_should_build_url_for_top_rated_for_today
|
72
|
-
request = YouTubeG::Request::StandardSearch.new(:top_rated, :time => :today)
|
73
|
-
assert_equal "http://gdata.youtube.com/feeds/api/standardfeeds/top_rated?time=today", request.url
|
74
|
-
end
|
75
|
-
|
76
|
-
# -- Complex Video Queries -------------------------------------------------------------------------
|
77
|
-
|
78
|
-
def test_should_build_url_for_boolean_or_case_for_categories
|
79
|
-
request = YouTubeG::Request::VideoSearch.new(:categories => { :either => [:news, :sports] })
|
80
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos/-/News%7CSports/", request.url
|
81
|
-
end
|
82
|
-
|
83
|
-
def test_should_build_url_for_boolean_or_and_exclude_case_for_categories
|
84
|
-
request = YouTubeG::Request::VideoSearch.new(:categories => { :either => [:news, :sports], :exclude => [:comedy] })
|
85
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos/-/News%7CSports/-Comedy/", request.url
|
86
|
-
end
|
87
|
-
|
88
|
-
def test_should_build_url_for_exclude_case_for_tags
|
89
|
-
request = YouTubeG::Request::VideoSearch.new(:categories => { :either => [:news, :sports], :exclude => [:comedy] },
|
90
|
-
:tags => { :include => ['football'], :exclude => ['soccer'] })
|
91
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos/-/News%7CSports/-Comedy/football/-soccer/", request.url
|
92
|
-
end
|
93
|
-
|
94
|
-
def test_should_build_url_for_either_case_for_tags
|
95
|
-
request = YouTubeG::Request::VideoSearch.new(:categories => { :either => [:news, :sports], :exclude => [:comedy] },
|
96
|
-
:tags => { :either => ['soccer', 'football', 'donkey'] })
|
97
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos/-/News%7CSports/-Comedy/soccer%7Cfootball%7Cdonkey/", request.url
|
98
|
-
end
|
99
|
-
|
100
|
-
def test_should_build_url_for_query_search_with_categories_excluded
|
101
|
-
request = YouTubeG::Request::VideoSearch.new(:query => 'bench press',
|
102
|
-
:categories => { :exclude => [:comedy, :entertainment] },
|
103
|
-
:max_results => 10)
|
104
|
-
assert_equal "http://gdata.youtube.com/feeds/api/videos/-/-Comedy/-Entertainment/?vq=bench+press&max-results=10", request.url
|
105
|
-
end
|
106
|
-
|
107
|
-
# -- User Queries ---------------------------------------------------------------------------------
|
108
|
-
|
109
|
-
def test_should_build_url_for_videos_by_user
|
110
|
-
request = YouTubeG::Request::UserSearch.new(:user => 'liz')
|
111
|
-
assert_equal "http://gdata.youtube.com/feeds/api/users/liz/uploads", request.url
|
112
|
-
end
|
113
|
-
|
114
|
-
def test_should_build_url_for_favorite_videos_by_user
|
115
|
-
request = YouTubeG::Request::UserSearch.new(:favorites, :user => 'liz')
|
116
|
-
assert_equal "http://gdata.youtube.com/feeds/api/users/liz/favorites", request.url
|
117
|
-
end
|
118
|
-
end
|