youtube_it 1.4.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt CHANGED
@@ -18,11 +18,15 @@ lib/youtube_it/model/video.rb
18
18
  lib/youtube_it/parser.rb
19
19
  lib/youtube_it/record.rb
20
20
  lib/youtube_it/request/base_search.rb
21
+ lib/youtube_it/request/error.rb
21
22
  lib/youtube_it/request/standard_search.rb
22
23
  lib/youtube_it/request/user_search.rb
23
24
  lib/youtube_it/request/video_search.rb
24
25
  lib/youtube_it/request/video_upload.rb
25
26
  lib/youtube_it/response/video_search.rb
27
+ lib/youtube_it/middleware/faraday_authheader.rb
28
+ lib/youtube_it/middleware/faraday_oauth.rb
29
+ lib/youtube_it/middleware/faraday_youtubeit.rb
26
30
  lib/youtube_it/version.rb
27
31
  test/helper.rb
28
32
  test/test_chain_io.rb
data/README.rdoc CHANGED
@@ -13,6 +13,8 @@
13
13
  * Create a developer key here http://code.google.com/apis/youtube/dashboard.
14
14
  * sudo gem install youtube_it
15
15
 
16
+ Note: youtube_it supports ClientLogin(YouTube account), OAuth or AuthSub authentication methods.
17
+
16
18
  == ESTABLISHING A CLIENT
17
19
 
18
20
  Creating a client:
@@ -52,9 +54,20 @@ Standard Queries:
52
54
  Advanced Queries (with boolean operators OR (either), AND (include), NOT (exclude)):
53
55
  $ client.videos_by(:categories => { :either => [:news, :sports], :exclude => [:comedy] }, :tags => { :include => ['football'], :exclude => ['soccer'] })
54
56
 
