I’m quite busy recently, and as result I write posts on my blogs with smaller frequency as I usually did… But there are few interesting topics I want to write about. First – RFacebook and photos upload.
I’m using RFacebook gem to handle calls to Facebook API. But recently I found out, that probably there is no way to upload photos to Facebook with RFacebook. The reason is that API call is special case and as far as I know, there is no code for that in RFacebook.
So we need to extend RFacebook by ourself. Problem with facebook.photos.upload is that need to be multi-part encoded post, that means MIME encoding. Since this is one way post, we don’t need any specialized library to handle MIME thus we will prepare own code. To make HTTP request Net::HTTP Ruby library is obvious choice, however it does not support multiparts.
First – Google, and I found this post describing how to make multiparts with Net::HTTP.
Next we need to extend RFacebook::FacebookWebSession providing photos_upload method. RFacebook uses method_missing to handle calls to API, providing own method photos_upload will skip default processing flow:
module RFacebook
class FacebookWebSession
def photos_upload(params = {})
params = (params || {}).dup
params[:method] = "facebook.photos.upload"
params[:api_key] = FACEBOOK["key"]
params[:v] = API_VERSION
params[:session_key] = session_key
params[:call_id] = Time.now.to_f.to_s
file = params.delete :file
params[:sig] = signature(params)
boundary = 'some_long_and_random_string_which_wont_show_in_data_stream'
params_as_arr = []
params.each {|k,v| params_as_arr << text_to_multipart(k,v)}
params_as_arr << file_to_multipart('filename', 'somefile', 'image/jpg', file)
qry = params_as_arr.collect {|p|
'--' + boundary + "\r\n" + p
}.join('') + "--" + boundary + "--\r\n"
handle_xml_response(
Net::HTTP.start(API_HOST).post2(
API_PATH_REST,
qry,
"Content-type" => "multipart/form-data; boundary=" + boundary).response.body.to_s
)
end
end
private
def text_to_multipart(key,value)
return "Content-Disposition: form-data; name=\"#{key.to_s}\"\r\n" +
"\r\n" +
"#{value}\r\n"
end
def file_to_multipart(key,filename,mime_type,content)
return "Content-Disposition: form-data; name=\"#{key.to_s}\"; filename=\"#{CGI::escape(filename)}\"\r\n" +
"Content-Transfer-Encoding: binary\r\n" +
"Content-Type: #{mime_type}\r\n" +
"\r\n" +
"#{content}\r\n"
end
end
Now assuming that fbsession is valid Facebook session we use it providing :file with raw data and :caption for description to Facebook:
fbsession.photos_upload :file => File.read("SOME_PATH_TO_FILE.jpg"),
:caption => 'some caption'
As You can see this is very ‘rough’ solution, just to give You idea where to head next (error checking, handle other MIME types than image/jpeg, etc).
Please give me You thoughts on that code – if there will be some response I will feel obligated to prepare some more quality code to submit it as patch to RFacebook :)))
Leave a Reply