youtube_it 1.4.3 → 2.0.0

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.
@@ -22,6 +22,51 @@ class YouTubeIt
22
22
  end
23
23
  end
24
24
 
25
+
26
+ module FieldSearch
27
+ def default_fields
28
+ "id,updated,openSearch:totalResults,openSearch:startIndex,openSearch:itemsPerPage"
29
+ end
30
+
31
+ def fields_to_params(fields)
32
+ return "" unless fields
33
+
34
+ fields_param = [default_fields]
35
+
36
+ if fields[:recorded]
37
+ if fields[:recorded].is_a? Range
38
+ fields_param << "entry[xs:date(yt:recorded) > xs:date('#{formatted_date(fields[:recorded].first)}') and xs:date(yt:recorded) < xs:date('#{formatted_date(fields[:recorded].last)}')]"
39
+ else
40
+ fields_param << "entry[xs:date(yt:recorded) = xs:date('#{formatted_date(fields[:recorded])}')]"
41
+ end
42
+ end
43
+
44
+ if fields[:published]
45
+ if fields[:published].is_a? Range
46
+ fields_param << "entry[xs:dateTime(published) > xs:dateTime('#{formatted_date(fields[:published].first)}T00:00:00') and xs:dateTime(published) < xs:dateTime('#{formatted_date(fields[:published].last)}T00:00:00')]"
47
+ else
48
+ fields_param << "entry[xs:date(published) = xs:date('#{formatted_date(fields[:published])}')]"
49
+ end
50
+ end
51
+
52
+ if fields[:view_count]
53
+ fields_param << "entry[yt:statistics/@viewCount > #{fields[:view_count]}]"
54
+ end
55
+
56
+
57
+ return "&fields=#{URI.escape(fields_param.join(","))}"
58
+ end
59
+
60
+ #youtube taked dates that look like 'YYYY-MM-DD'
61
+ def formatted_date(date)
62
+ return date if date.is_a? String
63
+ if date.respond_to? :strftime
64
+ date.strftime("%Y-%m-%d")
65
+ else
66
+ ""
67
+ end
68
+ end
69
+ end
25
70
  end
26
71
  end
27
72
 
@@ -0,0 +1,15 @@
1
+ class UploadError < YouTubeIt::Error
2
+ attr_reader :code
3
+ def initialize(msg, code = 0)
4
+ super(msg)
5
+ @code = code
6
+ end
7
+ end
8
+
9
+ class AuthenticationError < YouTubeIt::Error
10
+ attr_reader :code
11
+ def initialize(msg, code = 0)
12
+ super(msg)
13
+ @code = code
14
+ end
15
+ end
@@ -1,6 +1,7 @@
1
1
  class YouTubeIt
2
2
  module Request #:nodoc:
3
3
  class UserSearch < BaseSearch #:nodoc:
4
+ include FieldSearch
4
5
  attr_reader :max_results # max_results
5
6
  attr_reader :order_by # orderby, ([relevance], viewCount, published, rating)
6
7
  attr_reader :offset # start-index
@@ -22,6 +23,7 @@ class YouTubeIt
22
23
  end
23
24
 
24
25
  @url << build_query_params(to_youtube_params)
26
+ @url << fields_to_params(params.delete(:fields)) if params != :favorites && params[:fields]
25
27
  end
26
28
 
27
29
  private
@@ -1,6 +1,8 @@
1
1
  class YouTubeIt
2
2
  module Request #:nodoc:
3
3
  class VideoSearch < BaseSearch #:nodoc:
4
+ include FieldSearch
5
+
4
6
  # From here: http://code.google.com/apis/youtube/reference.html#yt_format
5
7
  ONLY_EMBEDDABLE = 5
6
8
 
@@ -16,7 +18,6 @@ class YouTubeIt
16
18
  attr_reader :author
17
19
  attr_reader :lang # lt
18
20
 
19
-
20
21
  def initialize(params={})
21
22
  # Initialize our various member data to avoid warnings and so we'll
22
23
  # automatically fall back to the youtube api defaults
