natedaiger-youtube-g 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.txt CHANGED
@@ -54,6 +54,11 @@ Standard feeds:
54
54
  Advanced queries (with boolean operators OR (either), AND (include), NOT (exclude)):
55
55
 
56
56
  client.videos_by(:categories => { :either => [:news, :sports], :exclude => [:comedy] }, :tags => { :include => ['football'], :exclude => ['soccer'] })
57
+
58
+ Comment feeds for videos:
59
+ client.comments_for('some_youtube_id').comments
60
+ video = client.video_by('some_youtube_id')
61
+ video.comments_seach(:page => 2, :per_page => 12).comments
57
62
 
58
63
  == LOGGING
59
64
 
data/lib/youtube_g.rb CHANGED
@@ -50,6 +50,7 @@ end
50
50
  parser
51
51
  model/author
52
52
  model/category
53
+ model/comment
53
54
  model/contact
54
55
  model/content
55
56
  model/playlist
@@ -58,10 +59,12 @@ end
58
59
  model/user
59
60
  model/video
60
61
  request/base_search
62
+ request/comments_search
61
63
  request/user_search
62
64
  request/standard_search
63
65
  request/video_upload
64
66
  request/video_search
67
+ response/comments_search
65
68
  response/video_search
66
69
  chain_io
67
70
  ).each{|m| require File.dirname(__FILE__) + '/youtube_g/' + m }
@@ -70,6 +70,21 @@ class YouTubeG
70
70
  parser = YouTubeG::Parser::VideoFeedParser.new(video_id)
71
71
  parser.parse
72
72
  end
73
+
74
+ # Retrieves a single YouTube video.
75
+ #
76
+ # === Parameters
77
+ # vid<String>:: The ID of the video whose contents you'd like to retrieve
78
+ #
79
+ # options<Hash> (optional):: Accepts the options of :page (default is 1),
80
+ # and :per_page (default is 25). :offset and :max_results
81
+ # can also be passed for a custom offset.
82
+ # === Returns
83
+ # YouTubeG::Response::CommentsSearch
84
+ def comments_for(vid, options={})
85
+ url = YouTubeG::Request::CommentsSearch.new(vid, options).url
86
+ YouTubeG::Parser::CommentsFeedParser.new(url).parse
87
+ end
73
88
 
74
89
  private
75
90
 
@@ -136,6 +136,16 @@ class YouTubeG
136
136
  def responses
137
137
  YouTubeG::Parser::VideosFeedParser.new("http://gdata.youtube.com/feeds/api/videos/#{unique_id}/responses").parse
138
138
  end
139
+
140
+ # Comments on the current video.
141
+ #
142
+ # === Returns
143
+ # YouTubeG::Response::CommentsSearch
144
+ def comments_search(options={})
145
+ url = YouTubeG::Request::CommentsSearch.new(unique_id,options).url
146
+ YouTubeG::Parser::CommentsFeedParser.new(url).parse
147
+ end
148
+
139
149
 
140
150
  # The ID of the video, useful for searching for the video again without having to store it anywhere.
141
151
  # A regular query search, with this id will return the same video.
@@ -21,6 +21,23 @@ class YouTubeG
21
21
  protected
22
22
  def parse_entry(entry)
23
23
  video_id = entry.elements["id"].text
24
+
25
+ if entry.elements["app:control/yt:state"]
26
+ # yt:state generally indicates a video is unavailable
27
+ # see: http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_yt:state
28
+ unless entry.elements["app:control/yt:state[@name='restricted']"]
29
+ # the exception I've found is for *restricted* videos, which generally
30
+ # means they're not available for viewing on a device other than a web browser
31
+ # or in a certain region
32
+ return nil
33
+ end
34
+ end
35
+
36
+ # if there's no content we're going to puke later
37
+ unless entry.elements['content']
38
+ return nil
39
+ end
40
+
24
41
  published_at = Time.parse(entry.elements["published"].text)
25
42
  updated_at = Time.parse(entry.elements["updated"].text)
26
43
 
@@ -157,7 +174,9 @@ class YouTubeG
157
174
 
158
175
  videos = []
159
176
  feed.elements.each("entry") do |entry|
160
- videos << parse_entry(entry)
177
+ if video = parse_entry(entry)
178
+ videos << video
179
+ end
161
180
  end
162
181
 
163
182
  YouTubeG::Response::VideoSearch.new(
@@ -169,6 +188,60 @@ class YouTubeG
169
188
  :videos => videos)
170
189
  end
171
190
  end
191
+
192
+ class CommentsFeedParser < FeedParser
172
193
 
