msp-youtube-g 0.4.5 → 0.4.6
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/History.txt +3 -0
- data/lib/youtube_g/request/video_upload.rb +58 -30
- metadata +1 -1
data/History.txt
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
== trunk
|
2
2
|
|
3
|
+
* Add error-handling for video upload errors. [FiXato]
|
4
|
+
* Add error-handling for authentication errors from YouTube during video upload. [FiXato]
|
5
|
+
* Add support for making videos private upon video upload. [FiXato]
|
3
6
|
* Fix issue with REXML parsing of video upload response. [FiXato]
|
4
7
|
* Fix issue with response code comparison. [FiXato]
|
5
8
|
* Authcode is now retrieved for video uploads. [FiXato]
|
@@ -7,6 +7,7 @@ class YouTubeG
|
|
7
7
|
|
8
8
|
module Upload
|
9
9
|
class UploadError < Exception; end
|
10
|
+
class AuthenticationError < Exception; end
|
10
11
|
|
11
12
|
# require 'youtube_g'
|
12
13
|
#
|
@@ -17,9 +18,23 @@ class YouTubeG
|
|
17
18
|
# :keywords => %w[cool blah test]
|
18
19
|
|
19
20
|
class VideoUpload
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
|
22
|
+
attr_accessor :auth_token
|
23
|
+
def initialize user, pass, dev_key, client_id = 'youtube_g', auth_token = nil
|
24
|
+
@user, @pass, @dev_key, @client_id, @auth_token = user, pass, dev_key, client_id, auth_token
|
25
|
+
end
|
26
|
+
|
27
|
+
# TODO merge this in with logger.rb or replace logger.rb
|
28
|
+
def logger
|
29
|
+
if not Object.const_defined?(get_rails_default_logger_name)
|
30
|
+
Logger.new(STDOUT)
|
31
|
+
else
|
32
|
+
eval(get_rails_default_logger_name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_rails_default_logger_name
|
37
|
+
"RAILS_DEFAULT_LOGGER"
|
23
38
|
end
|
24
39
|
|
25
40
|
#
|
@@ -32,8 +47,14 @@ class YouTubeG
|
|
32
47
|
# :description
|
33
48
|
# :category
|
34
49
|
# :keywords
|
50
|
+
# :private
|
51
|
+
# Specifying :private will make the video private, otherwise it will be public.
|
35
52
|
#
|
36
|
-
|
53
|
+
# When one of the fields is invalid according to YouTube,
|
54
|
+
# an UploadError will be returned. Its message contains a list of newline separated
|
55
|
+
# errors, containing the key and its error code.
|
56
|
+
#
|
57
|
+
# When the authentication credentials are incorrect, an AuthenticationError will be raised.
|
37
58
|
def upload data, opts = {}
|
38
59
|
data = data.respond_to?(:read) ? data.read : data
|
39
60
|
@opts = { :mime_type => 'video/mp4',
|
@@ -46,29 +67,33 @@ class YouTubeG
|
|
46
67
|
upload_body = generate_upload_body(boundary, video_xml, data)
|
47
68
|
|
48
69
|
upload_header = {
|
49
|
-
"Authorization" => "GoogleLogin auth=#{
|
70
|
+
"Authorization" => "GoogleLogin auth=#{derive_auth_token}",
|
50
71
|
"X-GData-Client" => "#{@client_id}",
|
51
72
|
"X-GData-Key" => "key=#{@dev_key}",
|
52
73
|
"Slug" => "#{@opts[:filename]}",
|
53
74
|
"Content-Type" => "multipart/related; boundary=#{boundary}",
|
54
75
|
"Content-Length" => "#{upload_body.length}",
|
55
76
|
}
|
56
|
-
|
77
|
+
logger.debug("upload_header [#{upload_header}]")
|
57
78
|
|
58
79
|
direct_upload_url = "/feeds/api/users/#{@user}/uploads"
|
59
|
-
|
80
|
+
logger.debug("direct_upload_url [#{direct_upload_url}]")
|
60
81
|
|
61
82
|
Net::HTTP.start(base_url) do |upload|
|
62
83
|
response = upload.post(direct_upload_url, upload_body, upload_header)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
84
|
+
if response.code.to_i == 403
|
85
|
+
raise AuthenticationError, response.body[/<TITLE>(.+)<\/TITLE>/, 1]
|
86
|
+
elsif response.code.to_i != 201
|
87
|
+
upload_error = ''
|
88
|
+
xml = REXML::Document.new(response.body)
|
89
|
+
errors = xml.elements["//errors"]
|
90
|
+
errors.each do |error|
|
91
|
+
location = error.elements["location"].text[/media:group\/media:(.*)\/text\(\)/,1]
|
92
|
+
code = error.elements["code"].text
|
93
|
+
upload_error << sprintf("%s: %s\r\n", location, code)
|
94
|
+
end
|
95
|
+
raise UploadError, upload_error
|
69
96
|
end
|
70
|
-
|
71
|
-
|
72
97
|
end
|
73
98
|
|
74
99
|
end
|
@@ -83,31 +108,34 @@ class YouTubeG
|
|
83
108
|
"An43094fu"
|
84
109
|
end
|
85
110
|
|
86
|
-
def
|
111
|
+
def derive_auth_token
|
87
112
|
unless @auth_token
|
88
113
|
http = Net::HTTP.new("www.google.com", 443)
|
89
114
|
http.use_ssl = true
|
90
115
|
body = "Email=#{CGI::escape @user}&Passwd=#{CGI::escape @pass}&service=youtube&source=#{CGI::escape @client_id}"
|
91
|
-
|
116
|
+
logger.debug("auth body [#{body}]")
|
92
117
|
response = http.post("/youtube/accounts/ClientLogin", body, "Content-Type" => "application/x-www-form-urlencoded")
|
93
|
-
raise UploadError, "
|
94
|
-
|
118
|
+
raise UploadError, ""+response.body[/Error=(.+)/,1] if response.code.to_i != 200
|
119
|
+
logger.debug("response.body [#{response.body}]")
|
95
120
|
@auth_token = response.body[/Auth=(.+)/, 1]
|
96
121
|
|
97
122
|
end
|
98
|
-
|
123
|
+
logger.debug "auth_token [#{@auth_token}]"
|
99
124
|
@auth_token
|
100
125
|
end
|
101
126
|
|
102
127
|
def video_xml
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
128
|
+
video_xml = ''
|
129
|
+
video_xml << '<?xml version="1.0"?>'
|
130
|
+
video_xml << '<entry xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:yt="http://gdata.youtube.com/schemas/2007">'
|
131
|
+
video_xml << '<media:group>'
|
132
|
+
video_xml << '<media:title type="plain">%s</media:title>' % @opts[:title]
|
133
|
+
video_xml << '<media:description type="plain">%s</media:description>' % @opts[:description]
|
134
|
+
video_xml << '<media:keywords>%s</media:keywords>' % @opts[:keywords].join(",")
|
135
|
+
video_xml << '<media:category scheme="http://gdata.youtube.com/schemas/2007/categories.cat">%s</media:category>' % @opts[:category]
|
136
|
+
video_xml << '<yt:private/>' if @opts[:private]
|
137
|
+
video_xml << '</media:group>'
|
138
|
+
video_xml << '</entry>'
|
111
139
|
end
|
112
140
|
|
113
141
|
def generate_upload_body(boundary, video_xml, data)
|
@@ -119,8 +147,8 @@ class YouTubeG
|
|
119
147
|
upload_body << "Content-Type: #{@opts[:mime_type]}\r\nContent-Transfer-Encoding: binary\r\n\r\n"
|
120
148
|
upload_body << data
|
121
149
|
upload_body << "\r\n--#{boundary}--\r\n"
|
122
|
-
end
|
123
|
-
|
150
|
+
end
|
151
|
+
|
124
152
|
end
|
125
153
|
end
|
126
154
|
end
|