@@ -41,6 +42,7 @@ class YouTubeIt
41
42
  end
42
43
 
43
44
  @url << build_query_params(to_youtube_params)
45
+ @url << fields_to_params(params.delete(:fields)) if params[:fields]
44
46
  end
45
47
 
46
48
  private
@@ -64,6 +66,7 @@ class YouTubeIt
64
66
  }
65
67
  end
66
68
 
69
+
67
70
  # Convert category symbols into strings and build the URL. GData requires categories to be capitalized.
68
71
  # Categories defined like: categories => { :include => [:news], :exclude => [:sports], :either => [..] }
69
72
  # or like: categories => [:news, :sports]
@@ -1,25 +1,7 @@
1
1
  class YouTubeIt
2
-
3
2
  module Upload
4
- class UploadError < YouTubeIt::Error; end
5
- class AuthenticationError < YouTubeIt::Error; end
6
-
7
- # Implements video uploads/updates/deletions
8
- #
9
- # require 'youtube_it'
10
- #
11
- # uploader = YouTubeIt::Upload::VideoUpload.new("user", "pass", "dev-key")
12
- # uploader.upload File.open("test.m4v"), :title => 'test',
13
- # :description => 'cool vid d00d',
14
- # :category => 'People',
15
- # :keywords => %w[cool blah test]
16
- #
17
3
  class VideoUpload
18
4
  include YouTubeIt::Logging
19
- def initialize user, pass, dev_key, access_token = nil, authsub_token = nil, client_id = 'youtube_it'
20
- @user, @password, @dev_key, @access_token, @authsub_token, @client_id = user, pass, dev_key, access_token, authsub_token, client_id
21
- @http_debugging = false
22
- end
23
5
 
24
6
  def initialize *params
25
7
  if params.first.is_a?(Hash)
@@ -30,6 +12,7 @@ class YouTubeIt
30
12
  @access_token = hash_options[:access_token]
31
13
  @authsub_token = hash_options[:authsub_token]
32
14
  @client_id = hash_options[:client_id] || "youtube_it"
15
+ @config_token = hash_options[:config_token]
33
16
  else
34
17
  puts "* warning: the method YouTubeIt::Upload::VideoUpload.new(username, password, dev_key) is depricated, use YouTubeIt::Upload::VideoUpload.new(:username => 'user', :password => 'passwd', :dev_key => 'dev_key')"
35
18
  @user = params.shift
@@ -38,6 +21,7 @@ class YouTubeIt
38
21
  @access_token = params.shift
39
22
  @authsub_token = params.shift
40
23
  @client_id = params.shift || "youtube_it"
24
+ @config_token = params.shift
41
25
  end
42
26
  end
43
27
 
@@ -73,7 +57,6 @@ class YouTubeIt
73
57
  #
74
58
  # When the authentication credentials are incorrect, an AuthenticationError will be raised.
75
59
  def upload(data, opts = {})
76
- response = nil
77
60
  @opts = { :mime_type => 'video/mp4',
78
61
  :title => '',
79
62
  :description => '',
@@ -90,22 +73,9 @@ class YouTubeIt
90
73
  "Content-Length" => "#{post_body_io.expected_length}",
91
74
  }
92
75
 
93
- if @access_token.nil?
94
- upload_header.merge!(authorization_headers).delete("GData-Version")
95
- http = Net::HTTP.new(uploads_url)
96
- http.set_debug_output(logger) if @http_debugging
97
- path = '/feeds/api/users/default/uploads'
98
- http.start do | session |
99
- post = Net::HTTP::Post.new(path, upload_header)
100
- post.body_stream = post_body_io
101
- response = session.request(post)
102
- end
103
- else
104
- upload_header.merge!(authorization_headers_for_oauth).delete("GData-Version")
105
- url = 'http://%s/feeds/api/users/default/uploads' % uploads_url
106
- response = @access_token.post(url, post_body_io, upload_header)
107
- end
108
- raise_on_faulty_response(response)
76
+ upload_url = "/feeds/api/users/default/uploads"
77
+ response = yt_session(uploads_url).post(upload_url, post_body_io, upload_header)
78
+
109
79
  return YouTubeIt::Parser::VideoFeedParser.new(response.body).parse
