slainer68_youtube_it 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. data/Gemfile +10 -0
  2. data/Gemfile.lock +27 -0
  3. data/Manifest.txt +37 -0
  4. data/README.rdoc +270 -0
  5. data/Rakefile +53 -0
  6. data/VERSION +1 -0
  7. data/lib/youtube_it/chain_io.rb +76 -0
  8. data/lib/youtube_it/client.rb +447 -0
  9. data/lib/youtube_it/middleware/faraday_authheader.rb +24 -0
  10. data/lib/youtube_it/middleware/faraday_oauth.rb +21 -0
  11. data/lib/youtube_it/middleware/faraday_oauth2.rb +13 -0
  12. data/lib/youtube_it/middleware/faraday_youtubeit.rb +30 -0
  13. data/lib/youtube_it/model/activity.rb +17 -0
  14. data/lib/youtube_it/model/author.rb +13 -0
  15. data/lib/youtube_it/model/category.rb +11 -0
  16. data/lib/youtube_it/model/comment.rb +16 -0
  17. data/lib/youtube_it/model/contact.rb +19 -0
  18. data/lib/youtube_it/model/content.rb +18 -0
  19. data/lib/youtube_it/model/message.rb +12 -0
  20. data/lib/youtube_it/model/playlist.rb +11 -0
  21. data/lib/youtube_it/model/rating.rb +23 -0
  22. data/lib/youtube_it/model/subscription.rb +7 -0
  23. data/lib/youtube_it/model/thumbnail.rb +17 -0
  24. data/lib/youtube_it/model/user.rb +27 -0
  25. data/lib/youtube_it/model/video.rb +239 -0
  26. data/lib/youtube_it/parser.rb +534 -0
  27. data/lib/youtube_it/record.rb +12 -0
  28. data/lib/youtube_it/request/base_search.rb +72 -0
  29. data/lib/youtube_it/request/error.rb +15 -0
  30. data/lib/youtube_it/request/standard_search.rb +43 -0
  31. data/lib/youtube_it/request/user_search.rb +47 -0
  32. data/lib/youtube_it/request/video_search.rb +102 -0
  33. data/lib/youtube_it/request/video_upload.rb +538 -0
  34. data/lib/youtube_it/response/video_search.rb +41 -0
  35. data/lib/youtube_it/version.rb +4 -0
  36. data/lib/youtube_it.rb +83 -0
  37. data/slainer68_youtube_it.gemspec +102 -0
  38. data/test/files/recorded_response.xml +1 -0
  39. data/test/files/youtube_video_response.xml +53 -0
  40. data/test/helper.rb +9 -0
  41. data/test/test.mov +0 -0
  42. data/test/test_chain_io.rb +63 -0
  43. data/test/test_client.rb +435 -0
  44. data/test/test_field_search.rb +48 -0
  45. data/test/test_video.rb +48 -0
  46. data/test/test_video_feed_parser.rb +271 -0
  47. data/test/test_video_search.rb +141 -0
  48. metadata +172 -0
