Upload Photo from web url

Aug 3, 2009 at 6:51 PM

Hi,

I have a photo on a publically accessible URL that I would like to be able to upload to facebook.

The API seems to only allow a FileInfo object and not a url.

Does this mean that I have to artificially cache the file on the local disk before being able to upload it to facebook? This will obviously make the uploading of a large number of photos take a much longer time than necessary.

Thanks,

~Liron

Aug 4, 2009 at 4:05 AM
Edited Aug 4, 2009 at 4:10 AM

FileInfo object constructor takes one argument as input and that argument referes to local path and not the URI. Thus it can be any location from your computer only. I don't think you have a way out to upload a picture from Url under current version.

Aug 4, 2009 at 4:58 PM

When I try that I get the following exception:

System.ArgumentException: URI formats are not supported.

   at System.IO.Path.NormalizePathFast(String path, Boolean fullCheck)

   at System.IO.Path.NormalizePath(String path, Boolean fullCheck)

   at System.IO.Path.GetFullPathInternal(String path)

   at System.IO.FileInfo..ctor(String fileName)

I can make it work if I hack the source code to add an upload command like:

Facebook.photos.upload(long aid, string caption, byte[] data, string name)

If you want me to send the code changes I needed for this, I would be happy to.

Thanks,

~Liron

From: ash_of_roses [mailto:notifications@codeplex.com]
Sent: Monday, August 03, 2009 9:06 PM
To: Liron Kopinsky
Subject: Re: Upload Photo from web url [FacebookToolkit:64332]

From: ash_of_roses

FileInfo object constructor takes one argument as input and that argument referes to Url. Thus it can be any location including ur local computer or a resource on the internet.

Read the full discussion online.

To add a post to this discussion, reply to this email (FacebookToolkit@discussions.codeplex.com)

To start a new discussion for this project, email FacebookToolkit@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com

Aug 4, 2009 at 5:09 PM

In addition to the problem below, the aid returned in the album object seems to not be valid. I am getting “100000033063373_3754” but the upload method requires a long.

Did something change in the definition of what the aid can be?

Thanks,
~Liron

From: Liron_K [mailto:notifications@codeplex.com]
Sent: Tuesday, August 04, 2009 9:59 AM
To: Liron Kopinsky
Subject: Re: Upload Photo from web url [FacebookToolkit:64332]

From: Liron_K

When I try that I get the following exception:

System.ArgumentException: URI formats are not supported.

at System.IO.Path.NormalizePathFast(String path, Boolean fullCheck)

at System.IO.Path.NormalizePath(String path, Boolean fullCheck)

at System.IO.Path.GetFullPathInternal(String path)

at System.IO.FileInfo..ctor(String fileName)

I can make it work if I hack the source code to add an upload command like:

Facebook.photos.upload(long aid, string caption, byte[] data, string name)

If you want me to send the code changes I needed for this, I would be happy to.

Thanks,

~Liron

From: ash_of_roses [mailto:notifications@codeplex.com]
Sent: Monday, August 03, 2009 9:06 PM
To: Liron Kopinsky
Subject: Re: Upload Photo from web url [FacebookToolkit:64332]

From: ash_of_roses

FileInfo object constructor takes one argument as input and that argument referes to Url. Thus it can be any location including ur local computer or a resource on the internet.

Read the full discussion online.

To add a post to this discussion, reply to this email (FacebookToolkit@discussions.codeplex.com)

To start a new discussion for this project, email FacebookToolkit@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com

Read the full discussion online.

To add a post to this discussion, reply to this email (FacebookToolkit@discussions.codeplex.com)

To start a new discussion for this project, email FacebookToolkit@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com

Aug 4, 2009 at 5:24 PM

Hi Liron,

I didn't get that. Are you trying to say you have updated the source code to allow upload from a Url path possible? Mind to share?

Aug 4, 2009 at 5:31 PM

Here are the code changes I had to make.

To summarize them:

1) aid must be a string

2) allow input of a byte array.

If you want to get an image from a url now, you just call:

      String title = "my title";

WebClient wc = new WebClient();

      byte[] originalData = wc.DownloadData(YOUR_URL);

      _fbService.photos.upload(a.aid, "", originalData,title);

If anyone wants to actually commit this code, feel free.