57
+
58
+ Fields Parameter(experimental features):
59
+ Return videos more than 1000 views
60
+ $ client.videos_by(:fields => {:view_count => "1000"})
61
+ Filter by date
62
+ $ client.videos_by(:fields => {:published => ((Date.today)})
63
+ $ client.videos_by(:fields => {:recorded => ((Date.today)})
64
+ Filter by date with range
65
+ $ client.videos_by(:fields => {:published => ((Date.today - 30)..(Date.today))})
66
+ $ client.videos_by(:fields => {:recorded => ((Date.today - 30)..(Date.today))})
67
+
55
68
  == VIDEO MANAGEMENT
56
69
 
57
- Note: YouTube account or OAuth enables video management.
70
+ Note: YouTube account, OAuth or AuthSub enables video management.
58
71
 
59
72
  Upload Video:
60
73
  $ client.video_upload(File.open("test.mov"), :title => "test",:description => 'some description', :category => 'People',:keywords => %w[cool blah test])
@@ -68,6 +81,12 @@ Update Video:
68
81
  Delete Video:
69
82
  $ client.video_delete("FQK1URcxmb4")
70
83
 
84
+ My Videos:
85
+ $ client.my_videos
86
+
87
+ My Video:
88
+ $ client.my_video(video_id)
89
+
71
90
  Profile Details:
72
91
  $ client.profile(user_id)
73
92
 
@@ -78,7 +97,7 @@ Add A Comment:
78
97
  $ client.add_comment(video_id, "test comment!")
79
98
 
80
99
  List Favorites:
81
- $ client.favorites
100
+ $ client.favorites(user) # current user by default
82
101
 
83
102
  Add Favorite:
84
103
  $ client.add_favorite(video_id)
@@ -86,8 +105,23 @@ Add Favorite:
86
105
  Delete Favorite:
87
106
  $ client.delete_favorite(video_id)
88
107
 
108
+ Like A Video:
109
+ $ client.like_video(video_id)
110
+
111
+ Dislike A Video:
112
+ $ client.dislike_video(video_id)
113
+
114
+ List Subscriptions:
115
+ $ client.subscriptions(user) #default: current user
116
+
117
+ Subscribe To A Channel:
118
+ $ client.subscribe_channel(channel_name)
119
+
120
+ Unsubscribe To A Channel:
121
+ $ client.unsubscribe_channel(subscription_id)
122
+
89
123
  List Playlists:
90
- $ client.playlists
124
+ $ client.playlists(user) # current user by default
91
125
 
92
126
  Select Playlist:
93
127
  $ client.playlist(playlist_id)
@@ -107,9 +141,6 @@ Add Video To Playlist:
107
141
 
108
142
  Remove Video From Playlist:
109
143
  $ client.remove_video_from_playlist(playlist_id, playlist_entry_id)
110
-
111
- Select Playlists From User:
112
- $ client.playlists_for(user)
113
144
 
114
145
  == ACCESS CONTROL LIST
115
146
 
data/Rakefile CHANGED
@@ -10,6 +10,8 @@ begin
10
10
  gem.email = "kylejginavan@gmail.com"
11
11
  gem.homepage = "http://github.com/kylejginavan/youtube_it"
12
12
  gem.add_dependency('oauth','>=0.4.4')
13
+ gem.add_dependency('simple_oauth', '>=0.1.5')
14
+ gem.add_dependency('faraday','>=0.7.3')
13
15
  gem.add_dependency('builder')
14
16
  gem.authors = ["kylejginavan","chebyte", "mseppae"]
15
17
  end
@@ -38,8 +40,6 @@ rescue LoadError
38
40
  end
39
41
  end
40
42
 
41
- task :test => :check_dependencies
42
-
43
43
  task :default => :test
44
44
 
45
45
  require 'rake/rdoctask'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.4.3
1
+ 2.0.0
data/lib/youtube_it.rb CHANGED
@@ -5,6 +5,7 @@ require 'digest/md5'
5
5
  require 'rexml/document'
6
6
  require 'builder'
7
7
  require 'oauth'
8
+ require 'faraday'
8
9
 
9
10
  class YouTubeIt
10
11
 
@@ -56,14 +57,19 @@ end
56
57
  model/content
57
58
  model/playlist
58
59
  model/rating
60
+ model/subscription
59
61
  model/thumbnail
60
62
  model/user
61
63
  model/video
62
64
  request/base_search
65
+ request/error
63
66
  request/user_search
64
67
  request/standard_search
65
68
  request/video_upload
66
69
  request/video_search
67
70
  response/video_search
71
+ middleware/faraday_authheader.rb
72
+ middleware/faraday_oauth.rb
73
+ middleware/faraday_youtubeit.rb
68
74
  chain_io
69
75
  ).each{|m| require File.dirname(__FILE__) + '/youtube_it/' + m }
@@ -11,7 +11,7 @@ class YouTubeIt
11
11
  @dev_key = hash_options[:dev_key]
12
12
  @client_id = hash_options[:client_id] || "youtube_it"
13
13
  @legacy_debug_flag = hash_options[:debug]
14
- else
14
+ elsif params.first
15
15
  puts "* warning: the method YouTubeIt::Client.new(user, passwd, dev_key) is deprecated, use YouTubeIt::Client.new(:username => 'user', :password => 'passwd', :dev_key => 'dev_key')"
16
16
  @user = params.shift
17
17
  @pass = params.shift
@@ -130,24 +130,20 @@ class YouTubeIt
130
130
  client.delete_favorite(video_id)
131
131
  end
132
132
 
133
- def favorites(opts = {})
134
- client.favorites(opts)
133
+ def favorites(user = nil, opts = {})
134
+ client.favorites(user, opts)
135
135
  end
136
136
 
137
- def profile(user_id)
138
- client.profile(user_id)
137
+ def profile(user = nil)
138
+ client.profile(user)
139
139
  end
140
140
 
141
141
  def playlist(playlist_id)
142
142
  client.playlist playlist_id
143
143
  end
144
144
 
145
- def playlists
146
- client.playlists
147
- end
148
-
149
- def playlists_for(user)
150
- client.playlists_for(user)
145
+ def playlists(user = nil)
146
+ client.playlists(user)
151
147
  end
152
148
 
153
149
  def add_playlist(options)
@@ -170,6 +166,26 @@ class YouTubeIt
170
166
  client.delete_playlist(playlist_id)
171
167
  end
172
168
 
169
+ def like_video(video_id)
170
+ client.rate_video(video_id, 'like')
171
+ end
172
+
173
+ def dislike_video(video_id)
174
+ client.rate_video(video_id, 'dislike')
175
+ end
176
+
177
+ def subscribe_channel(channel_name)
178
+ client.subscribe_channel(channel_name)
179
+ end
180
+
181
+ def unsubscribe_channel(subscription_id)
182
+ client.unsubscribe_channel(subscription_id)
183
+ end
184
+
185
+ def subscriptions(user_id = nil)
186
+ client.subscriptions(user_id)
187
+ end
188
+
173
189
  def enable_http_debugging
174
190
  client.enable_http_debugging
175
191
  end
@@ -177,6 +193,16 @@ class YouTubeIt
177
193
  def current_user
178
194
  client.get_current_user
179
195
  end
196
+
197
+ # Gets the authenticated users video with the given ID. It may be private.
198
+ def my_video(video_id)
199
+ client.get_my_video(video_id)
200
+ end
201
+
202
+ # Gets all videos
203
+ def my_videos(opts = {})
204
+ client.get_my_videos(opts)
205
+ end
180
206
 
181
207
  private
182
208
 
@@ -299,6 +325,15 @@ class YouTubeIt
299
325
  @access_token = ::OAuth::AccessToken.new(consumer, @atoken, @asecret)
300
326
  end
301
327
 
328
+ def config_token
329
+ {
330
+ :consumer_key => @consumer_key,
331
+ :consumer_secret => @consumer_secret,
332
+ :token => @atoken,
333
+ :token_secret => @asecret
334
+ }
335
+ end
336
+
302
337
  def authorize_from_request(rtoken,rsecret,verifier)
303
338
  request_token = ::OAuth::RequestToken.new(consumer,rtoken,rsecret)
304
339
  access_token = request_token.get_access_token({:oauth_verifier => verifier})
@@ -318,7 +353,7 @@ class YouTubeIt
318
353
 
319
354
  def client
320
355
  # IMPORTANT: make sure authorize_from_access is called before client is fetched
321
- @client ||= YouTubeIt::Upload::VideoUpload.new(:username => current_user, :dev_key => @dev_key, :access_token => access_token)
356
+ @client ||= YouTubeIt::Upload::VideoUpload.new(:username => current_user, :dev_key => @dev_key, :access_token => access_token, :config_token => config_token)
322
357
  end
323
358
 
324
359
  end
@@ -0,0 +1,13 @@
1
+ module Faraday
2
+ class Request::AuthHeader < Faraday::Middleware
3
+
4
+ def call(env)
5
+ env[:request_headers].merge!(@headers)
6
+ @app.call(env)
7
+ end
8
+
9
+ def initialize(app, headers)
10
+ @app, @headers = app, headers
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ module Faraday
2
+ class Request::OAuth < Faraday::Middleware
3
+ dependency 'simple_oauth'
4
+
5
+ def call(env)
6
+ params = env[:body].is_a?(Hash) ? env[:body] : {}
7
+
8
+ signature_params = params.reject{ |k,v| v.respond_to?(:content_type) }
9
+
10
+ header = SimpleOAuth::Header.new(env[:method], env[:url], signature_params, @options)
11
+
12
+ env[:request_headers]['Authorization'] = header.to_s
13
+
14
+ @app.call(env)
15
+ end
16
+
17
+ def initialize(app, options)
18
+ @app, @options = app, options
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ module Faraday
2
+ class Response::YouTubeIt < Response::Middleware
3
+ def parse_upload_error_from(string)
4
+ begin
5
+ REXML::Document.new(string).elements["//errors"].inject('') do | all_faults, error|
6
+ if error.elements["internalReason"]
7
+ msg_error = error.elements["internalReason"].text
8
+ elsif error.elements["location"]
9
+ msg_error = error.elements["location"].text[/media:group\/media:(.*)\/text\(\)/,1]
10
+ else
11
+ msg_error = "Unspecified error"
12
+ end
13
+ code = error.elements["code"].text if error.elements["code"]
14
+ all_faults + sprintf("%s: %s\n", msg_error, code)
15
+ end
16
+ rescue
17
+ string[/<TITLE>(.+)<\/TITLE>/, 1] || string
18
+ end
19
+ end
20
+
21
+ def on_complete(env) #this method is called after finish request
22
+ msg = parse_upload_error_from(env[:body].gsub(/\n/, ''))
23
+ if env[:status] == 403 || env[:status] == 401
24
+ raise ::AuthenticationError.new(msg, env[:status])
25
+ elsif env[:status] / 10 != 20
26
+ raise ::UploadError.new(msg, env[:status])
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,7 @@
1
+ class YouTubeIt
2
+ module Model
3
+ class Subscription < YouTubeIt::Record
4
+ attr_reader :id, :title, :published
5
+ end
6
+ end
7
+ end
@@ -114,6 +114,9 @@ class YouTubeIt
114
114
 
115
115
  # *Fixnum*:: Number of times that the video has been favorited
116
116
  attr_reader :favorite_count
117
+
118
+ # *String*:: State of the video (processing, restricted, deleted, rejected and failed)
119
+ attr_reader :state
117
120
 
118
121
 
119
122
  # Geodata
@@ -36,15 +36,15 @@ class YouTubeIt
36
36
  def parse_entry(entry)
37
37
  author = YouTubeIt::Model::Author.new(
38
38
  :name => entry.elements["author"].elements["name"].text,
39
- :uri => entry.elements["author"].elements["uri"].text
39
+ :uri => entry.elements["author"].elements["uri"].text
40
40
  )
41
41
  YouTubeIt::Model::Comment.new(
42
- :author => author,
43
- :content => entry.elements["content"].text,
42
+ :author => author,
43
+ :content => entry.elements["content"].text,
44
44
  :published => entry.elements["published"].text,
45
- :title => entry.elements["title"].text,
46
- :updated => entry.elements["updated "].text,
47
- :url => entry.elements["id"].text
45
+ :title => entry.elements["title"].text,
46
+ :updated => entry.elements["updated "].text,
47
+ :url => entry.elements["id"].text
48
48
  )
49
49
  end
50
50
  end
@@ -60,7 +60,7 @@ class YouTubeIt
60
60
  :description => (entry.elements["summary"] || entry.elements["media:group"].elements["media:description"]).text,
61
61
  :playlist_id => entry.elements["id"].text[/playlist([^<]+)/, 1].sub(':',''),
62
62
  :published => entry.elements["published"] ? entry.elements["published"].text : nil,
63
- :response_code => content.code,
63
+ :response_code => content.status,
64
64
  :xml => content.body)