194
+ def parse_content(content)
195
+ doc = REXML::Document.new(content)
196
+ feed = doc.elements['feed']
197
+
198
+ feed_id = feed.elements["id"].text
199
+ updated_at = Time.parse(feed.elements["updated"].text)
200
+ total_result_count = feed.elements["openSearch:totalResults"].text.to_i
201
+ offset = feed.elements["openSearch:startIndex"].text.to_i
202
+ max_result_count = feed.elements["openSearch:itemsPerPage"].text.to_i
203
+
204
+ comments = []
205
+ feed.elements.each('entry') do |entry|
206
+ comments << parse_entry(entry)
207
+ end
208
+ YouTubeG::Response::CommentsSearch.new(
209
+ :feed_id => feed_id,
210
+ :updated_at => updated_at,
211
+ :total_result_count => total_result_count,
212
+ :offset => offset,
213
+ :max_result_count => max_result_count,
214
+ :comments => comments)
215
+ end
216
+
217
+ private
218
+ def parse_entry(entry)
219
+ comment_id = entry.elements["id"].text
220
+
221
+ published_at = Time.parse(entry.elements["published"].text)
222
+ updated_at = Time.parse(entry.elements["updated"].text)
223
+
224
+ title = entry.elements["title"].text
225
+ content = entry.elements["content"].text
226
+
227
+ # parse the author
228
+ author_element = entry.elements["author"]
229
+ author = nil
230
+ if author_element
231
+ author = YouTubeG::Model::Author.new(
232
+ :name => author_element.elements["name"].text,
233
+ :uri => author_element.elements["uri"].text)
234
+ end
235
+
236
+
237
+ comment = YouTubeG::Model::Comment.new(
238
+ :published_at => published_at,
239
+ :updated_at => updated_at,
240
+ :title => title,
241
+ :content => content,
242
+ :author => author)
243
+ return comment
244
+ end
245
+ end
173
246
  end
174
247
  end
@@ -1,3 +1,3 @@
1
1
  class YouTubeG
2
- VERSION = '0.5.1'
2
+ VERSION = '0.6.0'
3
3
  end
data/test/test_client.rb CHANGED
@@ -149,7 +149,8 @@ class TestClient < Test::Unit::TestCase
149
149
 
150
150
  def test_should_get_videos_for_query_search_with_categories_excluded
151
151
  video = @client.video_by("EkF4JD2rO3Q")
152
- 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
152
+ # assert_equal "<object width=\"425\" height=\"350\">\n <param name=\"movie\" value=\"http://www.youtube.com/v/EkF4JD2rO3Q&feature=youtube_gdata\"></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
153
+ assert_equal "<object width=\"425\" height=\"350\">\n <param name=\"movie\" value=\"http://www.youtube.com/v/EkF4JD2rO3Q&feature=youtube_gdata\"></param>\n <param name=\"wmode\" value=\"transparent\"></param>\n <embed src=\"http://www.youtube.com/v/EkF4JD2rO3Q&feature=youtube_gdata\" type=\"application/x-shockwave-flash\" \n wmode=\"transparent\" width=\"425\" height=\"350\"></embed>\n</object>\n", video.embed_html
153
154
  assert_valid_video video
154
155
  end
155
156
 
metadata CHANGED
@@ -1,12 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: natedaiger-youtube-g
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 5
8
- - 1
9
- version: 0.5.1
4
+ version: 0.6.0
10
5
  platform: ruby
11
6
  authors:
12
7
  - Shane Vitarana
@@ -23,30 +18,24 @@ default_executable:
23
18
  dependencies:
24
19
  - !ruby/object:Gem::Dependency
25
20
  name: builder
26
- prerelease: false
27
- requirement: &id001 !ruby/object:Gem::Requirement
21
+ type: :runtime
22
+ version_requirement:
23
+ version_requirements: !ruby/object:Gem::Requirement
28
24
  requirements:
29
25
  - - ">="
30
26
  - !ruby/object:Gem::Version
31
- segments:
32
- - 0
33
27
  version: "0"
34
- type: :runtime
35
- version_requirements: *id001
28
+ version:
36
29
  - !ruby/object:Gem::Dependency
37
30
  name: hoe
38
- prerelease: false
39
- requirement: &id002 !ruby/object:Gem::Requirement
31
+ type: :development
32
+ version_requirement:
33
+ version_requirements: !ruby/object:Gem::Requirement
40
34
  requirements:
41
35
  - - ">="
42
36
  - !ruby/object:Gem::Version
43
- segments:
44
- - 1
45
- - 8
46
- - 3
47
37
  version: 1.8.3
48
- type: :development
49
- version_requirements: *id002
38
+ version:
50
39
  description: "youtube-g is a pure Ruby client for the YouTube GData API. It provides an easy way to access the latest YouTube video search results from your own programs. In comparison with the earlier Youtube search interfaces, this new API and library offers much-improved flexibility around executing complex search queries to obtain well-targeted video search results. More detail on the underlying source Google-provided API is available at: http://code.google.com/apis/youtube/overview.html"
51
40
  email: shanev@gmail.com
52
41
  executables: []
@@ -104,20 +93,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
104
93
  requirements:
105
94
  - - ">="
106
95
  - !ruby/object:Gem::Version
107
- segments:
108
- - 0
109
96
  version: "0"
97
+ version:
110
98
  required_rubygems_version: !ruby/object:Gem::Requirement
111
99
  requirements:
112
100
  - - ">="
113
101
  - !ruby/object:Gem::Version
114
- segments:
115
- - 0
116
102
  version: "0"
103
+ version:
117
104
  requirements: []
118
105
 
119
106
  rubyforge_project: youtube-g
120
- rubygems_version: 1.3.6
107
+ rubygems_version: 1.3.5
121
108
  signing_key:
122
109
  specification_version: 2
123
110
  summary: Ruby client for the YouTube GData API