110
80
  end
111
81
 
@@ -118,53 +88,59 @@ class YouTubeIt
118
88
  # :private
119
89
  # When the authentication credentials are incorrect, an AuthenticationError will be raised.
120
90
  def update(video_id, options)
121
- response = nil
122
- @opts = options
123
- update_body = video_xml
91
+ @opts = options
92
+ update_body = video_xml
124
93
  update_header = {
125
94
  "Content-Type" => "application/atom+xml",
126
95
  "Content-Length" => "#{update_body.length}",
127
96
  }
128
97
  update_url = "/feeds/api/users/default/uploads/%s" % video_id
98
+ response = yt_session.put(update_url, update_body, update_header)
99
+
100
+ return YouTubeIt::Parser::VideoFeedParser.new(response.body).parse
101
+ end
129
102
 
130
- if @access_token.nil?
131
- update_header.merge!(authorization_headers)
132
- http_connection do |session|
133
- response = session.put(update_url, update_body, update_header)
134
- end
135
- else
136
- update_header.merge!(authorization_headers_for_oauth)
137
- response = @access_token.put("http://%s%s" % [base_url,update_url], update_body, update_header)
138
- end
139
-
140
- raise_on_faulty_response(response)
103
+ # Fetches the data of a video, which may be private. The video must be owned by this user.
104
+ # When the authentication credentials are incorrect, an AuthenticationError will be raised.
105
+ def get_my_video(video_id)
106
+ get_header = {
107
+ "Content-Type" => "application/atom+xml",
108
+ "Content-Length" => "0",
109
+ }
110
+ get_url = "/feeds/api/users/default/uploads/%s" % video_id
111
+ response = yt_session.get(get_url, get_header)
112
+
141
113
  return YouTubeIt::Parser::VideoFeedParser.new(response.body).parse
142
114
  end
143
115
 
116
+ # Fetches the data of the videos of the current user, which may be private.
117
+ # When the authentication credentials are incorrect, an AuthenticationError will be raised.
118
+ def get_my_videos(opts)
119
+ max_results = opts[:per_page] || 50
120
+ start_index = ((opts[:page] || 1) -1) * max_results +1
121
+ get_header = {
122
+ "Content-Type" => "application/atom+xml",
123
+ "Content-Length" => "0",
124
+ }
125
+ get_url = "/feeds/api/users/default/uploads?max-results=#{max_results}&start-index=#{start_index}"
126
+ response = yt_session.get(get_url, get_header)
127
+
128
+ return YouTubeIt::Parser::VideosFeedParser.new(response.body).parse
129
+ end
130
+
144
131
  # Delete a video on YouTube
145
132
  def delete(video_id)
146
- response = nil
147
133
  delete_header = {
148
134
  "Content-Type" => "application/atom+xml; charset=UTF-8",
149
135
  "Content-Length" => "0",
150
136
  }
151
137
  delete_url = "/feeds/api/users/default/uploads/%s" % video_id
138
+ response = yt_session.delete(delete_url, delete_header)
152
139
 
153
- if @access_token.nil?
154
- delete_header.merge!(authorization_headers)
155
- http_connection do |session|
156
- response = session.delete(delete_url, delete_header)
157
- end
158
- else
159
- delete_header.merge!(authorization_headers_for_oauth)
160
- response = @access_token.delete("http://%s%s" % [base_url,delete_url], delete_header)
161
- end
162
- raise_on_faulty_response(response)
163
140
  return true
164
141
  end
165
142
 
166
143
  def get_upload_token(options, nexturl)
167
- response = nil
168
144
  @opts = options
169
145
  token_body = video_xml
170
146
  token_header = {
@@ -172,23 +148,13 @@ class YouTubeIt
172
148
  "Content-Length" => "#{token_body.length}",
173
149
  }
174
150
  token_url = "/action/GetUploadToken"