65
65
  end
66
66
  end
@@ -98,26 +98,52 @@ class YouTubeIt
98
98
  xml = REXML::Document.new(content.body)
99
99
  entry = xml.elements["entry"] || xml.elements["feed"]
100
100
  YouTubeIt::Model::User.new(
101
- :age => entry.elements["yt:age"] ? entry.elements["yt:age"].text : nil,
102
- :company => entry.elements["yt:company"] ? entry.elements["yt:company"].text : nil,
101
+ :age => entry.elements["yt:age"] ? entry.elements["yt:age"].text : nil,
102
+ :username => entry.elements["yt:username"] ? entry.elements["yt:username"].text : nil,
103
+ :company => entry.elements["yt:company"] ? entry.elements["yt:company"].text : nil,
103
104
  :gender => entry.elements["yt:gender"] ? entry.elements["yt:gender"].text : nil,
104
- :hobbies => entry.elements["yt:hobbies"] ? entry.elements["yt:hobbies"].text : nil,
105
- :hometown => entry.elements["yt:hometown"] ? entry.elements["yt:hometown"].text : nil,
106
- :location => entry.elements["yt:location"] ? entry.elements["yt:location"].text : nil,
107
- :last_login => entry.elements["yt:statistics"].attributes["lastWebAccess"],
108
- :join_date => entry.elements["published"] ? entry.elements["published"].text : nil,
105
+ :hobbies => entry.elements["yt:hobbies"] ? entry.elements["yt:hobbies"].text : nil,
106
+ :hometown => entry.elements["yt:hometown"] ? entry.elements["yt:hometown"].text : nil,
107
+ :location => entry.elements["yt:location"] ? entry.elements["yt:location"].text : nil,
108
+ :last_login => entry.elements["yt:statistics"].attributes["lastWebAccess"],
109
+ :join_date => entry.elements["published"] ? entry.elements["published"].text : nil,
109
110
  :movies => entry.elements["yt:movies"] ? entry.elements["yt:movies"].text : nil,
110
- :music => entry.elements["yt:music"] ? entry.elements["yt:music"].text : nil,
111
- :occupation => entry.elements["yt:occupation"] ? entry.elements["yt:occupation"].text : nil,
112
- :relationship => entry.elements["yt:relationship"] ? entry.elements["yt:relationship"].text : nil,
111
+ :music => entry.elements["yt:music"] ? entry.elements["yt:music"].text : nil,
112
+ :occupation => entry.elements["yt:occupation"] ? entry.elements["yt:occupation"].text : nil,
113
+ :relationship => entry.elements["yt:relationship"] ? entry.elements["yt:relationship"].text : nil,
113
114
  :school => entry.elements["yt:school"] ? entry.elements["yt:school"].text : nil,
114
- :subscribers => entry.elements["yt:statistics"].attributes["subscriberCount"],
115
- :videos_watched => entry.elements["yt:statistics"].attributes["videoWatchCount"],
116
- :view_count => entry.elements["yt:statistics"].attributes["viewCount"],
117
- :upload_views => entry.elements["yt:statistics"].attributes["totalUploadViews"]
115
+ :subscribers => entry.elements["yt:statistics"].attributes["subscriberCount"],
116
+ :videos_watched => entry.elements["yt:statistics"].attributes["videoWatchCount"],
117
+ :view_count => entry.elements["yt:statistics"].attributes["viewCount"],
118
+ :upload_views => entry.elements["yt:statistics"].attributes["totalUploadViews"]
118
119
  )