@@ -0,0 +1,534 @@
1
+ class YouTubeIt
2
+ module Parser #:nodoc:
3
+ class FeedParser #:nodoc:
4
+ def initialize(content)
5
+ @content = (content =~ URI::regexp(%w(http https)) ? open(content).read : content)
6
+
7
+ rescue OpenURI::HTTPError => e
8
+ raise OpenURI::HTTPError.new(e.io.status[0],e)
9
+ rescue
10
+ @content = content
11
+
12
+ end
13
+
14
+ def parse
15
+ parse_content @content
16
+ end
17
+
18
+ def parse_videos
19
+ doc = REXML::Document.new(@content)
20
+ videos = []
21
+ doc.elements.each("*/entry") do |video|
22
+ videos << parse_entry(video)
23
+ end
24
+ videos
25
+ end
26
+ end
27
+
28
+ class CommentsFeedParser < FeedParser #:nodoc:
29
+ # return array of comments
30
+ def parse_content(content)
31
+ doc = REXML::Document.new(content.body)
32
+ feed = doc.elements["feed"]
33
+
34
+ comments = []
35
+ feed.elements.each("entry") do |entry|
36
+ comments << parse_entry(entry)
37
+ end
38
+ return comments
39
+ end
40
+
41
+ protected
42
+ def parse_entry(entry)
43
+ author = YouTubeIt::Model::Author.new(
44
+ :name => (entry.elements["author"].elements["name"].text rescue nil),
45
+ :uri => (entry.elements["author"].elements["uri"].text rescue nil)
46
+ )
47
+ YouTubeIt::Model::Comment.new(
48
+ :author => author,
49
+ :content => entry.elements["content"].text,
50
+ :published => entry.elements["published"].text,
51
+ :title => entry.elements["title"].text,
52
+ :updated => entry.elements["updated "].text,
53
+ :url => entry.elements["id"].text
54
+ )
55
+ end
56
+ end
57
+
58
+ class PlaylistFeedParser < FeedParser #:nodoc:
59
+
60
+ def parse_content(content)
61
+ xml = REXML::Document.new(content.body)
62
+ entry = xml.elements["entry"] || xml.elements["feed"]
63
+ YouTubeIt::Model::Playlist.new(
64
+ :title => entry.elements["title"].text,
65
+ :summary => (entry.elements["summary"] || entry.elements["media:group"].elements["media:description"]).text,
66
+ :description => (entry.elements["summary"] || entry.elements["media:group"].elements["media:description"]).text,
67
+ :playlist_id => entry.elements["id"].text[/playlist([^<]+)/, 1].sub(':',''),
68
+ :published => entry.elements["published"] ? entry.elements["published"].text : nil,
69
+ :response_code => content.status,
70
+ :xml => content.body)
71
+ end
72
+ end
73
+
74
+ class PlaylistsFeedParser < FeedParser #:nodoc:
75
+
76
+ # return array of playlist objects
77
+ def parse_content(content)
78
+ doc = REXML::Document.new(content.body)
79
+ feed = doc.elements["feed"]
80
+
81
+ playlists = []
82
+ feed.elements.each("entry") do |entry|
83
+ playlists << parse_entry(entry)
84
+ end
85
+ return playlists
86
+ end
87
+
88
+ protected
89
+
90
+ def parse_entry(entry)
91
+ YouTubeIt::Model::Playlist.new(
92
+ :title => entry.elements["title"].text,
93
+ :summary => (entry.elements["summary"] || entry.elements["media:group"].elements["media:description"]).text,
94
+ :description => (entry.elements["summary"] || entry.elements["media:group"].elements["media:description"]).text,
95
+ :playlist_id => entry.elements["id"].text[/playlist([^<]+)/, 1].sub(':',''),
96
+ :published => entry.elements["published"] ? entry.elements["published"].text : nil,
97
+ :response_code => nil,
98
+ :xml => nil)
99
+ end
100
+ end
101
+
102
+ # Returns an array of the user's activity
103
+ class ActivityParser < FeedParser
104
+ def parse_content(content)
105
+ doc = REXML::Document.new(content.body)
106
+ feed = doc.elements["feed"]
107
+
108
+ activity = []
109
+ feed.elements.each("entry") do |entry|
110
+ parsed_activity = parse_activity(entry)
111
+ if parsed_activity
112
+ activity << parsed_activity
113
+ end
114
+ end
115
+
116
+ return activity
117
+ end
118
+
119
+ protected
120
+
121
+ # Parses the user's activity feed.
122
+ def parse_activity(entry)
123
+ # Figure out what kind of activity we have
124
+ video_type = nil
125
+ parsed_activity = nil
126
+ entry.elements.each("category") do |category_tag|
127
+ if category_tag.attributes["scheme"]=="http://gdata.youtube.com/schemas/2007/userevents.cat"
128
+ video_type = category_tag.attributes["term"]
129
+ end
130
+ end
131
+
132
+ if video_type
133
+ case video_type
134
+ when "video_rated"
135
+ parsed_activity = YouTubeIt::Model::Activity.new(
136
+ :type => "video_rated",
137
+ :time => entry.elements["updated"] ? entry.elements["updated"].text : nil,
138
+ :author => entry.elements["author"].elements["name"] ? entry.elements["author"].elements["name"].text : nil,
139
+ :videos => parse_activity_videos(entry),
140
+ :video_id => entry.elements["yt:videoid"] ? entry.elements["yt:videoid"].text : nil
141
+ )
142
+ when "video_shared"
143
+ parsed_activity = YouTubeIt::Model::Activity.new(
144
+ :type => "video_shared",
145
+ :time => entry.elements["updated"] ? entry.elements["updated"].text : nil,
146
+ :author => entry.elements["author"].elements["name"] ? entry.elements["author"].elements["name"].text : nil,
147
+ :videos => parse_activity_videos(entry),
148
+ :video_id => entry.elements["yt:videoid"] ? entry.elements["yt:videoid"].text : nil
149
+ )
150
+ when "video_favorited"
151
+ parsed_activity = YouTubeIt::Model::Activity.new(
152
+ :type => "video_favorited",
153
+ :time => entry.elements["updated"] ? entry.elements["updated"].text : nil,
154
+ :author => entry.elements["author"].elements["name"] ? entry.elements["author"].elements["name"].text : nil,
155
+ :videos => parse_activity_videos(entry),
156
+ :video_id => entry.elements["yt:videoid"] ? entry.elements["yt:videoid"].text : nil
157
+ )
158
+ when "video_commented"
159
+ # Load the comment and video URL
160
+ comment_thread_url = nil
161
+ video_url = nil
162
+ entry.elements.each("link") do |link_tag|
163
+ case link_tag.attributes["rel"]
164
+ when "http://gdata.youtube.com/schemas/2007#comments"
165
+ comment_thread_url = link_tag.attributes["href"]
166
+ when "http://gdata.youtube.com/schemas/2007#video"
167
+ video_url = link_tag.attributes["href"]
168
+ else
169
+ # Invalid rel type, do nothing
170
+ end
171
+ end
172
+
173
+ parsed_activity = YouTubeIt::Model::Activity.new(
174
+ :type => "video_commented",
175
+ :time => entry.elements["updated"] ? entry.elements["updated"].text : nil,
176
+ :author => entry.elements["author"].elements["name"] ? entry.elements["author"].elements["name"].text : nil,
177
+ :videos => parse_activity_videos(entry),
178
+ :video_id => entry.elements["yt:videoid"] ? entry.elements["yt:videoid"].text : nil,
179
+ :comment_thread_url => comment_thread_url,
180
+ :video_url => video_url
181
+ )
182
+ when "video_uploaded"
183
+ parsed_activity = YouTubeIt::Model::Activity.new(
184
+ :type => "video_uploaded",
185
+ :time => entry.elements["updated"] ? entry.elements["updated"].text : nil,
186
+ :author => entry.elements["author"].elements["name"] ? entry.elements["author"].elements["name"].text : nil,
187
+ :videos => parse_activity_videos(entry),
188
+ :video_id => entry.elements["yt:videoid"] ? entry.elements["yt:videoid"].text : nil
189
+ )
190
+ when "friend_added"
191
+ parsed_activity = YouTubeIt::Model::Activity.new(
192
+ :type => "friend_added",
193
+ :time => entry.elements["updated"] ? entry.elements["updated"].text : nil,
194
+ :author => entry.elements["author"].elements["name"] ? entry.elements["author"].elements["name"].text : nil,
195
+ :username => entry.elements["yt:username"] ? entry.elements["yt:username"].text : nil
196
+ )
197
+ when "user_subscription_added"
198
+ parsed_activity = YouTubeIt::Model::Activity.new(
199
+ :type => "user_subscription_added",
200
+ :time => entry.elements["updated"] ? entry.elements["updated"].text : nil,
201
+ :author => entry.elements["author"].elements["name"] ? entry.elements["author"].elements["name"].text : nil,
202
+ :username => entry.elements["yt:username"] ? entry.elements["yt:username"].text : nil
203
+ )
204
+ else
205
+ # Invalid activity type, just let it return nil
206
+ end
207
+ end
208
+
209
+ return parsed_activity
210
+ end
211
+
212
+ # If a user enabled inline attribute videos may be included in results.
213
+ def parse_activity_videos(entry)
214
+ videos = []
215
+
216
+ entry.elements.each("link") do |link_tag|
217
+ if link_tag.attributes["rel"]=="http://gdata.youtube.com/schemas/2007#video"
218
+ videos << YouTubeIt::Parser::VideoFeedParser.new(link_tag).parse
219
+ end
220
+ end
221
+
222
+ if videos.size <= 0
223
+ videos = nil
224
+ end
225
+
226
+ return videos
227
+ end
228
+ end
229
+
230
+ # Returns an array of the user's contacts
231
+ class ContactsParser < FeedParser
232
+ def parse_content(content)
233
+ doc = REXML::Document.new(content.body)
234
+ feed = doc.elements["feed"]
235
+
236
+ contacts = []
237
+ feed.elements.each("entry") do |entry|
238
+ temp_contact = YouTubeIt::Model::Contact.new(
239
+ :title => entry.elements["title"] ? entry.elements["title"].text : nil,
240
+ :username => entry.elements["yt:username"] ? entry.elements["yt:username"].text : nil,
241
+ :status => entry.elements["yt:status"] ? entry.elements["yt:status"].text : nil
242
+ )
243
+
244
+ contacts << temp_contact
245
+ end
246
+
247
+ return contacts
248
+ end
249
+ end
250
+
251
+ # Returns an array of the user's messages
252
+ class MessagesParser < FeedParser
253
+ def parse_content(content)
254
+ doc = REXML::Document.new(content.body)
255
+ puts content.body
256
+ puts "doc..."
257
+ puts doc.inspect
258
+ feed = doc.elements["feed"]
259
+
260
+ messages = []
261
+ feed.elements.each("entry") do |entry|
262
+ author = entry.elements["author"]
263
+ temp_message = YouTubeIt::Model::Message.new(
264
+ :id => entry.elements["id"] ? entry.elements["id"].text.gsub(/.+:inbox:/, "") : nil,
265
+ :title => entry.elements["title"] ? entry.elements["title"].text : nil,
266
+ :name => author && author.elements["name"] ? author.elements["name"].text : nil,
267
+ :summary => entry.elements["summary"] ? entry.elements["summary"].text : nil,
268
+ :published => entry.elements["published"] ? entry.elements["published"].text : nil
269
+ )
270
+
271
+ messages << temp_message
272
+ end
273
+
274
+ return messages
275
+ end
276
+ end
277
+
278
+ class ProfileFeedParser < FeedParser #:nodoc:
279
+ def parse_content(content)
280
+ xml = REXML::Document.new(content.body)
281
+ entry = xml.elements["entry"] || xml.elements["feed"]
282
+ YouTubeIt::Model::User.new(
283
+ :age => entry.elements["yt:age"] ? entry.elements["yt:age"].text : nil,
284
+ :username => entry.elements["yt:username"] ? entry.elements["yt:username"].text : nil,
285
+ :company => entry.elements["yt:company"] ? entry.elements["yt:company"].text : nil,
286
+ :gender => entry.elements["yt:gender"] ? entry.elements["yt:gender"].text : nil,
287
+ :hobbies => entry.elements["yt:hobbies"] ? entry.elements["yt:hobbies"].text : nil,
288
+ :hometown => entry.elements["yt:hometown"] ? entry.elements["yt:hometown"].text : nil,
289
+ :location => entry.elements["yt:location"] ? entry.elements["yt:location"].text : nil,
290
+ :last_login => entry.elements["yt:statistics"].attributes["lastWebAccess"],
291
+ :join_date => entry.elements["published"] ? entry.elements["published"].text : nil,
292
+ :movies => entry.elements["yt:movies"] ? entry.elements["yt:movies"].text : nil,
293
+ :music => entry.elements["yt:music"] ? entry.elements["yt:music"].text : nil,
294
+ :occupation => entry.elements["yt:occupation"] ? entry.elements["yt:occupation"].text : nil,
295
+ :relationship => entry.elements["yt:relationship"] ? entry.elements["yt:relationship"].text : nil,
296
+ :school => entry.elements["yt:school"] ? entry.elements["yt:school"].text : nil,
297
+ :avatar => entry.elements["media:thumbnail"] ? entry.elements["media:thumbnail"].attributes["url"] : nil,
298
+ :subscribers => entry.elements["yt:statistics"].attributes["subscriberCount"],
299
+ :videos_watched => entry.elements["yt:statistics"].attributes["videoWatchCount"],
300
+ :view_count => entry.elements["yt:statistics"].attributes["viewCount"],
301
+ :upload_views => entry.elements["yt:statistics"].attributes["totalUploadViews"]
302
+ )
303
+ end
304
+ end
305
+
306
+ class SubscriptionFeedParser < FeedParser #:nodoc:
307
+
308
+ def parse_content(content)
309
+ doc = REXML::Document.new(content.body)
310
+ feed = doc.elements["feed"]
311
+
312
+ subscriptions = []
313
+ feed.elements.each("entry") do |entry|
314
+ subscriptions << parse_entry(entry)
315
+ end
316
+ return subscriptions
317
+ end
318
+
319
+ protected
320
+
321
+ def parse_entry(entry)
322
+ YouTubeIt::Model::Subscription.new(
323
+ :title => entry.elements["title"].text,
324
+ :id => entry.elements["id"].text[/subscription([^<]+)/, 1].sub(':',''),
325
+ :published => entry.elements["published"] ? entry.elements["published"].text : nil
326
+ )
327
+ end
328
+ end
329
+
330
+
331
+ class VideoFeedParser < FeedParser #:nodoc:
332
+
333
+ def parse_content(content)
334
+ doc = (content.is_a?(REXML::Element)) ? content : REXML::Document.new(content)
335
+
336
+ entry = doc.elements["entry"]
337
+ parse_entry(entry)
338
+ end
339
+
340
+ protected
341
+ def parse_entry(entry)
342
+ video_id = entry.elements["id"].text
343
+ published_at = entry.elements["published"] ? Time.parse(entry.elements["published"].text) : nil
344
+ updated_at = entry.elements["updated"] ? Time.parse(entry.elements["updated"].text) : nil
345
+
346
+ # parse the category and keyword lists
347
+ categories = []
348
+ keywords = []
349
+ entry.elements.each("category") do |category|
350
+ # determine if it's really a category, or just a keyword
351
+ scheme = category.attributes["scheme"]
352
+ if (scheme =~ /\/categories\.cat$/)
353
+ # it's a category
354
+ categories << YouTubeIt::Model::Category.new(
355
+ :term => category.attributes["term"],
356
+ :label => category.attributes["label"])
357
+
358
+ elsif (scheme =~ /\/keywords\.cat$/)
359
+ # it's a keyword
360
+ keywords << category.attributes["term"]
361
+ end
362
+ end
363
+
364
+ title = entry.elements["title"].text
365
+ html_content = entry.elements["content"] ? entry.elements["content"].text : nil
366
+
367
+ # parse the author
368
+ author_element = entry.elements["author"]
369
+ author = nil
370
+ if author_element
371
+ author = YouTubeIt::Model::Author.new(
372
+ :name => author_element.elements["name"].text,
373
+ :uri => author_element.elements["uri"].text)
374
+ end
375
+ media_group = entry.elements["media:group"]
376
+
377
+ # if content is not available on certain region, there is no media:description, media:player or yt:duration
378
+ description = ""
379
+ unless media_group.elements["media:description"].nil?
380
+ description = media_group.elements["media:description"].text
381
+ end
382
+
383
+ # if content is not available on certain region, there is no media:description, media:player or yt:duration
384
+ duration = 0
385
+ unless media_group.elements["yt:duration"].nil?
386
+ duration = media_group.elements["yt:duration"].attributes["seconds"].to_i
387
+ end
388
+
389
+ # if content is not available on certain region, there is no media:description, media:player or yt:duration
390
+ player_url = ""
391
+ unless media_group.elements["media:player"].nil?
392
+ player_url = media_group.elements["media:player"].attributes["url"]
393
+ end
394
+
395
+ unless media_group.elements["yt:aspectRatio"].nil?
396
+ widescreen = media_group.elements["yt:aspectRatio"].text == 'widescreen' ? true : false
397
+ end
398
+
399
+ media_content = []
400
+ media_group.elements.each("media:content") do |mce|
401
+ media_content << parse_media_content(mce)
402
+ end
403
+
404
+ # parse thumbnails
405
+ thumbnails = []
406
+ media_group.elements.each("media:thumbnail") do |thumb_element|
407
+ # TODO: convert time HH:MM:ss string to seconds?
408
+ thumbnails << YouTubeIt::Model::Thumbnail.new(
409
+ :url => thumb_element.attributes["url"],
410
+ :height => thumb_element.attributes["height"].to_i,
411
+ :width => thumb_element.attributes["width"].to_i,
412
+ :time => thumb_element.attributes["time"])
413
+ end
414
+
415
+ rating_element = entry.elements["gd:rating"]
416
+ extended_rating_element = entry.elements["yt:rating"]
417
+
418
+ rating = nil
419
+ if rating_element
420
+ rating_values = {
421
+ :min => rating_element.attributes["min"].to_i,
422
+ :max => rating_element.attributes["max"].to_i,
423
+ :rater_count => rating_element.attributes["numRaters"].to_i,
424
+ :average => rating_element.attributes["average"].to_f
425
+ }
426
+
427
+ if extended_rating_element
428
+ rating_values[:likes] = extended_rating_element.attributes["numLikes"].to_i
429
+ rating_values[:dislikes] = extended_rating_element.attributes["numDislikes"].to_i
430
+ end
431
+
432
+ rating = YouTubeIt::Model::Rating.new(rating_values)
433
+ end
434
+
435
+ if (el = entry.elements["yt:statistics"])
436
+ view_count, favorite_count = el.attributes["viewCount"].to_i, el.attributes["favoriteCount"].to_i
437
+ else
438
+ view_count, favorite_count = 0,0
439
+ end
440
+
441
+ noembed = entry.elements["yt:noembed"] ? true : false
442
+ racy = entry.elements["media:rating"] ? true : false
443
+
444
+ if where = entry.elements["georss:where"]
445
+ position = where.elements["gml:Point"].elements["gml:pos"].text
446
+ latitude, longitude = position.split(" ")
447
+ end
448
+
449
+ control = entry.elements["app:control"]
450
+ state = { :name => "published" }
451
+ if control && control.elements["yt:state"]
452
+ state = {
453
+ :name => control.elements["yt:state"].attributes["name"],
454
+ :reason_code => control.elements["yt:state"].attributes["reasonCode"],
455
+ :help_url => control.elements["yt:state"].attributes["helpUrl"],
456
+ :copy => control.elements["yt:state"].text
457
+ }
458
+
459
+ end
460
+
461
+ YouTubeIt::Model::Video.new(
462
+ :video_id => video_id,
463
+ :published_at => published_at,
464
+ :updated_at => updated_at,
465
+ :categories => categories,
466
+ :keywords => keywords,
467
+ :title => title,
468
+ :html_content => html_content,
469
+ :author => author,
470
+ :description => description,
471
+ :duration => duration,
472
+ :media_content => media_content,
473
+ :player_url => player_url,
474
+ :thumbnails => thumbnails,
475
+ :rating => rating,
476
+ :view_count => view_count,
477
+ :favorite_count => favorite_count,
478
+ :widescreen => widescreen,
479
+ :noembed => noembed,
480
+ :racy => racy,
481
+ :where => where,
482
+ :position => position,
483
+ :latitude => latitude,
484
+ :longitude => longitude,
485
+ :state => state)
486
+ end
487
+
488
+ def parse_media_content (media_content_element)
489
+ content_url = media_content_element.attributes["url"]
490
+ format_code = media_content_element.attributes["yt:format"].to_i
491
+ format = YouTubeIt::Model::Video::Format.by_code(format_code)
492
+ duration = media_content_element.attributes["duration"].to_i
493
+ mime_type = media_content_element.attributes["type"]
494
+ default = (media_content_element.attributes["isDefault"] == "true")
495
+
496
+ YouTubeIt::Model::Content.new(
497
+ :url => content_url,
498
+ :format => format,
499
+ :duration => duration,
500
+ :mime_type => mime_type,
501
+ :default => default)
502
+ end
503
+ end
504
+
505
+ class VideosFeedParser < VideoFeedParser #:nodoc:
506
+
507
+ private
508
+ def parse_content(content)
509
+ videos = []
510
+ doc = REXML::Document.new(content)
511
+ feed = doc.elements["feed"]
512
+ if feed
513
+ feed_id = feed.elements["id"].text
514
+ updated_at = Time.parse(feed.elements["updated"].text)
515
+ total_result_count = feed.elements["openSearch:totalResults"].text.to_i
516
+ offset = feed.elements["openSearch:startIndex"].text.to_i
517
+ max_result_count = feed.elements["openSearch:itemsPerPage"].text.to_i
518
+
519
+ feed.elements.each("entry") do |entry|
520
+ videos << parse_entry(entry)
521
+ end
522
+ end
523
+ YouTubeIt::Response::VideoSearch.new(
524
+ :feed_id => feed_id || nil,
525
+ :updated_at => updated_at || nil,
526
+ :total_result_count => total_result_count || nil,
527
+ :offset => offset || nil,
528
+ :max_result_count => max_result_count || nil,
529
+ :videos => videos)
530
+ end
531
+ end
532
+ end
533
+ end
534
+