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