119
120
  end
120
121
  end
122
+
123
+ class SubscriptionFeedParser < FeedParser #:nodoc:
124
+
125
+ def parse_content(content)
126
+ doc = REXML::Document.new(content.body)
127
+ feed = doc.elements["feed"]
128
+
129
+ subscriptions = []
130
+ feed.elements.each("entry") do |entry|
131
+ subscriptions << parse_entry(entry)
132
+ end
133
+ return subscriptions
134
+ end
135
+
136
+ protected
137
+
138
+ def parse_entry(entry)
139
+ YouTubeIt::Model::Subscription.new(
140
+ :title => entry.elements["title"].text,
141
+ :id => entry.elements["id"].text[/subscription([^<]+)/, 1].sub(':',''),
142
+ :published => entry.elements["published"] ? entry.elements["published"].text : nil
143
+ )
144
+ end
145
+ end
146
+
121
147
 
122
148
  class VideoFeedParser < FeedParser #:nodoc:
123
149
 
@@ -196,10 +222,10 @@ class YouTubeIt
196
222
  media_group.elements.each("media:thumbnail") do |thumb_element|
197
223
  # TODO: convert time HH:MM:ss string to seconds?
198
224
  thumbnails << YouTubeIt::Model::Thumbnail.new(
199
- :url => thumb_element.attributes["url"],
225
+ :url => thumb_element.attributes["url"],
200
226
  :height => thumb_element.attributes["height"].to_i,
201
- :width => thumb_element.attributes["width"].to_i,
202
- :time => thumb_element.attributes["time"])
227
+ :width => thumb_element.attributes["width"].to_i,
228
+ :time => thumb_element.attributes["time"])
203
229
  end
