vibedeck-youtube_it 0.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.
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
+