msp-youtube-g 0.4.7 → 0.4.8.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,15 @@
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]
5
+ * Added :page and :per_page options, this allows easier usage of the will_paginate
6
+ plugin with the library. The :offset and :max_results options are no longer available. [Daniel Insley]
7
+ * Added ability to get video responses on the instances of the YouTube::Model::Video object. [Daniel Insley]
8
+ * Added and improved the existing documentation [Daniel Insley]
9
+ * Fixed usage of deprecated yt:racy, now using media:rating [Daniel Insley]
10
+ * Renamed can_embed? method to embeddable? [Daniel Insley]
11
+ * Added ability for padingation and ordering on standard feeds. [Daniel Insley]
12
+ * Move network dependent tests to integration-test [msp]
3
13
  * Create a parser and a model for upload errors [msp]
4
14
  * Stub driven tests for VideoFeedParser, VideosFeedParser, UploadErrorParser [msp]
5
15
  * Add error-handling for video upload errors. [FiXato]
@@ -18,6 +18,9 @@ lib/youtube_g/model/video.rb
18
18
  lib/youtube_g/model/upload_error.rb
19
19
  lib/youtube_g/parser.rb
20
20
  lib/youtube_g/record.rb
21
+ lib/youtube_g/request/base_search.rb
22
+ lib/youtube_g/request/standard_search.rb
23
+ lib/youtube_g/request/user_search.rb
21
24
  lib/youtube_g/request/video_search.rb
22
25
  lib/youtube_g/request/video_upload.rb
23
26
  lib/youtube_g/response/video_search.rb
data/README.txt CHANGED
@@ -32,6 +32,7 @@ Create a client:
32
32
  Basic queries:
33
33
 
34
34
  client.videos_by(:query => "penguin")
35
+ client.videos_by(:query => "penguin", :page => 2, :per_page => 15)
35
36
  client.videos_by(:tags => ['tiger', 'leopard'])
36
37
  client.videos_by(:categories => [:news, :sports])
37
38
  client.videos_by(:categories => [:news, :sports], :tags => ['soccer', 'football'])
@@ -40,6 +41,7 @@ Basic queries:
40
41
  Standard feeds:
41
42
 
42
43
  client.videos_by(:most_viewed)
44
+ client.videos_by(:most_linked, :page => 3)
43
45
  client.videos_by(:top_rated, :time => :today)
44
46
 
45
47
  Advanced queries (with boolean operators OR (either), AND (include), NOT (exclude)):
data/Rakefile CHANGED
@@ -17,4 +17,9 @@ desc 'Tag release'
17
17
  task :tag do
18
18
  svn_root = 'svn+ssh://drummr77@rubyforge.org/var/svn/youtube-g'