204
230
 
205
231
  rating_element = entry.elements["gd:rating"]
@@ -208,10 +234,10 @@ class YouTubeIt
208
234
  rating = nil
209
235
  if rating_element
210
236
  rating_values = {
211
- :min => rating_element.attributes["min"].to_i,
212
- :max => rating_element.attributes["max"].to_i,
237
+ :min => rating_element.attributes["min"].to_i,
238
+ :max => rating_element.attributes["max"].to_i,
213
239
  :rater_count => rating_element.attributes["numRaters"].to_i,
214
- :average => rating_element.attributes["average"].to_f
240
+ :average => rating_element.attributes["average"].to_f
215
241
  }
216
242
 
217
243
  if extended_rating_element
@@ -235,31 +261,44 @@ class YouTubeIt
235
261
  position = where.elements["gml:Point"].elements["gml:pos"].text
236
262
  latitude, longitude = position.split(" ")
237
263
  end
264
+
265
+ control = entry.elements["app:control"]
266
+ state = { :name => "published" }
267
+ if control && control.elements["yt:state"]
268
+ state = {
269
+ :name => control.elements["yt:state"].attributes["name"],
270
+ :reason_code => control.elements["yt:state"].attributes["reasonCode"],
271
+ :help_url => control.elements["yt:state"].attributes["helpUrl"],
272
+ :copy => control.elements["yt:state"].text
273
+ }
274
+
275
+ end
238
276
 
