Donate

Upload Photos Or Files To Google Photos Using Google Photos API, REST And C#.NET

Good morning!

I wrote a console application before Read Files From Google Photos Using Google Photos API, REST And C#.NET that reads media items from Google Photos using Google Photos API, C# And REST. That console application was the foundation to one of my project using real world client API. However, that project is limited to only read files and does not have the upload capabilities. Now that I'm free with the projects at work, it's time to revisit the Google Photos API and create a simple console application that will upload photos/images or files to Google Photos using REST, Google Photos API and C#.

So to get started, make sure you have read the documentation to setup the API here Get started with REST. Once you have successfully setup the API, download the JSON file that contains your credentials specifically Client Secret and Client ID and add that file to your console app project. Make sure to set the Copy to Output Directory of the JSON file to Copy always in Visual Studio's Solution Explorer. Add also these Nuget packages Google.Apis, Google.Apis.Auth and Google.Apis.Core since they will be used to authenticate your console application when accessing the Google Photos cloud. 

The console app's main method get's the files to be uploaded from an existing directory, set's the scope of the application to create media items and upload in bytes which is appendonly and performs the authorization and authentication of your application. It will then call the uploading of files method which will pass the directory, UserCredential object and the files retrieved.
static void Main(string[] args)
{
	string UserName = "your_gmail_account@gmail.com";
	string credPath = @"D:\Codes\GooglePhotosUpload\";
	string filesRepository = @"D:\FilesToUploadFolder";
	string[] files = Directory.GetFiles(filesRepository);
    UserCredential credential;
	string[] scopes = {
		"https://www.googleapis.com/auth/photoslibrary.appendonly"
	 };

	

	using (var stream = new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
	{
		credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
			GoogleClientSecrets.Load(stream).Secrets,
			scopes,
			UserName,
			CancellationToken.None,
			new FileDataStore(credPath, true)).Result;
	}

	try
	{          
		if (files.Length > 0)
		{
			UploadFileWebRequest(filesRepository, credential, files);
		}
	}
	catch (Exception ex)
	{
		Console.WriteLine("Error occured: " + ex.Message);
	}

	Console.WriteLine("Files Uploaded Successfully!!!");
	Console.ReadLine();
}
The uploading of files method loops through the files and creates a task object for each individual file which in turn will send a POST request to the API along with the POST request headers defined in this documentation Upload Media. If the posting of a file is successful, it will then return an upload-token for that file which will be used to create that media item in the cloud. I added the upload token along with the file name to a dictionary which will be used to create the media items.Next is to create the JSON string that contains the media items to be pushed to the cloud that follows the format defined in the documentation above. A separate request object is created including the url and the correct headers that will upload the media items to the cloud.
private static void UploadFileWebRequest(string filesRepository, UserCredential credential, string[] fileNames)
{
	string jsonData = string.Empty;
	List<Task> tasks = new List<Task>();
	Dictionary<string, string> fileUploads = new Dictionary<string, string>();

	//Get upload-token 
	foreach (var fileName in fileNames)
	{
		var task = new Task(() =>
		{
			byte[] byteArr = File.ReadAllBytes(Path.Combine(filesRepository, Path.GetFileName(fileName)));

			var request = WebRequest.Create("https://photoslibrary.googleapis.com/v1/uploads");
			request.Method = "POST";
			request.Headers.Add("Authorization:" + credential.Token.TokenType + " " + credential.Token.AccessToken);
			request.Headers.Add("X-Goog-Upload-Content-Type", "raw");
			request.Headers.Add("X-Goog-Upload-Content-Type", "image/jpeg");
			request.Headers.Add("X-Goog-Upload-File-Name", Path.GetFileName(fileName));
			request.ContentType = "application/octet-stream";
			request.ContentLength = byteArr.Length;
			request.Credentials = CredentialCache.DefaultCredentials;

			Stream dataStream = request.GetRequestStream();
			dataStream.Write(byteArr, 0, byteArr.Length);
			dataStream.Close();

			WebResponse response = request.GetResponse();
			using (dataStream = response.GetResponseStream())
			{
				StreamReader reader = new StreamReader(dataStream);
				string uploadToken = reader.ReadToEnd();
				fileUploads.Add(Path.GetFileName(fileName), uploadToken);
			}

			response.Close();
		});

		tasks.Add(task);
		task.Start();
	}

	Task.WaitAll(tasks.ToArray());

	//Prepare to create media items
	jsonData = "{";
	jsonData += "\"newMediaItems\": [";
	foreach (var fileUpload in fileUploads)
	{
		jsonData += "{";
		jsonData += "\"description\": \"" + Path.GetFileName(fileUpload.Key) + "\"" + ",";
		jsonData += "\"simpleMediaItem\": {";
		jsonData += "\"fileName\": \"" + Path.GetFileName(fileUpload.Key) + "\"" + ",";
		jsonData += "\"uploadToken\": \"" + fileUpload.Value + "\"";
		jsonData += "}";
		jsonData += "},";
	}
	jsonData += "]";
	jsonData += "}";
	jsonData = jsonData.Remove(jsonData.Length - 3, 1);

	var requestUpload = WebRequest.Create("https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate");
	requestUpload.ContentType = "application/json";
	requestUpload.Method = "POST";
	requestUpload.Credentials = CredentialCache.DefaultCredentials;
	requestUpload.Headers.Add("Authorization:" + credential.Token.TokenType + " " + credential.Token.AccessToken);

	using (var streamWriter = new StreamWriter(requestUpload.GetRequestStream()))
	{
		streamWriter.Write(jsonData.ToString());
	}

	try
	{
		var httpResponse = (HttpWebResponse)requestUpload.GetResponse();
		using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
		{
			var result = streamReader.ReadToEnd();
		}
	}
	catch (WebException ex)
	{
		using (WebResponse responseError = ex.Response)
		{
			var httpResponse = (HttpWebResponse)responseError;

			using (Stream data = responseError.GetResponseStream())
			{
				StreamReader sr = new StreamReader(data);
				Console.WriteLine(sr.ReadToEnd());
			}
		}
	}
}
Once everything is setup correctly and the codes have no errors during debug mode, it will open an Internet Explorer or Microsoft Edge browser asking you to sign in to Google Photos using your account and authorize your app to be able to upload the media items. It will then download a verification code to your app.
Upload Photos Or Files To Google Photos Using Google Photos API, REST And C#.NET
Upload Photos Or Files To Google Photos Using Google Photos API, REST And C#.NET
To verify if the uploading of media items or if the files were successfully uploaded, go to Google Photos and sign-in using your gmail account. You should be able to see your files saved to photos cloud. Here's the complete source code of the console app.
using Google.Apis.Auth.OAuth2;
using Google.Apis.Util.Store;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;