19
19
  sh %(svn cp #{svn_root}/trunk #{svn_root}/tags/release-#{YouTubeG::VERSION} -m "Tag YouTubeG release #{YouTubeG::VERSION}")
20
+ end
21
+
22
+ desc 'Load the library in an IRB session'
23
+ task :console do
24
+ sh %(irb -r lib/youtube_g.rb)
20
25
  end
data/TODO.txt CHANGED
@@ -1,12 +1,10 @@
1
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
- [ ] consider defaulting the client to no-logger, rather than outputting to STDOUT.
3
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' ]
4
3
  [ ] make sure symbols will work as well as tags everywhere (again, :tags => :chickens is same as :tags => 'chickens')
5
4
  [ ] figure out better structure for class/file (either rename request/video_search.rb or split into one class per file again)
6
5
  [ ] restore spaces after method def names
7
6
  [ ] use a proxy for testing with static sample result xml so we have repeatable tests (see above [msp])
8
7
  [ ] Clean up tests using Shoulda to define contexts
9
- [ ] Consolidate requires
10
8
  [ ] Allow :category and :categories for query DSL
11
9
  [ ] Exception handling
12
10
 
@@ -0,0 +1,256 @@
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
+
56
+ def test_should_get_videos_for_multiword_metasearch_query
57
+ response = @client.videos_by(:query => 'christina ricci')
58
+
59
+ assert_equal "http://gdata.youtube.com/feeds/api/videos", response.feed_id
60
+ assert_equal 25, response.max_result_count
61
+ assert_equal 25, response.videos.length
62
+ assert_equal 1, response.offset
63
+ assert(response.total_result_count > 100)
64
+ assert_instance_of Time, response.updated_at
65
+
66
+ response.videos.each { |v| assert_valid_video v }
67
+ end
68
+
69
+ def test_should_handle_video_not_yet_viewed
70
+ response = @client.videos_by(:query => "YnqHZDh_t2Q")
71
+
72
+ assert_equal 1, response.videos.length
73
+ response.videos.each { |v| assert_valid_video v }
74
+ end
75
+
76
+ # TODO: this doesn't work because the returned feed is in an unknown format
77
+ # def test_should_get_video_for_search_by_video_id
78
+ # response = @client.videos_by(:video_id => "T7YazwP8GtY")
79
+ # response.videos.each { |v| assert_valid_video v }
80
+ # end
81
+
82
+ def test_should_get_videos_for_one_tag
83
+ response = @client.videos_by(:tags => ['panther'])
84
+ response.videos.each { |v| assert_valid_video v }
85
+ end
86
+
87
+ def test_should_get_videos_for_multiple_tags
88
+ response = @client.videos_by(:tags => ['tiger', 'leopard'])
89
+ response.videos.each { |v| assert_valid_video v }
90
+ end
91
+
92
+ def test_should_get_videos_for_one_category
93
+ response = @client.videos_by(:categories => [:news])
94
+ response.videos.each { |v| assert_valid_video v }
95
+ end
96
+
97
+ def test_should_get_videos_for_multiple_categories
98
+ response = @client.videos_by(:categories => [:news, :sports])
99
+ response.videos.each { |v| assert_valid_video v }
100
+ end
101
+
102
+ # TODO: Need to do more specific checking in these tests
103
+ # Currently, if a URL is valid, and videos are found, the test passes regardless of search criteria
104
+ def test_should_get_videos_for_categories_and_tags
105
+ response = @client.videos_by(:categories => [:news, :sports], :tags => ['soccer', 'football'])
106
+ response.videos.each { |v| assert_valid_video v }
107
+ end
108
+
109
+ def test_should_get_most_viewed_videos
110
+ response = @client.videos_by(:most_viewed)
111
+ response.videos.each { |v| assert_valid_video v }
112
+ end
113
+
114
+ def test_should_get_top_rated_videos_for_today
115
+ response = @client.videos_by(:top_rated, :time => :today)
116
+ response.videos.each { |v| assert_valid_video v }
117
+ end
118
+
119
+ def test_should_get_videos_for_categories_and_tags_with_category_boolean_operators
120
+ response = @client.videos_by(:categories => { :either => [:news, :sports], :exclude => [:comedy] },
121
+ :tags => { :include => ['football'], :exclude => ['soccer'] })
122
+ response.videos.each { |v| assert_valid_video v }
123
+ end
124
+
125
+ def test_should_get_videos_for_categories_and_tags_with_tag_boolean_operators
126
+ response = @client.videos_by(:categories => { :either => [:news, :sports], :exclude => [:comedy] },
127
+ :tags => { :either => ['football', 'soccer', 'polo'] })
128
+ response.videos.each { |v| assert_valid_video v }
129
+ end
130
+
131
+ def test_should_get_videos_by_user
132
+ response = @client.videos_by(:user => 'liz')
133
+ response.videos.each { |v| assert_valid_video v }
134
+ end
135
+
136
+ # HTTP 403 Error
137
+ # def test_should_get_favorite_videos_by_user
138
+ # response = @client.videos_by(:favorites, :user => 'liz')
139
+ # response.videos.each { |v| assert_valid_video v }
140
+ # end
141
+
142
+ def test_should_get_videos_for_query_search_with_categories_excluded
143
+ video = @client.video_by("EkF4JD2rO3Q")
144
+ 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
145
+ assert_valid_video video
146
+ end
147
+
148
+ def test_should_disable_debug_if_debug_is_set_to_false
149
+ @client = YouTubeG::Client.new
150
+ assert_nil @client.logger
151
+ end
152
+
153
+ def test_should_enable_logger_if_debug_is_true
154
+ @client = YouTubeG::Client.new(true)
155
+ assert_not_nil @client.logger
156
+ end
157
+
158
+ def test_should_determine_if_nonembeddable_video_is_embeddable
159
+ response = @client.videos_by(:query => "avril lavigne girlfriend")
160
+
161
+ video = response.videos.first
162
+ assert !video.embeddable?
163
+ end
164
+
165
+ def test_should_determine_if_embeddable_video_is_embeddable
166
+ response = @client.videos_by(:query => "strongbad")
167
+
168
+ video = response.videos.first
169
+ assert video.embeddable?
170
+ end
171
+
172
+ def test_should_retrieve_video_by_id
173
+ video = @client.video_by("http://gdata.youtube.com/feeds/videos/EkF4JD2rO3Q")
174
+ assert_valid_video video
175
+
176
+ video = @client.video_by("EkF4JD2rO3Q")
177
+ assert_valid_video video
178
+ end
179
+
180
+ private
181
+
182
+ def assert_valid_video (video)
183
+ # pp video
184
+
185
+ # check general attributes
186
+ assert_instance_of YouTubeG::Model::Video, video
187
+ assert_instance_of Fixnum, video.duration
188
+ assert(video.duration > 0)
189
+ #assert_match(/^<div style=.*?<\/div>/m, video.html_content)
190
+ assert_instance_of String, video.html_content
191
+
192
+ # validate media content records
193
+ video.media_content.each do |media_content|
194
+ # http://www.youtube.com/v/IHVaXG1thXM
195
+ assert_valid_url media_content.url
196
+ assert(media_content.duration > 0)
197
+ assert_instance_of YouTubeG::Model::Video::Format, media_content.format
198
+ assert_instance_of String, media_content.mime_type
199
+ assert_match(/^[^\/]+\/[^\/]+$/, media_content.mime_type)
200
+ end
201
+
202
+ default_content = video.default_media_content
203
+ if default_content
204
+ assert_instance_of YouTubeG::Model::Content, default_content
205
+ assert default_content.is_default?
206
+ end
207
+
208
+ # validate keywords
209
+ video.keywords.each { |kw| assert_instance_of(String, kw) }
210
+
211
+ # http://www.youtube.com/watch?v=IHVaXG1thXM
212
+ assert_valid_url video.player_url
213
+ assert_instance_of Time, video.published_at
214
+
215
+ # validate optionally-present rating
216
+ if video.rating
217
+ assert_instance_of YouTubeG::Model::Rating, video.rating
218
+ assert_instance_of Float, video.rating.average
219
+ assert_instance_of Fixnum, video.rating.max
220
+ assert_instance_of Fixnum, video.rating.min
221
+ assert_instance_of Fixnum, video.rating.rater_count
222
+ end
223
+
224
+ # validate thumbnails
225
+ assert(video.thumbnails.size > 0)
226
+
227
+ assert_not_nil video.title
228
+ assert_instance_of String, video.title
229
+ assert(video.title.length > 0)
230
+
231
+ assert_instance_of Time, video.updated_at
232
+ # http://gdata.youtube.com/feeds/videos/IHVaXG1thXM
233
+ assert_valid_url video.video_id
234
+ assert_instance_of Fixnum, video.view_count
235
+
236
+ # validate author
237
+ assert_instance_of YouTubeG::Model::Author, video.author
238
+ assert_instance_of String, video.author.name
239
+ assert(video.author.name.length > 0)
240
+ assert_valid_url video.author.uri
241
+
242
+ # validate categories
243
+ video.categories.each do |cat|
244
+ assert_instance_of YouTubeG::Model::Category, cat
245
+ assert_instance_of String, cat.label
246
+ assert_instance_of String, cat.term
247
+ end
248
+ end
249
+
250
+ def assert_valid_url (url)
251
+ URI::parse(url)
252
+ return true
253
+ rescue
254
+ return false
255
+ end
256
+ end
@@ -0,0 +1,42 @@
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
+ assert(response.total_result_count > 0)
27
+ assert_instance_of Time, response.updated_at
28
+ end
29
+
30
+ def test_should_have_response_videos
31
+ video = YouTubeG::Model::Video.new(:video_id => "http://gdata.youtube.com/feeds/videos/BDqs-OZWw9o")
32
+ response = video.responses
33
+
34
+ assert_equal "http://gdata.youtube.com/feeds/api/videos/BDqs-OZWw9o/responses", response.feed_id
35
+ assert_equal 25, response.max_result_count
36
+ assert_equal 25, response.videos.length
37
+ assert_equal 1, response.offset
38
+ assert(response.total_result_count > 0)
39
+ assert_instance_of Time, response.updated_at
40
+ end
41
+
42
+ end
@@ -0,0 +1,128 @@
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_build_url_for_top_rated_for_today
66
+ request = YouTubeG::Request::StandardSearch.new(:top_rated, :time => :today)
67
+ assert_equal "http://gdata.youtube.com/feeds/api/standardfeeds/top_rated?time=today", request.url
68
+ end
69
+
70
+ def test_should_build_url_for_most_viewed_offset_and_max_results_without_time
71
+ request = YouTubeG::Request::StandardSearch.new(:top_rated, :offset => 5, :max_results => 10)
72
+ assert_equal "http://gdata.youtube.com/feeds/api/standardfeeds/top_rated?max-results=10&start-index=5", request.url
73
+ end
74
+
75
+ def test_should_build_url_for_most_viewed_offset_and_max_results_with_time
76
+ request = YouTubeG::Request::StandardSearch.new(:top_rated, :offset => 5, :max_results => 10, :time => :today)
77
+ assert_equal "http://gdata.youtube.com/feeds/api/standardfeeds/top_rated?time=today&max-results=10&start-index=5", request.url
78
+ end
79
+
80
+ def test_should_raise_exception_for_invalid_type
81
+ assert_raise RuntimeError do
82
+ request = YouTubeG::Request::StandardSearch.new(:most_viewed_yo)
83
+ end
84
+ end
85
+
86
+ # -- Complex Video Queries -------------------------------------------------------------------------
87
+
88
+ def test_should_build_url_for_boolean_or_case_for_categories
89
+ request = YouTubeG::Request::VideoSearch.new(:categories => { :either => [:news, :sports] })
90
+ assert_equal "http://gdata.youtube.com/feeds/api/videos/-/News%7CSports/", request.url
91
+ end
92
+
93
+ def test_should_build_url_for_boolean_or_and_exclude_case_for_categories
94
+ request = YouTubeG::Request::VideoSearch.new(:categories => { :either => [:news, :sports], :exclude => [:comedy] })
95
+ assert_equal "http://gdata.youtube.com/feeds/api/videos/-/News%7CSports/-Comedy/", request.url
96
+ end
97
+
98
+ def test_should_build_url_for_exclude_case_for_tags
99
+ request = YouTubeG::Request::VideoSearch.new(:categories => { :either => [:news, :sports], :exclude => [:comedy] },
100
+ :tags => { :include => ['football'], :exclude => ['soccer'] })
101
+ assert_equal "http://gdata.youtube.com/feeds/api/videos/-/News%7CSports/-Comedy/football/-soccer/", request.url
102
+ end
103
+
104
+ def test_should_build_url_for_either_case_for_tags
105
+ request = YouTubeG::Request::VideoSearch.new(:categories => { :either => [:news, :sports], :exclude => [:comedy] },
106
+ :tags => { :either => ['soccer', 'football', 'donkey'] })
107
+ assert_equal "http://gdata.youtube.com/feeds/api/videos/-/News%7CSports/-Comedy/soccer%7Cfootball%7Cdonkey/", request.url
108
+ end
109
+
110
+ def test_should_build_url_for_query_search_with_categories_excluded
111
+ request = YouTubeG::Request::VideoSearch.new(:query => 'bench press',
112
+ :categories => { :exclude => [:comedy, :entertainment] },
113
+ :max_results => 10)
114
+ assert_equal "http://gdata.youtube.com/feeds/api/videos/-/-Comedy/-Entertainment/?vq=bench+press&max-results=10", request.url
115
+ end
116
+
117
+ # -- User Queries ---------------------------------------------------------------------------------
118
+
119
+ def test_should_build_url_for_videos_by_user
120
+ request = YouTubeG::Request::UserSearch.new(:user => 'liz')
121
+ assert_equal "http://gdata.youtube.com/feeds/api/users/liz/uploads", request.url
122
+ end
123
+
124
+ def test_should_build_url_for_favorite_videos_by_user
125
+ request = YouTubeG::Request::UserSearch.new(:favorites, :user => 'liz')
126
+ assert_equal "http://gdata.youtube.com/feeds/api/users/liz/favorites", request.url
127
+ end
128
+ end