175
-
176
- if @access_token.nil?
177
- token_header.merge!(authorization_headers)
178
- http_connection do |session|
179
- response = session.post(token_url, token_body, token_header)
180
- end
181
- else
182
- token_header.merge!(authorization_headers_for_oauth)
183
- response = @access_token.post("http://%s%s" % [base_url, token_url], token_body, token_header)
184
- end
185
- raise_on_faulty_response(response)
151
+ response = yt_session.post(token_url, token_body, token_header)
152
+
186
153
  return {:url => "#{response.body[/<url>(.+)<\/url>/, 1]}?nexturl=#{nexturl}",
187
154
  :token => response.body[/<token>(.+)<\/token>/, 1]}
188
155
  end
189
156
 
190
157
  def add_comment(video_id, comment)
191
- response = nil
192
158
  comment_body = video_xml_for(:comment => comment)
193
159
  comment_header = {
194
160
  "Content-Type" => "application/atom+xml",
@@ -196,265 +162,193 @@ class YouTubeIt
196
162
  }
197
163
  comment_url = "/feeds/api/videos/%s/comments" % video_id
198
164
 
199
- if @access_token.nil?
200
- comment_header.merge!(authorization_headers)
201
- http_connection do |session|
202
- response = session.post(comment_url, comment_body, comment_header)
203
- end
204
- else
205
- comment_header.merge!(authorization_headers_for_oauth)
206
- response = @access_token.post("http://%s%s" % [base_url, comment_url], comment_body, comment_header)
207
- end
208
- raise_on_faulty_response(response)
209
- {:code => response.code, :body => response.body}
165
+ response = yt_session.post(comment_url, comment_body, comment_header)
166
+
167
+ return {:code => response.status, :body => response.body}
210
168
  end
211
169
 
212
170
  def comments(video_id, opts = {})
213
171
  comment_url = "/feeds/api/videos/%s/comments?" % video_id
214
172
  comment_url << opts.collect { |k,p| [k,p].join '=' }.join('&')
215
- http_connection do |session|
216
- response = session.get(comment_url)
217
- raise_on_faulty_response(response)
218
- {:code => response.code, :body => response.body}
219
- return YouTubeIt::Parser::CommentsFeedParser.new(response).parse
220
- end
173
+ response = yt_session.get(comment_url)
174
+
175
+ return YouTubeIt::Parser::CommentsFeedParser.new(response).parse
221
176
  end
222
177
 
223
178
  def add_favorite(video_id)
224
- response = nil
225
179
  favorite_body = video_xml_for(:favorite => video_id)
226
180
  favorite_header = {
227
181
  "Content-Type" => "application/atom+xml",
228
182
  "Content-Length" => "#{favorite_body.length}",
229
183
  }
230
184
  favorite_url = "/feeds/api/users/default/favorites"
231
-
232
- if @access_token.nil?
233
- favorite_header.merge!(authorization_headers)
234
- http_connection do |session|
235
- response = session.post(favorite_url, favorite_body, favorite_header)
236
- end
237
- else
238
- favorite_header.merge!(authorization_headers_for_oauth)
239
- response = @access_token.post("http://%s%s" % [base_url, favorite_url], favorite_body, favorite_header)
240
- end
241
- raise_on_faulty_response(response)
242
- {:code => response.code, :body => response.body}
185
+ response = yt_session.post(favorite_url, favorite_body, favorite_header)
186
+
187
+ return {:code => response.status, :body => response.body}
243
188
  end
244
189
 
245
190
  def delete_favorite(video_id)
246
- response = nil
247
191
  favorite_header = {
248
192
  "Content-Type" => "application/atom+xml; charset=UTF-8",
249
193
  "Content-Length" => "0",
250
194
  }
251
195
  favorite_url = "/feeds/api/users/default/favorites/%s" % video_id
252
-
253
- if @access_token.nil?
254
- favorite_header.merge!(authorization_headers).delete("GData-Version")
255
- http_connection do |session|
256
- response = session.delete(favorite_url, favorite_header)
257
- end
258
- else
259
- favorite_header.merge!(authorization_headers_for_oauth).delete("GData-Version")
260
- response = @access_token.delete("http://%s%s" % [base_url, favorite_url], favorite_header)
261
- end
262
- raise_on_faulty_response(response)
196
+ response = yt_session.delete(favorite_url, favorite_header)
197
+
263
198
  return true