239
277
  YouTubeIt::Model::Video.new(
240
- :video_id => video_id,
241
- :published_at => published_at,
242
- :updated_at => updated_at,
243
- :categories => categories,
244
- :keywords => keywords,
245
- :title => title,
246
- :html_content => html_content,
247
- :author => author,
248
- :description => description,
249
- :duration => duration,
250
- :media_content => media_content,
251
- :player_url => player_url,
252
- :thumbnails => thumbnails,
253
- :rating => rating,
254
- :view_count => view_count,
278
+ :video_id => video_id,
279
+ :published_at => published_at,
280
+ :updated_at => updated_at,
281
+ :categories => categories,
282
+ :keywords => keywords,
283
+ :title => title,
284
+ :html_content => html_content,
285
+ :author => author,
286
+ :description => description,
287
+ :duration => duration,
288
+ :media_content => media_content,
289
+ :player_url => player_url,
290
+ :thumbnails => thumbnails,
291
+ :rating => rating,
292
+ :view_count => view_count,
255
293
  :favorite_count => favorite_count,
256
- :widescreen => widescreen,
257
- :noembed => noembed,
258
- :racy => racy,
259
- :where => where,
260
- :position => position,
261
- :latitude => latitude,
262
- :longitude => longitude)
294
+ :widescreen => widescreen,
295
+ :noembed => noembed,
296
+ :racy => racy,
297
+ :where => where,
298
+ :position => position,
299
+ :latitude => latitude,
300
+ :longitude => longitude,
301
+ :state => state)
263
302
  end
264
303
 
265
304
  def parse_media_content (media_content_element)
@@ -271,11 +310,11 @@ class YouTubeIt
271
310
  default = (media_content_element.attributes["isDefault"] == "true")
272
311
 
273
312
  YouTubeIt::Model::Content.new(
274
- :url => content_url,
275
- :format => format,
276
- :duration => duration,
313
+ :url => content_url,
314
+ :format => format,
315
+ :duration => duration,
277
316
  :mime_type => mime_type,
278
- :default => default)
317
+ :default => default)
279
318
  end
280
319
  end
281
320
 
@@ -298,12 +337,12 @@ class YouTubeIt
298
337
  end
299
338
  end
300
339
  YouTubeIt::Response::VideoSearch.new(
301
- :feed_id => feed_id || nil,
302
- :updated_at => updated_at || nil,
340
+ :feed_id => feed_id || nil,
341
+ :updated_at => updated_at || nil,
303
342
  :total_result_count => total_result_count || nil,
304
- :offset => offset || nil,
305
- :max_result_count => max_result_count || nil,
306
- :videos => videos)
343
+ :offset => offset || nil,
344
+ :max_result_count => max_result_count || nil,
345
+ :videos => videos)
307
346
  end
308
347
  end
309
348
  end