From photos.cs:

            /// <summary>

            /// Uploads a photo owned by the current session user and returns the new photo. See photo uploads for a description of the upload workflow. The only storable values returned from this call are pid, aid, and owner.

            /// </summary>

            /// <param name="aid">Optional - The album id of the destination album.</param>

            /// <param name="caption">Optional - The caption of the photo.</param>

            /// <param name="data">A Fileinfo object of the image file on the local disk.</param>

            /// <param name="uid">The uid of the user to upload to.</param>

            /// <returns>Photo information, including the photo URL.</returns>     

            /// <remarks>If no album is specified, the photo will be uploaded to a default album for the application, which will be created if necessary. Regular albums have a size limit of 60 photos. Default application albums have a size limit of 1000 photos. It is strongly recommended that you scale the image in your application before adding it to the request. The largest dimension should be at most 604 pixels (the largest display size Facebook supports).</remarks>

            public photo upload(string aid, string caption, FileInfo data, long uid)

            {

            return upload(aid, caption, File.ReadAllBytes(data.FullName),data.Name, uid);

            }

        /// <summary>

        /// Uploads a photo owned by the current session user and returns the new photo. See photo uploads for a description of the upload workflow. The only storable values returned from this call are pid, aid, and owner.

        /// </summary>

        /// <param name="aid">Optional - The album id of the destination album.</param>

        /// <param name="caption">Optional - The caption of the photo.</param>

        /// <param name="data">The raw image data for the photo.</param>

        /// <returns>Photo information, including the photo URL.</returns>

        /// <remarks>If no album is specified, the photo will be uploaded to a default album for the application, which will be created if necessary. Regular albums have a size limit of 60 photos. Default application albums have a size limit of 1000 photos. It is strongly recommended that you scale the image in your application before adding it to the request. The largest dimension should be at most 604 pixels (the largest display size Facebook supports).</remarks>

        public photo upload(string aid, string caption, byte[] fileData, string fileName)

        {

            return upload(aid, caption, fileData, fileName, 0);

        }

        /// <summary>

        /// Uploads a photo owned by the current session user and returns the new photo. See photo uploads for a description of the upload workflow. The only storable values returned from this call are pid, aid, and owner.

        /// </summary>

        /// <param name="aid">Optional - The album id of the destination album.</param>

        /// <param name="caption">Optional - The caption of the photo.</param>

        /// <param name="data">The raw image data for the photo.</param>

        /// <param name="fileName">The name of the image you want.</param>

        /// <returns>Photo information, including the photo URL.</returns>

        /// <remarks>If no album is specified, the photo will be uploaded to a default album for the application, which will be created if necessary. Regular albums have a size limit of 60 photos. Default application albums have a size limit of 1000 photos. It is strongly recommended that you scale the image in your application before adding it to the request. The largest dimension should be at most 604 pixels (the largest display size Facebook supports).</remarks>

        public photo upload(string aid, string caption, byte[] fileData, string fileName, long uid)

        {

            var parameterList = new Dictionary<string, string> { { "method", "facebook.photos.upload" } };

            _api.AddOptionalParameter(parameterList, "aid", aid);

            _api.AddOptionalParameter(parameterList, "caption", caption);

            _api.AddOptionalParameter(parameterList, "uid", uid);

            var response = _api.ExecuteApiImageUpload(fileData, fileName, parameterList);

            return !string.IsNullOrEmpty(response) ? photos_upload_response.Parse(response).Content : null;

        }

