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.
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