vibedeck-youtube_it 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/README.rdoc +234 -0
  2. data/Rakefile +35 -0
  3. data/lib/youtube_it/chain_io.rb +76 -0
  4. data/lib/youtube_it/client.rb +367 -0
  5. data/lib/youtube_it/middleware/faraday_authheader.rb +24 -0
  6. data/lib/youtube_it/middleware/faraday_oauth.rb +21 -0
  7. data/lib/youtube_it/middleware/faraday_youtubeit.rb +30 -0
  8. data/lib/youtube_it/model/author.rb +13 -0
  9. data/lib/youtube_it/model/category.rb +11 -0
  10. data/lib/youtube_it/model/comment.rb +16 -0
  11. data/lib/youtube_it/model/contact.rb +16 -0
  12. data/lib/youtube_it/model/content.rb +18 -0
  13. data/lib/youtube_it/model/playlist.rb +11 -0
  14. data/lib/youtube_it/model/rating.rb +23 -0
  15. data/lib/youtube_it/model/subscription.rb +7 -0
  16. data/lib/youtube_it/model/thumbnail.rb +17 -0
  17. data/lib/youtube_it/model/user.rb +26 -0
  18. data/lib/youtube_it/model/video.rb +225 -0
  19. data/lib/youtube_it/parser.rb +357 -0
  20. data/lib/youtube_it/record.rb +12 -0
  21. data/lib/youtube_it/request/base_search.rb +72 -0
  22. data/lib/youtube_it/request/error.rb +15 -0
  23. data/lib/youtube_it/request/standard_search.rb +43 -0
  24. data/lib/youtube_it/request/user_search.rb +47 -0
  25. data/lib/youtube_it/request/video_search.rb +102 -0
  26. data/lib/youtube_it/request/video_upload.rb +415 -0
  27. data/lib/youtube_it/response/video_search.rb +41 -0
  28. data/lib/youtube_it/version.rb +4 -0
  29. data/lib/youtube_it.rb +75 -0
  30. data/test/helper.rb +10 -0
  31. data/test/test_chain_io.rb +63 -0
  32. data/test/test_client.rb +418 -0
  33. data/test/test_field_search.rb +48 -0
  34. data/test/test_video.rb +43 -0
  35. data/test/test_video_feed_parser.rb +271 -0
  36. data/test/test_video_search.rb +141 -0
  37. metadata +150 -0