264
199
  end
265
200
 
266
- def profile(user_id)
267
- profile_url = "/feeds/api/users/%s?v=2" % user_id
268
- http_connection do |session|
269
- response = session.get(profile_url)
270
- raise_on_faulty_response(response)
271
- return YouTubeIt::Parser::ProfileFeedParser.new(response).parse
272
- end
201
+ def profile(user)
202
+ profile_url = "/feeds/api/users/%s?v=2" % (user ? user : "default")
203
+ profile_header = {
204
+ "Content-Type" => "application/atom+xml; charset=UTF-8"
205
+ }
206
+ response = yt_session.get(profile_url, profile_header)
207
+
208
+ return YouTubeIt::Parser::ProfileFeedParser.new(response).parse
273
209
  end
274
210
 
275
211
  def playlist(playlist_id)
276
212
  playlist_url = "/feeds/api/playlists/%s?v=2" % playlist_id
277
- http_connection do |session|
278
- response = session.get(playlist_url)
279
- raise_on_faulty_response(response)
280
- return YouTubeIt::Parser::PlaylistFeedParser.new(response).parse
281
- end
282
- end
283
-
284
- def playlists
285
- playlist_url = "/feeds/api/users/default/playlists?v=2"
286
- http_connection do |session|
287
- response = session.get(playlist_url)
288
- raise_on_faulty_response(response)
289
- return response.body
290
- end
213
+ response = yt_session.get(playlist_url)
214
+
215
+ return YouTubeIt::Parser::PlaylistFeedParser.new(response).parse
291
216
  end
292
217
 
293
- def playlists_for(user)
294
- playlist_url = "/feeds/api/users/#{user}/playlists?v=2"
295
- http_connection do |session|
296
- response = session.get(playlist_url)
297
- raise_on_faulty_response(response)
298
- return YouTubeIt::Parser::PlaylistsFeedParser.new(response).parse #return response.body
299
- end
218
+ def playlists(user)
219
+ playlist_url = "/feeds/api/users/%s/playlists?v=2" % (user ? user : "default")
220
+ response = yt_session.get(playlist_url)
221
+
222
+ return YouTubeIt::Parser::PlaylistsFeedParser.new(response).parse
300
223
  end
301
-
224
+
302
225
  def add_playlist(options)
303
- response = nil
304
226
  playlist_body = video_xml_for_playlist(options)
305
227
  playlist_header = {
306
228
  "Content-Type" => "application/atom+xml",
307
229
  "Content-Length" => "#{playlist_body.length}",
308
230
  }
309
231
  playlist_url = "/feeds/api/users/default/playlists"
310
-
311
- if @access_token.nil?
312
- playlist_header.merge!(authorization_headers)
313
- http_connection do |session|
314
- response = session.post(playlist_url, playlist_body, playlist_header)
315
- end
316
- else
317
- playlist_header.merge!(authorization_headers_for_oauth)
318
- response = @access_token.post("http://%s%s" % [base_url, playlist_url], playlist_body, playlist_header)
319
- end
320
- raise_on_faulty_response(response)
232
+ response = yt_session.post(playlist_url, playlist_body, playlist_header)
233
+
321
234
  return YouTubeIt::Parser::PlaylistFeedParser.new(response).parse
322
235
  end
323
236
 
324
237
  def add_video_to_playlist(playlist_id, video_id)
325
- response = nil
326
238
  playlist_body = video_xml_for(:playlist => video_id)
327
239
  playlist_header = {
328
240
  "Content-Type" => "application/atom+xml",
329
241
  "Content-Length" => "#{playlist_body.length}",
330
242
  }
331
243
  playlist_url = "/feeds/api/playlists/%s" % playlist_id