From API.cs:

  internal string ExecuteApiImageUpload(FileSystemInfo uploadFile, IDictionary<string, string> parameterList)

        {

            parameterList.Add("api_key", ApplicationKey);

            parameterList.Add("session_key", SessionKey);

            parameterList.Add("v", VERSION);

            parameterList.Add("call_id", DateTime.Now.Ticks.ToString(CultureInfo.InvariantCulture));

            parameterList.Add("sig", GenerateSignature(parameterList));

            return GetFileQueryResponse(parameterList, uploadFile, "image/jpeg");

        }

        internal string ExecuteApiImageUpload(byte[] fileData, string fileName, IDictionary<string, string> parameterList)

        {

            parameterList.Add("api_key", ApplicationKey);

            parameterList.Add("session_key", SessionKey);

            parameterList.Add("v", VERSION);

            parameterList.Add("call_id", DateTime.Now.Ticks.ToString(CultureInfo.InvariantCulture));

            parameterList.Add("sig", GenerateSignature(parameterList));

            return GetFileQueryResponse(parameterList, fileData, fileName, "image/jpeg");

        }

        /// <summary>

        /// Get File Query Response

        /// </summary>

        /// <param name="parameterDictionary">parameter list</param>

        /// <param name="uploadFile">uploaded file info</param>

        /// <returns>Response data</returns>

        internal static string GetFileQueryResponse(IEnumerable<KeyValuePair<string, string>> parameterDictionary,

                                                    byte[] fileData, string filename, string contentType)

        {

            string responseData;

            string boundary = DateTime.Now.Ticks.ToString("x", CultureInfo.InvariantCulture);

            string sRequestUrl = Resources.FacebookRESTUrl;

            if (contentType == "video/avi")

            {

                sRequestUrl = sRequestUrl.Replace("api.", "api-video.");

            }

            // Build up the post message header

            var sb = new StringBuilder();

            foreach (var kvp in parameterDictionary)

            {

                sb.Append(PREFIX).Append(boundary).Append(NEWLINE);

                sb.Append("Content-Disposition: form-data; name=\"").Append(kvp.Key).Append("\"");

                sb.Append(NEWLINE);

                sb.Append(NEWLINE);

                sb.Append(kvp.Value);

                sb.Append(NEWLINE);

            }

            sb.Append(PREFIX).Append(boundary).Append(NEWLINE);

            sb.Append("Content-Disposition: form-data; filename=\"").Append(filename).Append("\"").Append(NEWLINE);

            sb.Append("Content-Type: ").Append(contentType).Append(NEWLINE).Append(NEWLINE);

            byte[] postHeaderBytes = Encoding.UTF8.GetBytes(sb.ToString());

            byte[] boundaryBytes = Encoding.UTF8.GetBytes(String.Concat(NEWLINE, PREFIX, boundary, PREFIX, NEWLINE));

            var webrequest = (HttpWebRequest)WebRequest.Create(sRequestUrl);

            webrequest.ContentLength = postHeaderBytes.Length + fileData.Length + boundaryBytes.Length;

            webrequest.ContentType = String.Concat("multipart/form-data; boundary=", boundary);

            webrequest.Method = "POST";

            using (Stream requestStream = webrequest.GetRequestStream())

            {

                requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);

                requestStream.Write(fileData, 0, fileData.Length);

                requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);

            }

            var response = (HttpWebResponse)webrequest.GetResponse();

            using (var streamReader = new StreamReader(response.GetResponseStream()))

            {

                responseData = streamReader.ReadToEnd();

            }

            ErrorCheck(responseData);

            return responseData;

        }

        /// <summary>

        /// Get File Query Response

        /// </summary>

        /// <param name="parameterDictionary">parameter list</param>

        /// <param name="uploadFile">uploaded file info</param>

        /// <returns>Response data</returns>

        internal static string GetFileQueryResponse(IEnumerable<KeyValuePair<string, string>> parameterDictionary,

                                                    FileSystemInfo uploadFile, string contentType)

        {

            byte[] fileData = File.ReadAllBytes(uploadFile.FullName);

            return GetFileQueryResponse(parameterDictionary, fileData, uploadFile.Name, contentType);

        }

From: ash_of_roses [mailto:notifications@codeplex.com]
Sent: Tuesday, August 04, 2009 10:24 AM
To: Liron Kopinsky
Subject: Re: Upload Photo from web url [FacebookToolkit:64332]

From: ash_of_roses

Hi Liron,

I didn't get that. Are you trying to say you have updated the source code to allow upload from a Url path possible? Mind to share?

Read the full discussion online.

To add a post to this discussion, reply to this email (FacebookToolkit@discussions.codeplex.com)

To start a new discussion for this project, email FacebookToolkit@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com

Aug 4, 2009 at 5:44 PM

But using WebClient, rn't u actually downloading the file on your local cache and then uploading the bytes? I mean, the roundtrip from Url to your local cache is still caused?

Aug 4, 2009 at 5:56 PM
Edited Aug 4, 2009 at 6:12 PM

With the new upload overload that takes byte input, something like this may be more efficent as to establish a connection between two end points, the actual Image containing URI and the facebook server,

WebRequest reqObj = WebRequest.Create("Your Url");
WebResponse responseObj = reqObj.GetResponse();
Stream streamObj = responseObj.GetResponseStream();
byte[] buffer = new byte[1024];

int totalBytes = stream.Read(buffer, 0, buffer.Length);

I think this would be more asynchronus and lightweigh

_fbService.photos.upload(a.aid, "", buffer,'Title');

Aug 4, 2009 at 6:03 PM

I’m a bit new to web development, so what is the difference between creating a webrequest and using the webclient?

From: ash_of_roses [mailto:notifications@codeplex.com]
Sent: Tuesday, August 04, 2009 10:56 AM
To: Liron Kopinsky
Subject: Re: Upload Photo from web url [FacebookToolkit:64332]

From: ash_of_roses

With the new upload overload that takes byte input, something like this may be more efficent as to establish a connection between two end points, the actual Image containing URI and the facebook server,

WebRequest reqObj = WebRequest.Create("Your Url");
WebResponse responseObj = reqObj.GetResponse();
Stream streamObj = responseObj.GetResponseStream();
byte[] buffer = new byte[1024];

I think this would be more asynchronus and lightweigh

_fbService.photos.upload(a.aid, "", buffer,'Title');

Read the full discussion online.

To add a post to this discussion, reply to this email (FacebookToolkit@discussions.codeplex.com)

To start a new discussion for this project, email FacebookToolkit@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com

Aug 4, 2009 at 6:33 PM

Kinldy take a look at this. Simply put, WebClient is a wrapper around WebRequest and makes it simpler to deal with. But I would tend to move for WebRequest due to Asynchronus nature and its little connectedness with UI. Take a look at this,

http://wildermuth.com/2008/09/27/WebClient_vs_WebRequest_in_Silverlight_2