namespace GooglePhotosUpload
{
    class Program
    {
        static void Main(string[] args)
        {
            string UserName = "your_gmail_account@gmail.com";
            string credPath = @"D:\Codes\GooglePhotosUpload\";
            string filesRepository = @"D:\FilesToUploadFolder";
            string[] files = Directory.GetFiles(filesRepository);

            UserCredential credential;
            string[] scopes = {
                "https://www.googleapis.com/auth/photoslibrary.appendonly"
             };

            
            using (var stream = new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
            {
                credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.Load(stream).Secrets,
                    scopes,
                    UserName,
                    CancellationToken.None,
                    new FileDataStore(credPath, true)).Result;
            }

            try
            {          
                if (files.Length > 0)
                {
                    UploadFileWebRequest(filesRepository, credential, files);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error occured: " + ex.Message);
            }

            Console.WriteLine("Files Uploaded Successfully!!!");
            Console.ReadLine();
        }

        private static void UploadFileWebRequest(string filesRepository, UserCredential credential, string[] fileNames)
        {
            string jsonData = string.Empty;
            List<Task> tasks = new List<Task>();
            Dictionary<string, string> fileUploads = new Dictionary<string, string>();

            //Get upload-token 
            foreach (var fileName in fileNames)
            {
                var task = new Task(() =>
                {
                    byte[] byteArr = File.ReadAllBytes(Path.Combine(filesRepository, Path.GetFileName(fileName)));

                    var request = WebRequest.Create("https://photoslibrary.googleapis.com/v1/uploads");
                    request.Method = "POST";
                    request.Headers.Add("Authorization:" + credential.Token.TokenType + " " + credential.Token.AccessToken);
                    request.Headers.Add("X-Goog-Upload-Content-Type", "raw");
                    request.Headers.Add("X-Goog-Upload-Content-Type", "image/jpeg");
                    request.Headers.Add("X-Goog-Upload-File-Name", Path.GetFileName(fileName));
                    request.ContentType = "application/octet-stream";
                    request.ContentLength = byteArr.Length;
                    request.Credentials = CredentialCache.DefaultCredentials;

                    Stream dataStream = request.GetRequestStream();
                    dataStream.Write(byteArr, 0, byteArr.Length);
                    dataStream.Close();

                    WebResponse response = request.GetResponse();
                    using (dataStream = response.GetResponseStream())
                    {
                        StreamReader reader = new StreamReader(dataStream);
                        string uploadToken = reader.ReadToEnd();
                        fileUploads.Add(Path.GetFileName(fileName), uploadToken);
                    }

                    response.Close();
                });

                tasks.Add(task);
                task.Start();
            }

            Task.WaitAll(tasks.ToArray());

            //Prepare to create media items
            jsonData = "{";
            jsonData += "\"newMediaItems\": [";
            foreach (var fileUpload in fileUploads)
            {
                jsonData += "{";
                jsonData += "\"description\": \"" + Path.GetFileName(fileUpload.Key) + "\"" + ",";
                jsonData += "\"simpleMediaItem\": {";
                jsonData += "\"fileName\": \"" + Path.GetFileName(fileUpload.Key) + "\"" + ",";
                jsonData += "\"uploadToken\": \"" + fileUpload.Value + "\"";
                jsonData += "}";
                jsonData += "},";
            }
            jsonData += "]";
            jsonData += "}";
            jsonData = jsonData.Remove(jsonData.Length - 3, 1);

            var requestUpload = WebRequest.Create("https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate");
            requestUpload.ContentType = "application/json";
            requestUpload.Method = "POST";
            requestUpload.Credentials = CredentialCache.DefaultCredentials;
            requestUpload.Headers.Add("Authorization:" + credential.Token.TokenType + " " + credential.Token.AccessToken);

            using (var streamWriter = new StreamWriter(requestUpload.GetRequestStream()))
            {
                streamWriter.Write(jsonData.ToString());
            }

            try
            {
                var httpResponse = (HttpWebResponse)requestUpload.GetResponse();
                using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
                {
                    var result = streamReader.ReadToEnd();
                }
            }
            catch (WebException ex)
            {
                using (WebResponse responseError = ex.Response)
                {
                    var httpResponse = (HttpWebResponse)responseError;

                    using (Stream data = responseError.GetResponseStream())
                    {
                        StreamReader sr = new StreamReader(data);
                        Console.WriteLine(sr.ReadToEnd());
                    }
                }
            }
        }
    }
}

Comments

Donate

Popular Posts From This Blog

WPF CRUD Application Using DataGrid, MVVM Pattern, Entity Framework, And C#.NET

TypeScript Error Or Bug: The term 'tsc' is not recognized as the name of a cmdlet, function, script file, or operable program.

Invalid nested tag div found, expected closing tag input