332
-
333
- if @access_token.nil?
334
- playlist_header.merge!(authorization_headers)
335
- http_connection do |session|
336
- response = session.post(playlist_url, playlist_body, playlist_header)
337
- end
338
- else
339
- playlist_header.merge!(authorization_headers_for_oauth)
340
- response = @access_token.post("http://%s%s" % [base_url, playlist_url], playlist_body, playlist_header)
341
- end
342
- raise_on_faulty_response(response)
343
- {:code => response.code, :body => response.body, :playlist_entry_id => playlist_entry_id_from_playlist(response.body)}
244
+ response = yt_session.post(playlist_url, playlist_body, playlist_header)
245
+
246
+ return {:code => response.status, :body => response.body, :playlist_entry_id => playlist_entry_id_from_playlist(response.body)}
344
247
  end
345
248
 
346
249
  def update_playlist(playlist_id, options)
347
- response = nil
348
250
  playlist_body = video_xml_for_playlist(options)
349
251
  playlist_header = {
350
252
  "Content-Type" => "application/atom+xml",
351
253
  "Content-Length" => "#{playlist_body.length}",
352
254
  }
353
255
  playlist_url = "/feeds/api/users/default/playlists/%s" % playlist_id
354
-
355
- if @access_token.nil?
356
- playlist_header.merge!(authorization_headers)
357
- http_connection do |session|
358
- response = session.put(playlist_url, playlist_body, playlist_header)
359
- end
360
- else
361
- playlist_header.merge!(authorization_headers_for_oauth)
362
- response = @access_token.put("http://%s%s" % [base_url, playlist_url], playlist_body, playlist_header)
363
- end
364
- raise_on_faulty_response(response)
256
+ response = yt_session.put(playlist_url, playlist_body, playlist_header)
257
+
365
258
  return YouTubeIt::Parser::PlaylistFeedParser.new(response).parse
366
259
  end
367
260
 
368
261
  def delete_video_from_playlist(playlist_id, playlist_entry_id)
369
- response = nil
370
262
  playlist_header = {
371
263
  "Content-Type" => "application/atom+xml",
372
264
  }
373
265
  playlist_url = "/feeds/api/playlists/%s/%s" % [playlist_id, playlist_entry_id]
374
-
375
- if @access_token.nil?
376
- playlist_header.merge!(authorization_headers)
377
- http_connection do |session|
378
- response = session.delete(playlist_url, playlist_header)
379
- end
380
- else
381
- playlist_header.merge!(authorization_headers_for_oauth)
382
- response = @access_token.delete("http://%s%s" % [base_url, playlist_url], playlist_header)
383
- end
384
- raise_on_faulty_response(response)
266
+ response = yt_session.delete(playlist_url, playlist_header)
267
+
385
268
  return true
386
269
  end
387
270
 
388
271
  def delete_playlist(playlist_id)
