youtube_it 2.0.0 → 2.0.1
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/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
|