youtube_it 2.0.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +28 -5
- data/VERSION +1 -1
- data/lib/youtube_it/client.rb +17 -1
- data/lib/youtube_it/middleware/faraday_authheader.rb +12 -1
- data/lib/youtube_it/model/activity.rb +17 -0
- data/lib/youtube_it/model/author.rb +2 -0
- data/lib/youtube_it/model/comment.rb +5 -0
- data/lib/youtube_it/model/contact.rb +3 -0
- data/lib/youtube_it/model/user.rb +1 -0
- data/lib/youtube_it/model/video.rb +16 -0
- data/lib/youtube_it/parser.rb +160 -3
- data/lib/youtube_it/request/video_upload.rb +69 -117
- data/lib/youtube_it.rb +1 -0
- data/test/test_client.rb +26 -15
- data/test/test_video_feed_parser.rb +9 -0
- data/youtube_it.gemspec +6 -5
- metadata +4 -5
data/README.rdoc
CHANGED
@@ -27,6 +27,9 @@ Client with developer key:
|
|
27
27
|
Client with youtube account and developer key:
|
28
28
|
$ client = YouTubeIt::Client.new(:username => "youtube_username", :password => "youtube_passwd", :dev_key => "developer_key")
|
29
29
|
|
30
|
+
Client with AuthSub:
|
31
|
+
$ client = YouTubeIt::AuthSubClient.new(:token => "token" , :dev_key => "developer_key")
|
32
|
+
|
30
33
|
Client with OAuth:
|
31
34
|
$ client = YouTubeIt::OAuthClient.new("consumer_key", "consumer_secret", "youtube_username", "developer_key")
|
32
35
|
$ client.authorize_from_access("access_token", "access_secret")
|
@@ -58,9 +61,11 @@ Advanced Queries (with boolean operators OR (either), AND (include), NOT (exclud
|
|
58
61
|
Fields Parameter(experimental features):
|
59
62
|
Return videos more than 1000 views
|
60
63
|
$ client.videos_by(:fields => {:view_count => "1000"})
|
64
|
+
|
61
65
|
Filter by date
|
62
66
|
$ client.videos_by(:fields => {:published => ((Date.today)})
|
63
67
|
$ client.videos_by(:fields => {:recorded => ((Date.today)})
|
68
|
+
|
64
69
|
Filter by date with range
|
65
70
|
$ client.videos_by(:fields => {:published => ((Date.today - 30)..(Date.today))})
|
66
71
|
$ client.videos_by(:fields => {:recorded => ((Date.today - 30)..(Date.today))})
|
@@ -88,7 +93,7 @@ My Video:
|
|
88
93
|
$ client.my_video(video_id)
|
89
94
|
|
90
95
|
Profile Details:
|
91
|
-
$ client.profile(
|
96
|
+
$ client.profile(user) #default: current user
|
92
97
|
|
93
98
|
List Comments:
|
94
99
|
$ client.comments(video_id)
|
@@ -97,7 +102,7 @@ Add A Comment:
|
|
97
102
|
$ client.add_comment(video_id, "test comment!")
|
98
103
|
|
99
104
|
List Favorites:
|
100
|
-
$ client.favorites(user) # current user
|
105
|
+
$ client.favorites(user) # default: current user
|
101
106
|
|
102
107
|
Add Favorite:
|
103
108
|
$ client.add_favorite(video_id)
|
@@ -112,7 +117,7 @@ Dislike A Video:
|
|
112
117
|
$ client.dislike_video(video_id)
|
113
118
|
|
114
119
|
List Subscriptions:
|
115
|
-
$ client.subscriptions(user) #default: current user
|
120
|
+
$ client.subscriptions(user) # default: current user
|
116
121
|
|
117
122
|
Subscribe To A Channel:
|
118
123
|
$ client.subscribe_channel(channel_name)
|
@@ -121,7 +126,7 @@ Unsubscribe To A Channel:
|
|
121
126
|
$ client.unsubscribe_channel(subscription_id)
|
122
127
|
|
123
128
|
List Playlists:
|
124
|
-
$ client.playlists(user) # current user
|
129
|
+
$ client.playlists(user) # default: current user
|
125
130
|
|
126
131
|
Select Playlist:
|
127
132
|
$ client.playlist(playlist_id)
|
@@ -190,6 +195,16 @@ If the videos has support for widescreen:
|
|
190
195
|
|
191
196
|
Note: you can specify width or just use the default of 1280.
|
192
197
|
|
198
|
+
== USING HTML5
|
199
|
+
|
200
|
+
Now you can embed videos without use flash using html5, usefull for mobiles that not support flash but has html5 browser
|
201
|
+
|
202
|
+
You can specify these options
|
203
|
+
$ video.embed_html5({:class => 'video-player', :id => 'my-video', :width => '425', :height => '350', :frameborder => '1'})
|
204
|
+
|
205
|
+
or just use with default options
|
206
|
+
$ video.embed_html5 #default: width: 425, height: 350, frameborder: 0
|
207
|
+
|
193
208
|
== LOGGING
|
194
209
|
|
195
210
|
YouTubeIt passes all logs through the logger variable on the class itself. In Rails context, assign the Rails logger to that variable to collect the messages
|
@@ -197,11 +212,19 @@ YouTubeIt passes all logs through the logger variable on the class itself. In Ra
|
|
197
212
|
$ YouTubeIt.logger = RAILS_DEFAULT_LOGGER
|
198
213
|
$ RAILS_DEFAULT_LOGGER.level = Logger::DEBUG
|
199
214
|
|
215
|
+
== Example Rails 3 App
|
216
|
+
|
217
|
+
You can get an example how you can use youtube_it with Rails 3 here: http://github.com/chebyte/youtube_it_rails_app_example
|
218
|
+
|
219
|
+
== DEMO
|
220
|
+
|
221
|
+
You can see to youtube_it in action here: http://youtube-it.heroku.com
|
222
|
+
|
200
223
|
== CONTRIBUTORS:
|
201
224
|
|
202
225
|
* Kyle J. Ginavan.
|
203
226
|
* Mauro Torres - http://github.com/chebyte
|
204
|
-
* Marko Seppa
|
227
|
+
* Marko Seppa - https://github.com/mseppae
|
205
228
|
|
206
229
|
== LICENSE:
|
207
230
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.0.
|
1
|
+
2.0.1
|
data/lib/youtube_it/client.rb
CHANGED
@@ -137,6 +137,11 @@ class YouTubeIt
|
|
137
137
|
def profile(user = nil)
|
138
138
|
client.profile(user)
|
139
139
|
end
|
140
|
+
|
141
|
+
# Fetches a user's activity feed.
|
142
|
+
def activity(user = nil, opts = {})
|
143
|
+
client.get_activity(user, opts)
|
144
|
+
end
|
140
145
|
|
141
146
|
def playlist(playlist_id)
|
142
147
|
client.playlist playlist_id
|
@@ -203,6 +208,11 @@ class YouTubeIt
|
|
203
208
|
def my_videos(opts = {})
|
204
209
|
client.get_my_videos(opts)
|
205
210
|
end
|
211
|
+
|
212
|
+
# Get's all of the user's contacts/friends.
|
213
|
+
def my_contacts(opts = {})
|
214
|
+
client.get_my_contacts(opts)
|
215
|
+
end
|
206
216
|
|
207
217
|
private
|
208
218
|
|
@@ -345,7 +355,13 @@ class YouTubeIt
|
|
345
355
|
end
|
346
356
|
|
347
357
|
def current_user
|
348
|
-
|
358
|
+
yt_session = Faraday.new(:url => "http://gdata.youtube.com") do |builder|
|
359
|
+
builder.use Faraday::Response::YouTubeIt
|
360
|
+
builder.use Faraday::Request::OAuth, config_token
|
361
|
+
builder.adapter Faraday.default_adapter
|
362
|
+
end
|
363
|
+
|
364
|
+
body = yt_session.get("/feeds/api/users/default").body
|
349
365
|
REXML::Document.new(body).elements["entry"].elements['author'].elements['name'].text
|
350
366
|
end
|
351
367
|
|
@@ -2,7 +2,18 @@ module Faraday
|
|
2
2
|
class Request::AuthHeader < Faraday::Middleware
|
3
3
|
|
4
4
|
def call(env)
|
5
|
-
env[:request_headers]
|
5
|
+
req_headers = env[:request_headers]
|
6
|
+
req_headers.merge!(@headers)
|
7
|
+
unless req_headers.include?("GData-Version")
|
8
|
+
req_headers.merge!("GData-Version" => "2")
|
9
|
+
end
|
10
|
+
unless req_headers.include?("Content-Type")
|
11
|
+
req_headers.merge!("Content-Type" => "application/atom+xml; charset=UTF-8")
|
12
|
+
end
|
13
|
+
unless req_headers.include?("Content-Length")
|
14
|
+
req_headers.merge!("Content-Length" => env[:body] ? "#{env[:body].length}" : "0")
|
15
|
+
end
|
16
|
+
|
6
17
|
@app.call(env)
|
7
18
|
end
|
8
19
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class YouTubeIt
|
2
|
+
module Model
|
3
|
+
class Activity < YouTubeIt::Record
|
4
|
+
# Attributes common to multiple activity types
|
5
|
+
attr_reader :type, :author, :videos, :video_id, :time
|
6
|
+
|
7
|
+
# video_rated
|
8
|
+
attr_reader :user_rating, :video_rating
|
9
|
+
|
10
|
+
# video_commented
|
11
|
+
attr_reader :comment_thread_url, :video_url
|
12
|
+
|
13
|
+
# friend_added and user_subscription_added
|
14
|
+
attr_reader :username
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -193,6 +193,22 @@ class YouTubeIt
|
|
193
193
|
EDOC
|
194
194
|
end
|
195
195
|
|
196
|
+
# Gives you the HTML 5 to embed the video on your website.
|
197
|
+
# Usefull for mobile that not support flash but has html5 browser
|
198
|
+
# === Returns
|
199
|
+
# String: The HTML for embedding the video on your website.
|
200
|
+
def embed_html5(params = {})
|
201
|
+
opts = {:class => params[:class] || "",
|
202
|
+
:id => params[:id] || "",
|
203
|
+
:width => params[:width] || "425",
|
204
|
+
:height => params[:height] || "350",
|
205
|
+
:frameborder => params[:frameborder] || "0"
|
206
|
+
}
|
207
|
+
<<EDOC
|
208
|
+
<iframe class="#{opts[:class]}" id="#{opts[:id]}" type="text/html" width="#{opts[:width]}" height="#{opts[:height]}" src="http://www.youtube.com/embed/#{unique_id}" frameborder="#{opts[:frameborder]}">
|
209
|
+
EDOC
|
210
|
+
end
|
211
|
+
|
196
212
|
# Gives you the HTML to embed the video on your website.
|
197
213
|
#
|
198
214
|
# === Returns
|
data/lib/youtube_it/parser.rb
CHANGED
@@ -2,7 +2,13 @@ class YouTubeIt
|
|
2
2
|
module Parser #:nodoc:
|
3
3
|
class FeedParser #:nodoc:
|
4
4
|
def initialize(content)
|
5
|
-
@content = open(content).read
|
5
|
+
@content = open(content).read
|
6
|
+
|
7
|
+
rescue OpenURI::HTTPError => e
|
8
|
+
raise OpenURI::HTTPError.new(e.io.status[0],e)
|
9
|
+
rescue
|
10
|
+
@content = content
|
11
|
+
|
6
12
|
end
|
7
13
|
|
8
14
|
def parse
|
@@ -92,6 +98,155 @@ class YouTubeIt
|
|
92
98
|
:xml => nil)
|
93
99
|
end
|
94
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
|
95
250
|
|
96
251
|
class ProfileFeedParser < FeedParser #:nodoc:
|
97
252
|
def parse_content(content)
|
@@ -112,6 +267,7 @@ class YouTubeIt
|
|
112
267
|
:occupation => entry.elements["yt:occupation"] ? entry.elements["yt:occupation"].text : nil,
|
113
268
|
:relationship => entry.elements["yt:relationship"] ? entry.elements["yt:relationship"].text : nil,
|
114
269
|
:school => entry.elements["yt:school"] ? entry.elements["yt:school"].text : nil,
|
270
|
+
:avatar => entry.elements["media:thumbnail"] ? entry.elements["media:thumbnail"].attributes["url"] : nil,
|
115
271
|
:subscribers => entry.elements["yt:statistics"].attributes["subscriberCount"],
|
116
272
|
:videos_watched => entry.elements["yt:statistics"].attributes["videoWatchCount"],
|
117
273
|
:view_count => entry.elements["yt:statistics"].attributes["viewCount"],
|
@@ -148,12 +304,13 @@ class YouTubeIt
|
|
148
304
|
class VideoFeedParser < FeedParser #:nodoc:
|
149
305
|
|
150
306
|
def parse_content(content)
|
151
|
-
doc = REXML::Document.new(content)
|
307
|
+
doc = (content.is_a?(REXML::Element)) ? content : REXML::Document.new(content)
|
308
|
+
|
152
309
|
entry = doc.elements["entry"]
|
153
310
|
parse_entry(entry)
|
154
311
|
end
|
155
312
|
|
156
|
-
|
313
|
+
protected
|
157
314
|
def parse_entry(entry)
|
158
315
|
video_id = entry.elements["id"].text
|
159
316
|
published_at = entry.elements["published"] ? Time.parse(entry.elements["published"].text) : nil
|
@@ -88,27 +88,29 @@ class YouTubeIt
|
|
88
88
|
# :private
|
89
89
|
# When the authentication credentials are incorrect, an AuthenticationError will be raised.
|
90
90
|
def update(video_id, options)
|
91
|
-
@opts
|
92
|
-
update_body
|
93
|
-
|
94
|
-
|
95
|
-
"Content-Length" => "#{update_body.length}",
|
96
|
-
}
|
97
|
-
update_url = "/feeds/api/users/default/uploads/%s" % video_id
|
98
|
-
response = yt_session.put(update_url, update_body, update_header)
|
91
|
+
@opts = options
|
92
|
+
update_body = video_xml
|
93
|
+
update_url = "/feeds/api/users/default/uploads/%s" % video_id
|
94
|
+
response = yt_session.put(update_url, update_body)
|
99
95
|
|
100
96
|
return YouTubeIt::Parser::VideoFeedParser.new(response.body).parse
|
101
97
|
end
|
98
|
+
|
99
|
+
# Fetches the currently authenticated user's contacts (i.e. friends).
|
100
|
+
# When the authentication credentials are incorrect, an AuthenticationError will be raised.
|
101
|
+
def get_my_contacts(opts)
|
102
|
+
contacts_url = "/feeds/api/users/default/contacts?v=2"
|
103
|
+
contacts_url << opts.collect { |k,p| [k,p].join '=' }.join('&')
|
104
|
+
response = yt_session.get(contacts_url)
|
105
|
+
|
106
|
+
return YouTubeIt::Parser::ContactsParser.new(response).parse
|
107
|
+
end
|
102
108
|
|
103
109
|
# Fetches the data of a video, which may be private. The video must be owned by this user.
|
104
110
|
# When the authentication credentials are incorrect, an AuthenticationError will be raised.
|
105
111
|
def get_my_video(video_id)
|
106
|
-
get_header = {
|
107
|
-
"Content-Type" => "application/atom+xml",
|
108
|
-
"Content-Length" => "0",
|
109
|
-
}
|
110
112
|
get_url = "/feeds/api/users/default/uploads/%s" % video_id
|
111
|
-
response = yt_session.get(get_url
|
113
|
+
response = yt_session.get(get_url)
|
112
114
|
|
113
115
|
return YouTubeIt::Parser::VideoFeedParser.new(response.body).parse
|
114
116
|
end
|
@@ -118,51 +120,34 @@ class YouTubeIt
|
|
118
120
|
def get_my_videos(opts)
|
119
121
|
max_results = opts[:per_page] || 50
|
120
122
|
start_index = ((opts[:page] || 1) -1) * max_results +1
|
121
|
-
|
122
|
-
|
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)
|
123
|
+
get_url = "/feeds/api/users/default/uploads?max-results=#{max_results}&start-index=#{start_index}"
|
124
|
+
response = yt_session.get(get_url)
|
127
125
|
|
128
126
|
return YouTubeIt::Parser::VideosFeedParser.new(response.body).parse
|
129
127
|
end
|
130
128
|
|
131
129
|
# Delete a video on YouTube
|
132
130
|
def delete(video_id)
|
133
|
-
delete_header = {
|
134
|
-
"Content-Type" => "application/atom+xml; charset=UTF-8",
|
135
|
-
"Content-Length" => "0",
|
136
|
-
}
|
137
131
|
delete_url = "/feeds/api/users/default/uploads/%s" % video_id
|
138
|
-
response
|
132
|
+
response = yt_session.delete(delete_url)
|
139
133
|
|
140
134
|
return true
|
141
135
|
end
|
142
136
|
|
143
137
|
def get_upload_token(options, nexturl)
|
144
|
-
@opts
|
145
|
-
token_body
|
146
|
-
|
147
|
-
|
148
|
-
"Content-Length" => "#{token_body.length}",
|
149
|
-
}
|
150
|
-
token_url = "/action/GetUploadToken"
|
151
|
-
response = yt_session.post(token_url, token_body, token_header)
|
138
|
+
@opts = options
|
139
|
+
token_body = video_xml
|
140
|
+
token_url = "/action/GetUploadToken"
|
141
|
+
response = yt_session.post(token_url, token_body)
|
152
142
|
|
153
143
|
return {:url => "#{response.body[/<url>(.+)<\/url>/, 1]}?nexturl=#{nexturl}",
|
154
144
|
:token => response.body[/<token>(.+)<\/token>/, 1]}
|
155
145
|
end
|
156
146
|
|
157
147
|
def add_comment(video_id, comment)
|
158
|
-
comment_body
|
159
|
-
|
160
|
-
|
161
|
-
"Content-Length" => "#{comment_body.length}",
|
162
|
-
}
|
163
|
-
comment_url = "/feeds/api/videos/%s/comments" % video_id
|
164
|
-
|
165
|
-
response = yt_session.post(comment_url, comment_body, comment_header)
|
148
|
+
comment_body = video_xml_for(:comment => comment)
|
149
|
+
comment_url = "/feeds/api/videos/%s/comments" % video_id
|
150
|
+
response = yt_session.post(comment_url, comment_body)
|
166
151
|
|
167
152
|
return {:code => response.status, :body => response.body}
|
168
153
|
end
|
@@ -170,43 +155,44 @@ class YouTubeIt
|
|
170
155
|
def comments(video_id, opts = {})
|
171
156
|
comment_url = "/feeds/api/videos/%s/comments?" % video_id
|
172
157
|
comment_url << opts.collect { |k,p| [k,p].join '=' }.join('&')
|
173
|
-
response
|
158
|
+
response = yt_session.get(comment_url)
|
174
159
|
|
175
160
|
return YouTubeIt::Parser::CommentsFeedParser.new(response).parse
|
176
161
|
end
|
177
162
|
|
178
163
|
def add_favorite(video_id)
|
179
|
-
favorite_body
|
180
|
-
|
181
|
-
|
182
|
-
"Content-Length" => "#{favorite_body.length}",
|
183
|
-
}
|
184
|
-
favorite_url = "/feeds/api/users/default/favorites"
|
185
|
-
response = yt_session.post(favorite_url, favorite_body, favorite_header)
|
164
|
+
favorite_body = video_xml_for(:favorite => video_id)
|
165
|
+
favorite_url = "/feeds/api/users/default/favorites"
|
166
|
+
response = yt_session.post(favorite_url, favorite_body)
|
186
167
|
|
187
168
|
return {:code => response.status, :body => response.body}
|
188
169
|
end
|
189
170
|
|
190
171
|
def delete_favorite(video_id)
|
191
172
|
favorite_header = {
|
192
|
-
"
|
193
|
-
"Content-Length" => "0",
|
173
|
+
"GData-Version" => "1",
|
194
174
|
}
|
195
|
-
favorite_url
|
196
|
-
response
|
175
|
+
favorite_url = "/feeds/api/users/default/favorites/%s" % video_id
|
176
|
+
response = yt_session.delete(favorite_url, favorite_header)
|
197
177
|
|
198
178
|
return true
|
199
179
|
end
|
200
180
|
|
201
181
|
def profile(user)
|
202
|
-
profile_url
|
203
|
-
|
204
|
-
"Content-Type" => "application/atom+xml; charset=UTF-8"
|
205
|
-
}
|
206
|
-
response = yt_session.get(profile_url, profile_header)
|
182
|
+
profile_url = "/feeds/api/users/%s?v=2" % (user ? user : "default")
|
183
|
+
response = yt_session.get(profile_url)
|
207
184
|
|
208
185
|
return YouTubeIt::Parser::ProfileFeedParser.new(response).parse
|
209
186
|
end
|
187
|
+
|
188
|
+
# Return's a user's activity feed.
|
189
|
+
def get_activity(user, opts)
|
190
|
+
activity_url = "/feeds/api/events?author=%s&v=2&" % (user ? user : "default")
|
191
|
+
activity_url << opts.collect { |k,p| [k,p].join '=' }.join('&')
|
192
|
+
response = yt_session.get(activity_url)
|
193
|
+
|
194
|
+
return YouTubeIt::Parser::ActivityParser.new(response).parse
|
195
|
+
end
|
210
196
|
|
211
197
|
def playlist(playlist_id)
|
212
198
|
playlist_url = "/feeds/api/playlists/%s?v=2" % playlist_id
|
@@ -223,101 +209,69 @@ class YouTubeIt
|
|
223
209
|
end
|
224
210
|
|
225
211
|
def add_playlist(options)
|
226
|
-
playlist_body
|
227
|
-
|
228
|
-
|
229
|
-
"Content-Length" => "#{playlist_body.length}",
|
230
|
-
}
|
231
|
-
playlist_url = "/feeds/api/users/default/playlists"
|
232
|
-
response = yt_session.post(playlist_url, playlist_body, playlist_header)
|
212
|
+
playlist_body = video_xml_for_playlist(options)
|
213
|
+
playlist_url = "/feeds/api/users/default/playlists"
|
214
|
+
response = yt_session.post(playlist_url, playlist_body)
|
233
215
|
|
234
216
|
return YouTubeIt::Parser::PlaylistFeedParser.new(response).parse
|
235
217
|
end
|
236
218
|
|
237
219
|
def add_video_to_playlist(playlist_id, video_id)
|
238
|
-
playlist_body
|
239
|
-
|
240
|
-
|
241
|
-
"Content-Length" => "#{playlist_body.length}",
|
242
|
-
}
|
243
|
-
playlist_url = "/feeds/api/playlists/%s" % playlist_id
|
244
|
-
response = yt_session.post(playlist_url, playlist_body, playlist_header)
|
220
|
+
playlist_body = video_xml_for(:playlist => video_id)
|
221
|
+
playlist_url = "/feeds/api/playlists/%s" % playlist_id
|
222
|
+
response = yt_session.post(playlist_url, playlist_body)
|
245
223
|
|
246
224
|
return {:code => response.status, :body => response.body, :playlist_entry_id => playlist_entry_id_from_playlist(response.body)}
|
247
225
|
end
|
248
226
|
|
249
227
|
def update_playlist(playlist_id, options)
|
250
|
-
playlist_body
|
251
|
-
|
252
|
-
|
253
|
-
"Content-Length" => "#{playlist_body.length}",
|
254
|
-
}
|
255
|
-
playlist_url = "/feeds/api/users/default/playlists/%s" % playlist_id
|
256
|
-
response = yt_session.put(playlist_url, playlist_body, playlist_header)
|
228
|
+
playlist_body = video_xml_for_playlist(options)
|
229
|
+
playlist_url = "/feeds/api/users/default/playlists/%s" % playlist_id
|
230
|
+
response = yt_session.put(playlist_url, playlist_body)
|
257
231
|
|
258
232
|
return YouTubeIt::Parser::PlaylistFeedParser.new(response).parse
|
259
233
|
end
|
260
234
|
|
261
235
|
def delete_video_from_playlist(playlist_id, playlist_entry_id)
|
262
|
-
playlist_header = {
|
263
|
-
"Content-Type" => "application/atom+xml",
|
264
|
-
}
|
265
236
|
playlist_url = "/feeds/api/playlists/%s/%s" % [playlist_id, playlist_entry_id]
|
266
|
-
response
|
237
|
+
response = yt_session.delete(playlist_url)
|
267
238
|
|
268
239
|
return true
|
269
240
|
end
|
270
241
|
|
271
242
|
def delete_playlist(playlist_id)
|
272
|
-
|
273
|
-
|
274
|
-
}
|
275
|
-
playlist_url = "/feeds/api/users/default/playlists/%s" % playlist_id
|
276
|
-
response = yt_session.delete(playlist_url, playlist_header)
|
243
|
+
playlist_url = "/feeds/api/users/default/playlists/%s" % playlist_id
|
244
|
+
response = yt_session.delete(playlist_url)
|
277
245
|
|
278
246
|
return true
|
279
247
|
end
|
280
248
|
|
281
249
|
def rate_video(video_id, rating)
|
282
|
-
rating_body
|
283
|
-
|
284
|
-
|
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)
|
250
|
+
rating_body = video_xml_for(:rating => rating)
|
251
|
+
rating_url = "/feeds/api/videos/#{video_id}/ratings"
|
252
|
+
response = yt_session.post(rating_url, rating_body)
|
289
253
|
|
290
254
|
return {:code => response.status, :body => response.body}
|
291
255
|
end
|
292
256
|
|
293
257
|
def subscriptions(user)
|
294
|
-
subscription_url
|
295
|
-
|
296
|
-
"Content-Type" => "application/atom+xml",
|
297
|
-
}
|
298
|
-
response = yt_session.get(subscription_url, subscription_header)
|
258
|
+
subscription_url = "/feeds/api/users/%s/subscriptions?v=2" % (user ? user : "default")
|
259
|
+
response = yt_session.get(subscription_url)
|
299
260
|
|
300
261
|
return YouTubeIt::Parser::SubscriptionFeedParser.new(response).parse
|
301
262
|
end
|
302
263
|
|
303
264
|
def subscribe_channel(channel_name)
|
304
|
-
subscribe_body
|
305
|
-
|
306
|
-
|
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)
|
265
|
+
subscribe_body = video_xml_for(:subscribe => channel_name)
|
266
|
+
subscribe_url = "/feeds/api/users/default/subscriptions"
|
267
|
+
response = yt_session.post(subscribe_url, subscribe_body)
|
311
268
|
|
312
269
|
return {:code => response.status, :body => response.body}
|
313
270
|
end
|
314
271
|
|
315
272
|
def unsubscribe_channel(subscription_id)
|
316
|
-
unsubscribe_header = {
|
317
|
-
"Content-Type" => "application/atom+xml"
|
318
|
-
}
|
319
273
|
unsubscribe_url = "/feeds/api/users/default/subscriptions/%s" % subscription_id
|
320
|
-
response
|
274
|
+
response = yt_session.delete(unsubscribe_url)
|
321
275
|
|
322
276
|
return {:code => response.status, :body => response.body}
|
323
277
|
end
|
@@ -325,12 +279,13 @@ class YouTubeIt
|
|
325
279
|
def favorites(user, opts = {})
|
326
280
|
favorite_url = "/feeds/api/users/%s/favorites#{opts.empty? ? '' : '?#{opts.to_param}'}" % (user ? user : "default")
|
327
281
|
response = yt_session.get(favorite_url)
|
282
|
+
|
328
283
|
return YouTubeIt::Parser::VideosFeedParser.new(response.body).parse
|
329
284
|
end
|
330
285
|
|
331
286
|
def get_current_user
|
332
287
|
current_user_url = "/feeds/api/users/default"
|
333
|
-
response = yt_session.get(current_user_url
|
288
|
+
response = yt_session.get(current_user_url)
|
334
289
|
|
335
290
|
return REXML::Document.new(response.body).elements["entry"].elements['author'].elements['name'].text
|
336
291
|
end
|
@@ -350,14 +305,11 @@ class YouTubeIt
|
|
350
305
|
end
|
351
306
|
|
352
307
|
def authorization_headers
|
353
|
-
header = {
|
354
|
-
|
355
|
-
"X-GData-Key" => "key=#{@dev_key}",
|
356
|
-
"GData-Version" => "2",
|
357
|
-
}
|
308
|
+
header = {"X-GData-Client" => "#{@client_id}"}
|
309
|
+
header.merge!("X-GData-Key" => "key=#{@dev_key}") if @dev_key
|
358
310
|
if @authsub_token
|
359
311
|
header.merge!("Authorization" => "AuthSub token=#{@authsub_token}")
|
360
|
-
elsif @access_token.nil? && @authsub_token.nil?
|
312
|
+
elsif @access_token.nil? && @authsub_token.nil? && @user
|
361
313
|
header.merge!("Authorization" => "GoogleLogin auth=#{auth_token}")
|
362
314
|
end
|
363
315
|
header
|
data/lib/youtube_it.rb
CHANGED
data/test/test_client.rb
CHANGED
@@ -234,16 +234,18 @@ class TestClient < Test::Unit::TestCase
|
|
234
234
|
@client.video_delete(video.unique_id)
|
235
235
|
end
|
236
236
|
|
237
|
+
|
237
238
|
def test_should_add_new_comment
|
238
|
-
|
239
|
-
@client.add_comment(
|
240
|
-
comment = @client.comments(
|
239
|
+
video = @client.video_upload(File.open("test/test.mov"), OPTIONS)
|
240
|
+
@client.add_comment(video.unique_id, "test comment")
|
241
|
+
comment = @client.comments(video.unique_id).first.content
|
241
242
|
assert comment.match(/test comment/)
|
243
|
+
@client.video_delete(video.unique_id)
|
242
244
|
end
|
243
|
-
|
245
|
+
|
244
246
|
def test_should_add_and_delete_video_from_playlist
|
245
247
|
playlist = @client.add_playlist(:title => "youtube_it test!", :description => "test playlist")
|
246
|
-
video = @client.add_video_to_playlist(playlist.playlist_id,"
|
248
|
+
video = @client.add_video_to_playlist(playlist.playlist_id,"CE62FSEoY28")
|
247
249
|
assert_equal video[:code].to_i, 201
|
248
250
|
assert @client.delete_video_from_playlist(playlist.playlist_id, video[:playlist_entry_id])
|
249
251
|
assert @client.delete_playlist(playlist.playlist_id)
|
@@ -270,15 +272,15 @@ class TestClient < Test::Unit::TestCase
|
|
270
272
|
|
271
273
|
def test_should_determine_if_widescreen_video_is_widescreen
|
272
274
|
widescreen_id = 'QqQVll-MP3I'
|
273
|
-
|
275
|
+
|
274
276
|
video = @client.video_by(widescreen_id)
|
275
277
|
assert video.widescreen?
|
276
278
|
end
|
277
|
-
|
279
|
+
|
278
280
|
def test_get_current_user
|
279
281
|
assert_equal @client.current_user, 'tubeit20101'
|
280
282
|
end
|
281
|
-
|
283
|
+
|
282
284
|
def test_should_get_my_videos
|
283
285
|
video = @client.video_upload(File.open("test/test.mov"), OPTIONS)
|
284
286
|
assert_valid_video video
|
@@ -286,7 +288,7 @@ class TestClient < Test::Unit::TestCase
|
|
286
288
|
assert_equal result.videos.first.unique_id, video.unique_id
|
287
289
|
@client.video_delete(video.unique_id)
|
288
290
|
end
|
289
|
-
|
291
|
+
|
290
292
|
def test_should_get_my_video
|
291
293
|
video = @client.video_upload(File.open("test/test.mov"), OPTIONS)
|
292
294
|
assert_valid_video video
|
@@ -294,33 +296,33 @@ class TestClient < Test::Unit::TestCase
|
|
294
296
|
assert_equal result.unique_id, video.unique_id
|
295
297
|
@client.video_delete(video.unique_id)
|
296
298
|
end
|
297
|
-
|
299
|
+
|
298
300
|
def test_should_add_like_to_video
|
299
301
|
r = @client.like_video("CE62FSEoY28")
|
300
302
|
assert_equal r[:code], 201
|
301
303
|
@client.dislike_video("CE62FSEoY28")
|
302
304
|
end
|
303
|
-
|
305
|
+
|
304
306
|
def test_should_dislike_to_video
|
305
307
|
@client.like_video("CE62FSEoY28")
|
306
308
|
r = @client.dislike_video("CE62FSEoY28")
|
307
309
|
assert_equal r[:code], 201
|
308
310
|
end
|
309
|
-
|
310
|
-
|
311
|
+
|
312
|
+
|
311
313
|
def test_should_subscribe_to_channel
|
312
314
|
r = @client.subscribe_channel("TheWoWArthas")
|
313
315
|
assert_equal r[:code], 201
|
314
316
|
assert_equal @client.subscriptions.first.title, "Videos published by : TheWoWArthas"
|
315
317
|
@client.unsubscribe_channel(@client.subscriptions.first.id)
|
316
318
|
end
|
317
|
-
|
319
|
+
|
318
320
|
def test_should_unsubscribe_to_channel
|
319
321
|
@client.subscribe_channel("TheWoWArthas")
|
320
322
|
r = @client.unsubscribe_channel(@client.subscriptions.first.id)
|
321
323
|
assert_equal r[:code], 200
|
322
324
|
end
|
323
|
-
|
325
|
+
|
324
326
|
def test_should_list_subscriptions
|
325
327
|
@client.subscribe_channel("TheWoWArthas")
|
326
328
|
assert @client.subscriptions.count == 1
|
@@ -332,6 +334,15 @@ class TestClient < Test::Unit::TestCase
|
|
332
334
|
profile = @client.profile
|
333
335
|
assert_equal profile.username, "tubeit20101"
|
334
336
|
end
|
337
|
+
|
338
|
+
def test_should_add_and_delete_video_to_favorite
|
339
|
+
video_id ="j5raG94IGCc"
|
340
|
+
result = @client.add_favorite(video_id)
|
341
|
+
assert_equal result[:code], 201
|
342
|
+
sleep 4
|
343
|
+
assert @client.delete_favorite(video_id)
|
344
|
+
end
|
345
|
+
|
335
346
|
private
|
336
347
|
|
337
348
|
def assert_valid_video (video)
|
@@ -2,6 +2,14 @@ require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
2
2
|
|
3
3
|
class TestVideoFeedParser < Test::Unit::TestCase
|
4
4
|
|
5
|
+
def test_should_raise_bad_request_exception_when_id_not_found
|
6
|
+
bad_url = "http://gdata.youtube.com/feeds/api/videos/abc?v=2"
|
7
|
+
|
8
|
+
assert_raise(OpenURI::HTTPError) do
|
9
|
+
parser = YouTubeIt::Parser::VideoFeedParser.new bad_url
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
5
13
|
# VIDEO ATTRIBUTES AFFECTED BY PARSING
|
6
14
|
|
7
15
|
def test_should_display_unique_id_correctly_after_parsing
|
@@ -259,4 +267,5 @@ class TestVideoFeedParser < Test::Unit::TestCase
|
|
259
267
|
yield parser
|
260
268
|
end
|
261
269
|
end
|
270
|
+
|
262
271
|
end
|
data/youtube_it.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{youtube_it}
|
8
|
-
s.version = "2.0.
|
8
|
+
s.version = "2.0.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = [
|
12
|
-
s.date = %q{2011-
|
11
|
+
s.authors = [%q{kylejginavan}, %q{chebyte}, %q{mseppae}]
|
12
|
+
s.date = %q{2011-09-02}
|
13
13
|
s.description = %q{Upload, delete, update, comment on youtube videos all from one gem.}
|
14
14
|
s.email = %q{kylejginavan@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
|
|
26
26
|
"lib/youtube_it/middleware/faraday_authheader.rb",
|
27
27
|
"lib/youtube_it/middleware/faraday_oauth.rb",
|
28
28
|
"lib/youtube_it/middleware/faraday_youtubeit.rb",
|
29
|
+
"lib/youtube_it/model/activity.rb",
|
29
30
|
"lib/youtube_it/model/author.rb",
|
30
31
|
"lib/youtube_it/model/category.rb",
|
31
32
|
"lib/youtube_it/model/comment.rb",
|
@@ -60,8 +61,8 @@ Gem::Specification.new do |s|
|
|
60
61
|
"youtube_it.gemspec"
|
61
62
|
]
|
62
63
|
s.homepage = %q{http://github.com/kylejginavan/youtube_it}
|
63
|
-
s.require_paths = [
|
64
|
-
s.rubygems_version = %q{1.
|
64
|
+
s.require_paths = [%q{lib}]
|
65
|
+
s.rubygems_version = %q{1.8.8}
|
65
66
|
s.summary = %q{The most complete Ruby wrapper for youtube api's}
|
66
67
|
s.test_files = [
|
67
68
|
"test/helper.rb",
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: youtube_it
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 2.0.
|
5
|
+
version: 2.0.1
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- kylejginavan
|
@@ -12,8 +12,7 @@ autorequire:
|
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
14
|
|
15
|
-
date: 2011-
|
16
|
-
default_executable:
|
15
|
+
date: 2011-09-02 00:00:00 Z
|
17
16
|
dependencies:
|
18
17
|
- !ruby/object:Gem::Dependency
|
19
18
|
name: oauth
|
@@ -78,6 +77,7 @@ files:
|
|
78
77
|
- lib/youtube_it/middleware/faraday_authheader.rb
|
79
78
|
- lib/youtube_it/middleware/faraday_oauth.rb
|
80
79
|
- lib/youtube_it/middleware/faraday_youtubeit.rb
|
80
|
+
- lib/youtube_it/model/activity.rb
|
81
81
|
- lib/youtube_it/model/author.rb
|
82
82
|
- lib/youtube_it/model/category.rb
|
83
83
|
- lib/youtube_it/model/comment.rb
|
@@ -110,7 +110,6 @@ files:
|
|
110
110
|
- test/test_video_feed_parser.rb
|
111
111
|
- test/test_video_search.rb
|
112
112
|
- youtube_it.gemspec
|
113
|
-
has_rdoc: true
|
114
113
|
homepage: http://github.com/kylejginavan/youtube_it
|
115
114
|
licenses: []
|
116
115
|
|
@@ -134,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
133
|
requirements: []
|
135
134
|
|
136
135
|
rubyforge_project:
|
137
|
-
rubygems_version: 1.
|
136
|
+
rubygems_version: 1.8.8
|
138
137
|
signing_key:
|
139
138
|
specification_version: 3
|
140
139
|
summary: The most complete Ruby wrapper for youtube api's
|