nddrylliog_youtube_it 2.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/Gemfile +5 -0
  2. data/Gemfile.lock +38 -0
  3. data/Manifest.txt +37 -0
  4. data/README.rdoc +296 -0
  5. data/Rakefile +21 -0
  6. data/VERSION +1 -0
  7. data/lib/youtube_it.rb +91 -0
  8. data/lib/youtube_it/chain_io.rb +76 -0
  9. data/lib/youtube_it/client.rb +469 -0
  10. data/lib/youtube_it/middleware/faraday_authheader.rb +24 -0
  11. data/lib/youtube_it/middleware/faraday_oauth.rb +21 -0
  12. data/lib/youtube_it/middleware/faraday_oauth2.rb +13 -0
  13. data/lib/youtube_it/middleware/faraday_youtubeit.rb +30 -0
  14. data/lib/youtube_it/model/activity.rb +17 -0
  15. data/lib/youtube_it/model/author.rb +13 -0
  16. data/lib/youtube_it/model/category.rb +11 -0
  17. data/lib/youtube_it/model/comment.rb +16 -0
  18. data/lib/youtube_it/model/contact.rb +19 -0
  19. data/lib/youtube_it/model/content.rb +18 -0
  20. data/lib/youtube_it/model/message.rb +12 -0
  21. data/lib/youtube_it/model/playlist.rb +11 -0
  22. data/lib/youtube_it/model/rating.rb +23 -0
  23. data/lib/youtube_it/model/subscription.rb +7 -0
  24. data/lib/youtube_it/model/thumbnail.rb +17 -0
  25. data/lib/youtube_it/model/user.rb +28 -0
  26. data/lib/youtube_it/model/video.rb +243 -0
  27. data/lib/youtube_it/parser.rb +543 -0
  28. data/lib/youtube_it/record.rb +12 -0
  29. data/lib/youtube_it/request/base_search.rb +76 -0
  30. data/lib/youtube_it/request/error.rb +15 -0
  31. data/lib/youtube_it/request/standard_search.rb +43 -0
  32. data/lib/youtube_it/request/user_search.rb +47 -0
  33. data/lib/youtube_it/request/video_search.rb +105 -0
  34. data/lib/youtube_it/request/video_upload.rb +552 -0
  35. data/lib/youtube_it/response/video_search.rb +41 -0
  36. data/lib/youtube_it/version.rb +4 -0
  37. data/test/files/recorded_response.xml +1 -0
  38. data/test/files/youtube_video_response.xml +53 -0
  39. data/test/helper.rb +9 -0
  40. data/test/test.mov +0 -0
  41. data/test/test_chain_io.rb +63 -0
  42. data/test/test_client.rb +504 -0
  43. data/test/test_field_search.rb +48 -0
  44. data/test/test_video.rb +48 -0
  45. data/test/test_video_feed_parser.rb +264 -0
  46. data/test/test_video_search.rb +147 -0
  47. data/youtube_it.gemspec +95 -0
  48. metadata +149 -0