389
- response = nil
390
- playlist_header = {
391
- "Content-Type" => "application/atom+xml; charset=UTF-8",
272
+ playlist_header = {
273
+ "Content-Type" => "application/atom+xml; charset=UTF-8",
392
274
  }
393
- playlist_url = "/feeds/api/users/default/playlists/%s" % playlist_id
394
-
395
- if @access_token.nil?
396
- playlist_header.merge!(authorization_headers)
397
- http_connection do |session|
398
- response = session.delete(playlist_url, playlist_header)
399
- end
400
- else
401
- playlist_header.merge!(authorization_headers_for_oauth)
402
- response = @access_token.delete("http://%s%s" % [base_url, playlist_url], playlist_header)
403
- end
404
- raise_on_faulty_response(response)
275
+ playlist_url = "/feeds/api/users/default/playlists/%s" % playlist_id
276
+ response = yt_session.delete(playlist_url, playlist_header)
277
+
405
278
  return true
406
279
  end
407
280
 
408
- def favorites(opts = {})
409
- favorite_url = "/feeds/api/users/default/favorites?#{opts.to_param}"
410
- if @access_token.nil?
411
- http_connection do |session|
412
- response = session.get(favorite_url)
413
- end
414
- else
415
- response = @access_token.get("http://%s%s" % [base_url, favorite_url])
416
- end
417
- raise_on_faulty_response(response)
281
+ def rate_video(video_id, rating)
282
+ rating_body = video_xml_for(:rating => rating)
283
+ rating_header = {
284
+ "Content-Type" => "application/atom+xml",
285
+ "Content-Length" => "#{rating_body.length}",
286
+ }
287
+ rating_url = "/feeds/api/videos/#{video_id}/ratings"
288
+ response = yt_session.post(rating_url, rating_body, rating_header)
289
+
290
+ return {:code => response.status, :body => response.body}
291
+ end
292
+
293
+ def subscriptions(user)
294
+ subscription_url = "/feeds/api/users/%s/subscriptions?v=2" % (user ? user : "default")
295
+ subscription_header = {
296
+ "Content-Type" => "application/atom+xml",
297
+ }
298
+ response = yt_session.get(subscription_url, subscription_header)
299
+
300
+ return YouTubeIt::Parser::SubscriptionFeedParser.new(response).parse
301
+ end
302
+
303
+ def subscribe_channel(channel_name)
304
+ subscribe_body = video_xml_for(:subscribe => channel_name)
305
+ subscribe_header = {
306
+ "Content-Type" => "application/atom+xml",
307
+ "Content-Length" => "#{subscribe_body.length}",
308
+ }
309
+ subscribe_url = "/feeds/api/users/default/subscriptions"
310
+ response = yt_session.post(subscribe_url, subscribe_body, subscribe_header)
311
+
312
+ return {:code => response.status, :body => response.body}
313
+ end
314
+
315
+ def unsubscribe_channel(subscription_id)
316
+ unsubscribe_header = {
317
+ "Content-Type" => "application/atom+xml"
318
+ }
319
+ unsubscribe_url = "/feeds/api/users/default/subscriptions/%s" % subscription_id
320
+ response = yt_session.delete(unsubscribe_url, unsubscribe_header)
321
+
322
+ return {:code => response.status, :body => response.body}
323
+ end
324
+
325
+ def favorites(user, opts = {})
326
+ favorite_url = "/feeds/api/users/%s/favorites#{opts.empty? ? '' : '?#{opts.to_param}'}" % (user ? user : "default")
327
+ response = yt_session.get(favorite_url)
418
328
  return YouTubeIt::Parser::VideosFeedParser.new(response.body).parse
419
329
  end
420
330
 
421
331
  def get_current_user
422
332
  current_user_url = "/feeds/api/users/default"
423
- response = ''
424
- if @access_token.nil?
425
- http_connection do |session|
426
- response = session.get2(current_user_url, authorization_headers)
427
- end
428
- else
429
- response = @access_token.get("http://gdata.youtube.com/feeds/api/users/default")
430
- end
333
+ response = yt_session.get(current_user_url, authorization_headers)
431
334
 
432
- raise_on_faulty_response(response)
433
- REXML::Document.new(response.body).elements["entry"].elements['author'].elements['name'].text
335
+ return REXML::Document.new(response.body).elements["entry"].elements['author'].elements['name'].text
434
336
  end
435
337
 
436
338
  private
437
339
 
438
340
  def uploads_url
439
- ["uploads", base_url].join('.')
341
+ ["http://uploads", base_url.sub("http://","")].join('.')
440
342
  end
441
343
 
442
344
  def base_url
443
- "gdata.youtube.com"
345
+ "http://gdata.youtube.com"
444
346
  end
445
347
 
446
348
  def boundary
447
349
  "An43094fu"
448
350
  end
449
351
 
450
- def authorization_headers_for_oauth
451
- {
452
- "X-GData-Client" => "#{@client_id}",
453
- "X-GData-Key" => "key=#{@dev_key}",
454
- "GData-Version" => "2",
455
- }
456
- end
457
-
458
352
  def authorization_headers
459
353
  header = {
460
354
  "X-GData-Client" => "#{@client_id}",
@@ -463,42 +357,12 @@ class YouTubeIt
463
357
  }
464
358
  if @authsub_token
465
359
  header.merge!("Authorization" => "AuthSub token=#{@authsub_token}")
466
- else
360
+ elsif @access_token.nil? && @authsub_token.nil?
467
361
  header.merge!("Authorization" => "GoogleLogin auth=#{auth_token}")
468
362
  end
469
363
  header
470
364
  end
471
365
 
472
- def parse_upload_error_from(string)
473
- begin
474
- REXML::Document.new(string).elements["//errors"].inject('') do | all_faults, error|
475
- if error.elements["internalReason"]
476
- msg_error = error.elements["internalReason"].text
477
- elsif error.elements["location"]
478
- msg_error = error.elements["location"].text[/media:group\/media:(.*)\/text\(\)/,1]
479
- else
480
- msg_error = "Unspecified error"
481
- end
482
- code = error.elements["code"].text if error.elements["code"]
483
- all_faults + sprintf("%s: %s\n", msg_error, code)
484
- end
485
- rescue
486
- string[/<TITLE>(.+)<\/TITLE>/, 1] || string
487
- end
488
- end
489
-
490
- def raise_on_faulty_response(response)
491
- response_code = response.code.to_i
492
- msg = parse_upload_error_from(response.body.gsub(/\n/, ''))
493
-
494
- if response_code == 403 || response_code == 401
495
- #if response_code / 10 == 40
496
- raise AuthenticationError, msg
497
- elsif response_code / 10 != 20 # Response in 20x means success
498
- raise UploadError, msg
499
- end
500
- end
501
-
502
366
  def uploaded_video_id_from(string)
503
367
  xml = REXML::Document.new(string)
504
368
  xml.elements["//id"].text[/videos\/(.+)/, 1]
@@ -526,11 +390,10 @@ class YouTubeIt
526
390
 
527
391
  def auth_token
528
392
  @auth_token ||= begin
529
- http = Net::HTTP.new("www.google.com", 443)
530
- http.use_ssl = true
393
+ http = Faraday.new("https://www.google.com")
531
394
  body = "Email=#{YouTubeIt.esc @user}&Passwd=#{YouTubeIt.esc @password}&service=youtube&source=#{YouTubeIt.esc @client_id}"
532
395
  response = http.post("/youtube/accounts/ClientLogin", body, "Content-Type" => "application/x-www-form-urlencoded")
533
- raise UploadError, response.body[/Error=(.+)/,1] if response.code.to_i != 200
396
+ raise ::AuthenticationError.new(response.body[/Error=(.+)/,1], response.status.to_i) if response.status.to_i != 200
534
397
  @auth_token = response.body[/Auth=(.+)/, 1]
535
398
  end
536
399
  end
@@ -564,6 +427,11 @@ class YouTubeIt
564
427
  b.entry(:xmlns => "http://www.w3.org/2005/Atom", 'xmlns:yt' => "http://gdata.youtube.com/schemas/2007") do | m |
565
428
  m.content(data[:comment]) if data[:comment]
566
429
  m.id(data[:favorite] || data[:playlist]) if data[:favorite] || data[:playlist]
430
+ m.tag!("yt:rating", :value => data[:rating]) if data[:rating]
431
+ if(data[:subscribe])
432
+ m.category(:scheme => "http://gdata.youtube.com/schemas/2007/subscriptiontypes.cat", :term => "channel")
433
+ m.tag!("yt:username", data[:subscribe])
434
+ end
567
435
  end.to_s
568
436
  end
569
437
 
@@ -599,11 +467,12 @@ class YouTubeIt
599
467
  end
600
468
  end
601
469
 
602
- def http_connection
603
- http = Net::HTTP.new(base_url)
604
- http.set_debug_output(logger) if @http_debugging
605
- http.start do |session|
606
- yield(session)
470
+ def yt_session(url = nil)
471
+ Faraday.new(:url => url ? url : base_url) do |builder|
472
+ builder.use Faraday::Request::OAuth, @config_token if @config_token
473
+ builder.use Faraday::Request::AuthHeader, authorization_headers
474
+ builder.use Faraday::Response::YouTubeIt
475
+ builder.adapter Faraday.default_adapter
607
476
  end
608
477
  end
609
478
  end