@@ -0,0 +1,43 @@
1
+ class YouTubeIt
2
+ module Request #:nodoc:
3
+ class StandardSearch < BaseSearch #:nodoc:
4
+ attr_reader :max_results # max_results
5
+ attr_reader :order_by # orderby, ([relevance], viewCount, published, rating)
6
+ attr_reader :offset # start-index
7
+ attr_reader :time # time
8
+
9
+ TYPES = [ :top_rated, :top_favorites, :most_viewed, :most_popular,
10
+ :most_recent, :most_discussed, :most_linked, :most_responded,
11
+ :recently_featured, :watch_on_mobile ]
12
+
13
+ def initialize(type, options={})
14
+ @dev_key = options[:dev_key] if options[:dev_key]
15
+ if TYPES.include?(type)
16
+ @max_results, @order_by, @offset, @time = nil
17
+ set_instance_variables(options)
18
+ @url = base_url + type.to_s << build_query_params(to_youtube_params)
19
+ else
20
+ raise "Invalid type, must be one of: #{ TYPES.map { |t| t.to_s }.join(", ") }"
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def base_url
27
+ super << "standardfeeds/"
28
+ end
29
+
30
+ def to_youtube_params
31
+ {
32
+ 'max-results' => @max_results,
33
+ 'orderby' => @order_by,
34
+ 'start-index' => @offset,
35
+ 'time' => @time,
36
+ 'v' => 2
37
+ }
38
+ end
39
+ end
40
+
41
+ end
42
+ end
43
+
@@ -0,0 +1,47 @@
1
+ class YouTubeIt
2
+ module Request #:nodoc:
3
+ class UserSearch < BaseSearch #:nodoc:
4
+ include FieldSearch
5
+ attr_reader :max_results # max_results
6
+ attr_reader :order_by # orderby, ([relevance], viewCount, published, rating)
7
+ attr_reader :offset # start-index
8
+
9
+ def initialize(params, options={})
10
+ @max_results, @order_by, @offset = nil
11
+ @url = base_url
12
+ @dev_key = options[:dev_key] if options[:dev_key]
13
+ if params == :favorites
14
+ @url << "#{options[:user]}/favorites"
15
+ set_instance_variables(options)
16
+ elsif params[:user] && options[:favorites]
17
+ @url << "#{params[:user]}/favorites"
18
+ set_instance_variables(params)
19
+ return
20
+ elsif params[:user]
21
+ @url << "#{params[:user]}/uploads"
22
+ set_instance_variables(params)
23
+ end
24
+
25
+ @url << build_query_params(to_youtube_params)
26
+ @url << fields_to_params(params.delete(:fields)) if params != :favorites && params[:fields]
27
+ end
28
+
29
+ private
30
+
31
+ def base_url
32
+ super << "users/"
33
+ end
34
+
35
+ def to_youtube_params
36
+ {
37
+ 'max-results' => @max_results,
38
+ 'orderby' => @order_by,
39
+ 'start-index' => @offset,
40
+ 'v' => 2
41
+ }
42
+ end
43
+ end
44
+
45
+ end
46
+ end
47
+
@@ -0,0 +1,102 @@
1
+ class YouTubeIt
2
+ module Request #:nodoc:
3
+ class VideoSearch < BaseSearch #:nodoc:
4
+ include FieldSearch
5
+
6
+ # From here: http://code.google.com/apis/youtube/reference.html#yt_format
7
+ ONLY_EMBEDDABLE = 5
8
+
9
+ attr_reader :max_results # max_results
10
+ attr_reader :order_by # orderby, ([relevance], viewCount, published, rating)
11
+ attr_reader :offset # start-index
12
+ attr_reader :query # vq
13
+ attr_reader :response_format # alt, ([atom], rss, json)
14
+ attr_reader :tags # /-/tag1/tag2
15
+ attr_reader :categories # /-/Category1/Category2
16
+ attr_reader :video_format # format (1=mobile devices)
17
+ attr_reader :racy # racy ([exclude], include)
18
+ attr_reader :author
19
+ attr_reader :lang # lt
20
+
21
+ def initialize(params={})
22
+ # Initialize our various member data to avoid warnings and so we'll
23
+ # automatically fall back to the youtube api defaults
24
+ @max_results, @order_by,
25
+ @offset, @query,
26
+ @response_format, @video_format,
27
+ @racy, @author, @lang = nil
28
+ @url = base_url
29
+ @dev_key = params[:dev_key] if params[:dev_key]
30
+
31
+ # Return a single video (base_url + /T7YazwP8GtY)
32
+ return @url << "/" << params[:video_id] << "?v=2" if params[:video_id]
33
+
34
+ @url << "/-/" if (params[:categories] || params[:tags])
35
+ @url << categories_to_params(params.delete(:categories)) if params[:categories]
36
+ @url << tags_to_params(params.delete(:tags)) if params[:tags]
37
+
38
+ set_instance_variables(params)
39
+
40
+ if( params[ :only_embeddable ] )
41
+ @video_format = ONLY_EMBEDDABLE
42
+ end
43
+
44
+ @url << build_query_params(to_youtube_params)
45
+ @url << fields_to_params(params.delete(:fields)) if params[:fields]
46
+ end
47
+
48
+ private
49
+
50
+ def base_url
51
+ super << "videos"
52
+ end
53
+
54
+ def to_youtube_params
55
+ {
56
+ 'max-results' => @max_results,
57
+ 'orderby' => @order_by,
58
+ 'start-index' => @offset,
59
+ 'v' => 2,
60
+ 'q' => @query,
61
+ 'alt' => @response_format,
62
+ 'format' => @video_format,
63
+ 'racy' => @racy,
64
+ 'author' => @author,
65
+ 'lr' => @lang
66
+ }
67
+ end
68
+
69
+
70
+ # Convert category symbols into strings and build the URL. GData requires categories to be capitalized.
71
+ # Categories defined like: categories => { :include => [:news], :exclude => [:sports], :either => [..] }
72
+ # or like: categories => [:news, :sports]
73
+ def categories_to_params(categories)
74
+ if categories.respond_to?(:keys) and categories.respond_to?(:[])
75
+ s = ""
76
+ s << categories[:either].map { |c| c.to_s.capitalize }.join("%7C") << '/' if categories[:either]
77
+ s << categories[:include].map { |c| c.to_s.capitalize }.join("/") << '/' if categories[:include]
78
+ s << ("-" << categories[:exclude].map { |c| c.to_s.capitalize }.join("/-")) << '/' if categories[:exclude]
79
+ s
80
+ else
81
+ categories.map { |c| c.to_s.capitalize }.join("/") << '/'
82
+ end
83
+ end
84
+
85
+ # Tags defined like: tags => { :include => [:football], :exclude => [:soccer], :either => [:polo, :tennis] }
86
+ # or tags => [:football, :soccer]
87
+ def tags_to_params(tags)
88
+ if tags.respond_to?(:keys) and tags.respond_to?(:[])
89
+ s = ""
90
+ s << tags[:either].map { |t| YouTubeIt.esc(t.to_s) }.join("%7C") << '/' if tags[:either]
91
+ s << tags[:include].map { |t| YouTubeIt.esc(t.to_s) }.join("/") << '/' if tags[:include]
92
+ s << ("-" << tags[:exclude].map { |t| YouTubeIt.esc(t.to_s) }.join("/-")) << '/' if tags[:exclude]
93
+ s
94
+ else
95
+ tags.map { |t| YouTubeIt.esc(t.to_s) }.join("/") << '/'
96
+ end
97
+ end
98
+
99
+ end
100
+ end
101
+ end
102
+
@@ -0,0 +1,415 @@
1
+ class YouTubeIt
2
+ module Upload
3
+ class VideoUpload
4
+ include YouTubeIt::Logging
5
+
6
+ def initialize *params
7
+ if params.first.is_a?(Hash)
8
+ hash_options = params.first
9
+ @user = hash_options[:username]
10
+ @password = hash_options[:password]
11
+ @dev_key = hash_options[:dev_key]
12
+ @access_token = hash_options[:access_token]
13
+ @authsub_token = hash_options[:authsub_token]
14
+ @client_id = hash_options[:client_id] || "youtube_it"
15
+ @config_token = hash_options[:config_token]
16
+ else
17
+ puts "* warning: the method YouTubeIt::Upload::VideoUpload.new(username, password, dev_key) is depricated, use YouTubeIt::Upload::VideoUpload.new(:username => 'user', :password => 'passwd', :dev_key => 'dev_key')"
18
+ @user = params.shift
19
+ @password = params.shift
20
+ @dev_key = params.shift
21
+ @access_token = params.shift
22
+ @authsub_token = params.shift
23
+ @client_id = params.shift || "youtube_it"
24
+ @config_token = params.shift
25
+ end
26
+ end
27
+
28
+
29
+ def enable_http_debugging
30
+ @http_debugging = true
31
+ end
32
+
33
+ #
34
+ # Upload "data" to youtube, where data is either an IO object or
35
+ # raw file data.
36
+ # The hash keys for opts (which specify video info) are as follows:
37
+ # :mime_type
38
+ # :filename
39
+ # :title
40
+ # :description
41
+ # :category
42
+ # :keywords
43
+ # :private
44
+ # New V2 api hash keys for accessControl:
45
+ # :rate
46
+ # :comment
47
+ # :commentVote
48
+ # :videoRespond
49
+ # :list
50
+ # :embed
51
+ # :syndicate
52
+ # Specifying :private will make the video private, otherwise it will be public.
53
+ #
54
+ # When one of the fields is invalid according to YouTube,
55
+ # an UploadError will be raised. Its message contains a list of newline separated
56
+ # errors, containing the key and its error code.
57
+ #
58
+ # When the authentication credentials are incorrect, an AuthenticationError will be raised.
59
+ def upload(data, opts = {})
60
+ @opts = { :mime_type => 'video/mp4',
61
+ :title => '',
62
+ :description => '',
63
+ :category => '',
64
+ :keywords => [] }.merge(opts)
65
+
66
+ @opts[:filename] ||= generate_uniq_filename_from(data)
67
+
68
+ post_body_io = generate_upload_io(video_xml, data)
69
+
70
+ upload_header = {
71
+ "Slug" => "#{@opts[:filename]}",
72
+ "Content-Type" => "multipart/related; boundary=#{boundary}",
73
+ "Content-Length" => "#{post_body_io.expected_length}",
74
+ }
75
+
76
+ upload_url = "/feeds/api/users/default/uploads"
77
+ response = yt_session(uploads_url).post(upload_url, post_body_io, upload_header)
78
+
79
+ return YouTubeIt::Parser::VideoFeedParser.new(response.body).parse
80
+ end
81
+
82
+ # Updates a video in YouTube. Requires:
83
+ # :title
84
+ # :description
85
+ # :category
86
+ # :keywords
87
+ # The following are optional attributes:
88
+ # :private
89
+ # When the authentication credentials are incorrect, an AuthenticationError will be raised.
90
+ def update(video_id, options)
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)
95
+
96
+ return YouTubeIt::Parser::VideoFeedParser.new(response.body).parse
97
+ end
98
+
99
+ # Fetches the data of a video, which may be private. The video must be owned by this user.
100
+ # When the authentication credentials are incorrect, an AuthenticationError will be raised.
101
+ def get_my_video(video_id)
102
+ get_url = "/feeds/api/users/default/uploads/%s" % video_id
103
+ response = yt_session.get(get_url)
104
+
105
+ return YouTubeIt::Parser::VideoFeedParser.new(response.body).parse
106
+ end
107
+
108
+ # Fetches the data of the videos of the current user, which may be private.
109
+ # When the authentication credentials are incorrect, an AuthenticationError will be raised.
110
+ def get_my_videos(opts)
111
+ max_results = opts[:per_page] || 50
112
+ start_index = ((opts[:page] || 1) -1) * max_results +1
113
+ get_url = "/feeds/api/users/default/uploads?max-results=#{max_results}&start-index=#{start_index}"
114
+ response = yt_session.get(get_url)
115
+
116
+ return YouTubeIt::Parser::VideosFeedParser.new(response.body).parse
117
+ end
118
+
119
+ # Delete a video on YouTube
120
+ def delete(video_id)
121
+ delete_url = "/feeds/api/users/default/uploads/%s" % video_id
122
+ response = yt_session.delete(delete_url)
123
+
124
+ return true
125
+ end
126
+
127
+ def get_upload_token(options, nexturl)
128
+ @opts = options
129
+ token_body = video_xml
130
+ token_url = "/action/GetUploadToken"
131
+ response = yt_session.post(token_url, token_body)
132
+
133
+ return {:url => "#{response.body[/<url>(.+)<\/url>/, 1]}?nexturl=#{nexturl}",
134
+ :token => response.body[/<token>(.+)<\/token>/, 1]}
135
+ end
136
+
137
+ def add_comment(video_id, comment)
138
+ comment_body = video_xml_for(:comment => comment)
139
+ comment_url = "/feeds/api/videos/%s/comments" % video_id
140
+ response = yt_session.post(comment_url, comment_body)
141
+
142
+ return {:code => response.status, :body => response.body}
143
+ end
144
+
145
+ def comments(video_id, opts = {})
146
+ comment_url = "/feeds/api/videos/%s/comments?" % video_id
147
+ comment_url << opts.collect { |k,p| [k,p].join '=' }.join('&')
148
+ response = yt_session.get(comment_url)
149
+
150
+ return YouTubeIt::Parser::CommentsFeedParser.new(response).parse
151
+ end
152
+
153
+ def add_favorite(video_id)
154
+ favorite_body = video_xml_for(:favorite => video_id)
155
+ favorite_url = "/feeds/api/users/default/favorites"
156
+ response = yt_session.post(favorite_url, favorite_body)
157
+
158
+ return {:code => response.status, :body => response.body}
159
+ end
160
+
161
+ def delete_favorite(video_id)
162
+ favorite_header = {
163
+ "GData-Version" => "1",
164
+ }
165
+ favorite_url = "/feeds/api/users/default/favorites/%s" % video_id
166
+ response = yt_session.delete(favorite_url, favorite_header)
167
+
168
+ return true
169
+ end
170
+
171
+ def profile(user)
172
+ profile_url = "/feeds/api/users/%s?v=2" % (user ? user : "default")
173
+ response = yt_session.get(profile_url)
174
+
175
+ return YouTubeIt::Parser::ProfileFeedParser.new(response).parse
176
+ end
177
+
178
+ def playlist(playlist_id)
179
+ playlist_url = "/feeds/api/playlists/%s?v=2" % playlist_id
180
+ response = yt_session.get(playlist_url)
181
+
182
+ return YouTubeIt::Parser::PlaylistFeedParser.new(response).parse
183
+ end
184
+
185
+ def playlists(user)
186
+ playlist_url = "/feeds/api/users/%s/playlists?v=2" % (user ? user : "default")
187
+ response = yt_session.get(playlist_url)
188
+
189
+ return YouTubeIt::Parser::PlaylistsFeedParser.new(response).parse
190
+ end
191
+
192
+ def add_playlist(options)
193
+ playlist_body = video_xml_for_playlist(options)
194
+ playlist_url = "/feeds/api/users/default/playlists"
195
+ response = yt_session.post(playlist_url, playlist_body)
196
+
197
+ return YouTubeIt::Parser::PlaylistFeedParser.new(response).parse
198
+ end
199
+
200
+ def add_video_to_playlist(playlist_id, video_id)
201
+ playlist_body = video_xml_for(:playlist => video_id)
202
+ playlist_url = "/feeds/api/playlists/%s" % playlist_id
203
+ response = yt_session.post(playlist_url, playlist_body)
204
+
205
+ return {:code => response.status, :body => response.body, :playlist_entry_id => playlist_entry_id_from_playlist(response.body)}
206
+ end
207
+
208
+ def update_playlist(playlist_id, options)
209
+ playlist_body = video_xml_for_playlist(options)
210
+ playlist_url = "/feeds/api/users/default/playlists/%s" % playlist_id
211
+ response = yt_session.put(playlist_url, playlist_body)
212
+
213
+ return YouTubeIt::Parser::PlaylistFeedParser.new(response).parse
214
+ end
215
+
216
+ def delete_video_from_playlist(playlist_id, playlist_entry_id)
217
+ playlist_url = "/feeds/api/playlists/%s/%s" % [playlist_id, playlist_entry_id]
218
+ response = yt_session.delete(playlist_url)
219
+
220
+ return true
221
+ end
222
+
223
+ def delete_playlist(playlist_id)
224
+ playlist_url = "/feeds/api/users/default/playlists/%s" % playlist_id
225
+ response = yt_session.delete(playlist_url)
226
+
227
+ return true
228
+ end
229
+
230
+ def rate_video(video_id, rating)
231
+ rating_body = video_xml_for(:rating => rating)
232
+ rating_url = "/feeds/api/videos/#{video_id}/ratings"
233
+ response = yt_session.post(rating_url, rating_body)
234
+
235
+ return {:code => response.status, :body => response.body}
236
+ end
237
+
238
+ def subscriptions(user)
239
+ subscription_url = "/feeds/api/users/%s/subscriptions?v=2" % (user ? user : "default")
240
+ response = yt_session.get(subscription_url)
241
+
242
+ return YouTubeIt::Parser::SubscriptionFeedParser.new(response).parse
243
+ end
244
+
245
+ def subscribe_channel(channel_name)
246
+ subscribe_body = video_xml_for(:subscribe => channel_name)
247
+ subscribe_url = "/feeds/api/users/default/subscriptions"
248
+ response = yt_session.post(subscribe_url, subscribe_body)
249
+
250
+ return {:code => response.status, :body => response.body}
251
+ end
252
+
253
+ def unsubscribe_channel(subscription_id)
254
+ unsubscribe_url = "/feeds/api/users/default/subscriptions/%s" % subscription_id
255
+ response = yt_session.delete(unsubscribe_url)
256
+
257
+ return {:code => response.status, :body => response.body}
258
+ end
259
+
260
+ def favorites(user, opts = {})
261
+ favorite_url = "/feeds/api/users/%s/favorites#{opts.empty? ? '' : '?#{opts.to_param}'}" % (user ? user : "default")
262
+ response = yt_session.get(favorite_url)
263
+
264
+ return YouTubeIt::Parser::VideosFeedParser.new(response.body).parse
265
+ end
266
+
267
+ def get_current_user
268
+ current_user_url = "/feeds/api/users/default"
269
+ response = yt_session.get(current_user_url, authorization_headers)
270
+
271
+ return REXML::Document.new(response.body).elements["entry"].elements['author'].elements['name'].text
272
+ end
273
+
274
+ private
275
+
276
+ def uploads_url
277
+ ["http://uploads", base_url.sub("http://","")].join('.')
278
+ end
279
+
280
+ def base_url
281
+ "http://gdata.youtube.com"
282
+ end
283
+
284
+ def boundary
285
+ "An43094fu"
286
+ end
287
+
288
+ def authorization_headers
289
+ header = {
290
+ "X-GData-Client" => "#{@client_id}",
291
+ "X-GData-Key" => "key=#{@dev_key}",
292
+ }
293
+ if @authsub_token
294
+ header.merge!("Authorization" => "AuthSub token=#{@authsub_token}")
295
+ elsif @access_token.nil? && @authsub_token.nil?
296
+ header.merge!("Authorization" => "GoogleLogin auth=#{auth_token}")
297
+ end
298
+ header
299
+ end
300
+
301
+ def uploaded_video_id_from(string)
302
+ xml = REXML::Document.new(string)
303
+ xml.elements["//id"].text[/videos\/(.+)/, 1]
304
+ end
305
+
306
+ def playlist_id_from(string)
307
+ xml = REXML::Document.new(string)
308
+ entry = xml.elements["entry"]
309
+ entry.elements["id"].text[/playlist([^<]+)/, 1].sub(':','')
310
+ end
311
+
312
+ # If data can be read, use the first 1024 bytes as filename. If data
313
+ # is a file, use path. If data is a string, checksum it
314
+ def generate_uniq_filename_from(data)
315
+ if data.respond_to?(:path)
316
+ Digest::MD5.hexdigest(data.path)
317
+ elsif data.respond_to?(:read)
318
+ chunk = data.read(1024)
319
+ data.rewind
320
+ Digest::MD5.hexdigest(chunk)
321
+ else
322
+ Digest::MD5.hexdigest(data)
323
+ end
324
+ end
325
+
326
+ def auth_token
327
+ @auth_token ||= begin
328
+ http = Faraday.new("https://www.google.com")
329
+ body = "Email=#{YouTubeIt.esc @user}&Passwd=#{YouTubeIt.esc @password}&service=youtube&source=#{YouTubeIt.esc @client_id}"
330
+ response = http.post("/youtube/accounts/ClientLogin", body, "Content-Type" => "application/x-www-form-urlencoded")
331
+ raise ::AuthenticationError.new(response.body[/Error=(.+)/,1], response.status.to_i) if response.status.to_i != 200
332
+ @auth_token = response.body[/Auth=(.+)/, 1]
333
+ end
334
+ end
335
+
336
+ # TODO: isn't there a cleaner way to output top-notch XML without requiring stuff all over the place?
337
+ def video_xml
338
+ b = Builder::XmlMarkup.new
339
+ b.instruct!
340
+ b.entry(:xmlns => "http://www.w3.org/2005/Atom", 'xmlns:media' => "http://search.yahoo.com/mrss/", 'xmlns:yt' => "http://gdata.youtube.com/schemas/2007") do | m |
341
+ m.tag!("media:group") do | mg |
342
+ mg.tag!("media:title", @opts[:title], :type => "plain")
343
+ mg.tag!("media:description", @opts[:description], :type => "plain")
344
+ mg.tag!("media:keywords", @opts[:keywords].join(","))
345
+ mg.tag!('media:category', @opts[:category], :scheme => "http://gdata.youtube.com/schemas/2007/categories.cat")
346
+ mg.tag!('yt:private') if @opts[:private]
347
+ mg.tag!('media:category', @opts[:dev_tag], :scheme => "http://gdata.youtube.com/schemas/2007/developertags.cat") if @opts[:dev_tag]
348
+ end
349
+ m.tag!("yt:accessControl", :action => "rate", :permission => @opts[:rate]) if @opts[:rate]
350
+ m.tag!("yt:accessControl", :action => "comment", :permission => @opts[:comment]) if @opts[:comment]
351
+ m.tag!("yt:accessControl", :action => "commentVote", :permission => @opts[:commentVote]) if @opts[:commentVote]
352
+ m.tag!("yt:accessControl", :action => "videoRespond", :permission => @opts[:videoRespond]) if @opts[:videoRespond]
353
+ m.tag!("yt:accessControl", :action => "list", :permission => @opts[:list]) if @opts[:list]
354
+ m.tag!("yt:accessControl", :action => "embed", :permission => @opts[:embed]) if @opts[:embed]
355
+ m.tag!("yt:accessControl", :action => "syndicate", :permission => @opts[:syndicate]) if @opts[:syndicate]
356
+ end.to_s
357
+ end
358
+
359
+ def video_xml_for(data)
360
+ b = Builder::XmlMarkup.new
361
+ b.instruct!
362
+ b.entry(:xmlns => "http://www.w3.org/2005/Atom", 'xmlns:yt' => "http://gdata.youtube.com/schemas/2007") do | m |
363
+ m.content(data[:comment]) if data[:comment]
364
+ m.id(data[:favorite] || data[:playlist]) if data[:favorite] || data[:playlist]
365
+ m.tag!("yt:rating", :value => data[:rating]) if data[:rating]
366
+ if(data[:subscribe])
367
+ m.category(:scheme => "http://gdata.youtube.com/schemas/2007/subscriptiontypes.cat", :term => "channel")
368
+ m.tag!("yt:username", data[:subscribe])
369
+ end
370
+ end.to_s
371
+ end
372
+
373
+ def video_xml_for_playlist(data)
374
+ b = Builder::XmlMarkup.new
375
+ b.instruct!
376
+ b.entry(:xmlns => "http://www.w3.org/2005/Atom", 'xmlns:yt' => "http://gdata.youtube.com/schemas/2007") do | m |
377
+ m.title(data[:title]) if data[:title]
378
+ m.summary(data[:description] || data[:summary]) if data[:description] || data[:summary]
379
+ m.tag!('yt:private') if data[:private]
380
+ end.to_s
381
+ end
382
+
383
+ def generate_upload_io(video_xml, data)
384
+ post_body = [
385
+ "--#{boundary}\r\n",
386
+ "Content-Type: application/atom+xml; charset=UTF-8\r\n\r\n",
387
+ video_xml,
388
+ "\r\n--#{boundary}\r\n",
389
+ "Content-Type: #{@opts[:mime_type]}\r\nContent-Transfer-Encoding: binary\r\n\r\n",
390
+ data,
391
+ "\r\n--#{boundary}--\r\n",
392
+ ]
393
+
394
+ # Use Greedy IO to not be limited by 1K chunks
395
+ YouTubeIt::GreedyChainIO.new(post_body)
396
+ end
397
+
398
+ def playlist_entry_id_from_playlist(string)
399
+ playlist_xml = REXML::Document.new(string)
400
+ playlist_xml.elements.each("/entry") do |item|
401
+ return item.elements["id"].text[/^.*:([^:]+)$/,1]
402
+ end
403
+ end
404
+
405
+ def yt_session(url = nil)
406
+ Faraday.new(:url => url ? url : base_url) do |builder|
407
+ builder.use Faraday::Request::OAuth, @config_token if @config_token
408
+ builder.use Faraday::Request::AuthHeader, authorization_headers
409
+ builder.use Faraday::Response::YouTubeIt
410
+ builder.adapter Faraday.default_adapter
411
+ end
412
+ end
413
+ end
414
+ end
415
+ end
@@ -0,0 +1,41 @@
1
+ class YouTubeIt
2
+ module Response
3
+ class VideoSearch < YouTubeIt::Record
4
+ # *String*:: Unique feed identifying url.
5
+ attr_reader :feed_id
6
+
7
+ # *Fixnum*:: Number of results per page.
8
+ attr_reader :max_result_count
9
+
10
+ # *Fixnum*:: 1-based offset index into the full result set.
11
+ attr_reader :offset
12
+
13
+ # *Fixnum*:: Total number of results available for the original request.
14
+ attr_reader :total_result_count
15
+
16
+ # *Time*:: Date and time at which the feed was last updated
17
+ attr_reader :updated_at
18
+
19
+ # *Array*:: Array of YouTubeIt::Model::Video records
20
+ attr_reader :videos
21
+
22
+ def current_page
23
+ ((offset - 1) / max_result_count) + 1
24
+ end
25
+
26
+ # current_page + 1 or nil if there is no next page
27
+ def next_page
28
+ current_page < total_pages ? (current_page + 1) : nil
29
+ end
30
+
31
+ # current_page - 1 or nil if there is no previous page
32
+ def previous_page
33
+ current_page > 1 ? (current_page - 1) : nil
34
+ end
35
+
36
+ def total_pages
37
+ (total_result_count / max_result_count.to_f).ceil
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,4 @@
1
+ class YouTubeIt
2
+ VERSION = '2.0.0.vbdk'
3
+ end
4
+