@@ -0,0 +1,543 @@
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
+ :insight_uri => (entry.elements['link[attribute::rel="http://gdata.youtube.com/schemas/2007#insight.views"]'].attributes['href'] rescue nil)
303
+ )
304
+ end
305
+ end
306
+
307
+ class SubscriptionFeedParser < FeedParser #:nodoc:
308
+
309
+ def parse_content(content)
310
+ doc = REXML::Document.new(content.body)
311
+ feed = doc.elements["feed"]
312
+
313
+ subscriptions = []
314
+ feed.elements.each("entry") do |entry|
315
+ subscriptions << parse_entry(entry)
316
+ end
317
+ return subscriptions
318
+ end
319
+
320
+ protected
321
+
322
+ def parse_entry(entry)
323
+ YouTubeIt::Model::Subscription.new(
324
+ :title => entry.elements["title"].text,
325
+ :id => entry.elements["id"].text[/subscription([^<]+)/, 1].sub(':',''),
326
+ :published => entry.elements["published"] ? entry.elements["published"].text : nil
327
+ )
328
+ end
329
+ end
330
+
331
+
332
+ class VideoFeedParser < FeedParser #:nodoc:
333
+
334
+ def parse_content(content)
335
+ doc = (content.is_a?(REXML::Element)) ? content : REXML::Document.new(content)
336
+
337
+ entry = doc.elements["entry"]
338
+ parse_entry(entry)
339
+ end
340
+
341
+ protected
342
+ def parse_entry(entry)
343
+ video_id = entry.elements["id"].text
344
+ published_at = entry.elements["published"] ? Time.parse(entry.elements["published"].text) : nil
345
+ updated_at = entry.elements["updated"] ? Time.parse(entry.elements["updated"].text) : nil
346
+
347
+ # parse the category and keyword lists
348
+ categories = []
349
+ keywords = []
350
+ entry.elements.each("category") do |category|
351
+ # determine if it's really a category, or just a keyword
352
+ scheme = category.attributes["scheme"]
353
+ if (scheme =~ /\/categories\.cat$/)
354
+ # it's a category
355
+ categories << YouTubeIt::Model::Category.new(
356
+ :term => category.attributes["term"],
357
+ :label => category.attributes["label"])
358
+
359
+ elsif (scheme =~ /\/keywords\.cat$/)
360
+ # it's a keyword
361
+ keywords << category.attributes["term"]
362
+ end
363
+ end
364
+
365
+ title = entry.elements["title"].text
366
+ html_content = entry.elements["content"] ? entry.elements["content"].text : nil
367
+
368
+ # parse the author
369
+ author_element = entry.elements["author"]
370
+ author = nil
371
+ if author_element
372
+ author = YouTubeIt::Model::Author.new(
373
+ :name => author_element.elements["name"].text,
374
+ :uri => author_element.elements["uri"].text)
375
+ end
376
+ media_group = entry.elements["media:group"]
377
+
378
+ ytid = nil
379
+ unless media_group.elements["yt:videoid"].nil?
380
+ ytid = media_group.elements["yt:videoid"].text
381
+ end
382
+
383
+ # if content is not available on certain region, there is no media:description, media:player or yt:duration
384
+ description = ""
385
+ unless media_group.elements["media:description"].nil?
386
+ description = media_group.elements["media:description"].text
387
+ end
388
+
389
+ # if content is not available on certain region, there is no media:description, media:player or yt:duration
390
+ duration = 0
391
+ unless media_group.elements["yt:duration"].nil?
392
+ duration = media_group.elements["yt:duration"].attributes["seconds"].to_i
393
+ end
394
+
395
+ # if content is not available on certain region, there is no media:description, media:player or yt:duration
396
+ player_url = ""
397
+ unless media_group.elements["media:player"].nil?
398
+ player_url = media_group.elements["media:player"].attributes["url"]
399
+ end
400
+
401
+ unless media_group.elements["yt:aspectRatio"].nil?
402
+ widescreen = media_group.elements["yt:aspectRatio"].text == 'widescreen' ? true : false
403
+ end
404
+
405
+ media_content = []
406
+ media_group.elements.each("media:content") do |mce|
407
+ media_content << parse_media_content(mce)
408
+ end
409
+
410
+ # parse thumbnails
411
+ thumbnails = []
412
+ media_group.elements.each("media:thumbnail") do |thumb_element|
413
+ # TODO: convert time HH:MM:ss string to seconds?
414
+ thumbnails << YouTubeIt::Model::Thumbnail.new(
415
+ :url => thumb_element.attributes["url"],
416
+ :height => thumb_element.attributes["height"].to_i,
417
+ :width => thumb_element.attributes["width"].to_i,
418
+ :time => thumb_element.attributes["time"])
419
+ end
420
+
421
+ rating_element = entry.elements["gd:rating"]
422
+ extended_rating_element = entry.elements["yt:rating"]
423
+
424
+ rating = nil
425
+ if rating_element
426
+ rating_values = {
427
+ :min => rating_element.attributes["min"].to_i,
428
+ :max => rating_element.attributes["max"].to_i,
429
+ :rater_count => rating_element.attributes["numRaters"].to_i,
430
+ :average => rating_element.attributes["average"].to_f
431
+ }
432
+
433
+ if extended_rating_element
434
+ rating_values[:likes] = extended_rating_element.attributes["numLikes"].to_i
435
+ rating_values[:dislikes] = extended_rating_element.attributes["numDislikes"].to_i
436
+ end
437
+
438
+ rating = YouTubeIt::Model::Rating.new(rating_values)
439
+ end
440
+
441
+ if (el = entry.elements["yt:statistics"])
442
+ view_count, favorite_count = el.attributes["viewCount"].to_i, el.attributes["favoriteCount"].to_i
443
+ else
444
+ view_count, favorite_count = 0,0
445
+ end
446
+
447
+ noembed = entry.elements["yt:noembed"] ? true : false
448
+ safe_search = entry.elements["media:rating"] ? true : false
449
+
450
+ if where = entry.elements["georss:where"]
451
+ position = where.elements["gml:Point"].elements["gml:pos"].text
452
+ latitude, longitude = position.split(" ")
453
+ end
454
+
455
+ control = entry.elements["app:control"]
456
+ state = { :name => "published" }
457
+ if control && control.elements["yt:state"]
458
+ state = {
459
+ :name => control.elements["yt:state"].attributes["name"],
460
+ :reason_code => control.elements["yt:state"].attributes["reasonCode"],
461
+ :help_url => control.elements["yt:state"].attributes["helpUrl"],
462
+ :copy => control.elements["yt:state"].text
463
+ }
464
+
465
+ end
466
+
467
+ insight_uri = (entry.elements['link[attribute::rel="http://gdata.youtube.com/schemas/2007#insight.views"]'].attributes['href'] rescue nil)
468
+
469
+ YouTubeIt::Model::Video.new(
470
+ :video_id => video_id,
471
+ :published_at => published_at,
472
+ :updated_at => updated_at,
473
+ :categories => categories,
474
+ :keywords => keywords,
475
+ :title => title,
476
+ :html_content => html_content,
477
+ :author => author,
478
+ :description => description,
479
+ :duration => duration,
480
+ :media_content => media_content,
481
+ :player_url => player_url,
482
+ :thumbnails => thumbnails,
483
+ :rating => rating,
484
+ :view_count => view_count,
485
+ :favorite_count => favorite_count,
486
+ :widescreen => widescreen,
487
+ :noembed => noembed,
488
+ :safe_search => safe_search,
489
+ :position => position,
490
+ :latitude => latitude,
491
+ :longitude => longitude,
492
+ :state => state,
493
+ :insight_uri => insight_uri,
494
+ :unique_id => ytid)
495
+ end
496
+
497
+ def parse_media_content (media_content_element)
498
+ content_url = media_content_element.attributes["url"]
499
+ format_code = media_content_element.attributes["yt:format"].to_i
500
+ format = YouTubeIt::Model::Video::Format.by_code(format_code)
501
+ duration = media_content_element.attributes["duration"].to_i
502
+ mime_type = media_content_element.attributes["type"]
503
+ default = (media_content_element.attributes["isDefault"] == "true")
504
+
505
+ YouTubeIt::Model::Content.new(
506
+ :url => content_url,
507
+ :format => format,
508
+ :duration => duration,
509
+ :mime_type => mime_type,
510
+ :default => default)
511
+ end
512
+ end
513
+
514
+ class VideosFeedParser < VideoFeedParser #:nodoc:
515
+
516
+ private
517
+ def parse_content(content)
518
+ videos = []
519
+ doc = REXML::Document.new(content)
520
+ feed = doc.elements["feed"]
521
+ if feed
522
+ feed_id = feed.elements["id"].text
523
+ updated_at = Time.parse(feed.elements["updated"].text)
524
+ total_result_count = feed.elements["openSearch:totalResults"].text.to_i
525
+ offset = feed.elements["openSearch:startIndex"].text.to_i
526
+ max_result_count = feed.elements["openSearch:itemsPerPage"].text.to_i
527
+
528
+ feed.elements.each("entry") do |entry|
529
+ videos << parse_entry(entry)
530
+ end
531
+ end
532
+ YouTubeIt::Response::VideoSearch.new(
533
+ :feed_id => feed_id || nil,
534
+ :updated_at => updated_at || nil,
535
+ :total_result_count => total_result_count || nil,
536
+ :offset => offset || nil,
537
+ :max_result_count => max_result_count || nil,
538
+ :videos => videos)
539
+ end
540
+ end
541
+ end
542
+ end
543
+