#region License Information (GPL v3)
/*
ShareX - A program that allows you to take screenshots and share any file type
Copyright (c) 2007-2021 ShareX Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Optionally you can also view the license at .
*/
#endregion License Information (GPL v3)
using Newtonsoft.Json;
using ShareX.UploadersLib.Properties;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
namespace ShareX.UploadersLib.ImageUploaders
{
public class GooglePhotosImageUploaderService : ImageUploaderService
{
public override ImageDestination EnumValue { get; } = ImageDestination.Picasa;
public override Image ServiceImage => Resources.GooglePhotos;
public override bool CheckConfig(UploadersConfig config)
{
return OAuth2Info.CheckOAuth(config.GooglePhotosOAuth2Info);
}
public override GenericUploader CreateUploader(UploadersConfig config, TaskReferenceHelper taskInfo)
{
return new GooglePhotos(config.GooglePhotosOAuth2Info)
{
AlbumID = config.GooglePhotosAlbumID,
IsPublic = config.GooglePhotosIsPublic
};
}
public override TabPage GetUploadersConfigTabPage(UploadersConfigForm form) => form.tpGooglePhotos;
}
public sealed class GooglePhotos : ImageUploader, IOAuth2
{
private GoogleOAuth2 GoogleAuth { get; set; }
public string AlbumID { get; set; }
public bool IsPublic { get; set; }
public GooglePhotos(OAuth2Info oauth)
{
GoogleAuth = new GoogleOAuth2(oauth, this)
{
Scope = "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/photoslibrary https://www.googleapis.com/auth/photoslibrary.sharing"
};
}
public OAuth2Info AuthInfo => GoogleAuth.AuthInfo;
public bool RefreshAccessToken()
{
return GoogleAuth.RefreshAccessToken();
}
public bool CheckAuthorization()
{
return GoogleAuth.CheckAuthorization();
}
public string GetAuthorizationURL()
{
return GoogleAuth.GetAuthorizationURL();
}
public bool GetAccessToken(string code)
{
return GoogleAuth.GetAccessToken(code);
}
public OAuthUserInfo GetUserInfo()
{
return GoogleAuth.GetUserInfo();
}
public GooglePhotosAlbum CreateAlbum(string albumName)
{
GooglePhotosNewAlbum newItemAlbum = new GooglePhotosNewAlbum
{
album = new GooglePhotosAlbum
{
title = albumName
}
};
Dictionary newItemAlbumArgs = new Dictionary
{
{ "fields", "id" }
};
string serializedNewItemAlbum = JsonConvert.SerializeObject(newItemAlbum);
string serializedNewItemAlbumResponse = SendRequest(HttpMethod.POST, "https://photoslibrary.googleapis.com/v1/albums", serializedNewItemAlbum, RequestHelpers.ContentTypeJSON, newItemAlbumArgs, GoogleAuth.GetAuthHeaders());
GooglePhotosAlbum newItemAlbumResponse = JsonConvert.DeserializeObject(serializedNewItemAlbumResponse);
return newItemAlbumResponse;
}
public List GetAlbumList()
{
if (!CheckAuthorization()) return null;
List albumList = new List();
Dictionary albumListArgs = new Dictionary
{
{ "excludeNonAppCreatedData", "true" },
{ "fields", "albums(id,title,shareInfo),nextPageToken" }
};
string pageToken = "";
do
{
albumListArgs["pageToken"] = pageToken;
string response = SendRequest(HttpMethod.GET, "https://photoslibrary.googleapis.com/v1/albums", albumListArgs, GoogleAuth.GetAuthHeaders());
pageToken = "";
if (!string.IsNullOrEmpty(response))
{
GooglePhotosAlbums albumsResponse = JsonConvert.DeserializeObject(response);
if (albumsResponse.albums != null)
{
foreach (GooglePhotosAlbum album in albumsResponse.albums)
{
GooglePhotosAlbumInfo AlbumInfo = new GooglePhotosAlbumInfo
{
ID = album.id,
Name = album.title
};
if (album.shareInfo == null)
{
albumList.Add(AlbumInfo);
}
}
}
pageToken = albumsResponse.nextPageToken;
}
}
while (!string.IsNullOrEmpty(pageToken));
return albumList;
}
public override UploadResult Upload(Stream stream, string fileName)
{
if (!CheckAuthorization()) return null;
UploadResult result = new UploadResult();
if (IsPublic)
{
AlbumID = CreateAlbum(fileName).id;
Dictionary albumOptionsResponseArgs = new Dictionary
{
{ "fields", "shareInfo/shareableUrl" }
};
GooglePhotosAlbumOptions albumOptions = new GooglePhotosAlbumOptions();
string serializedAlbumOptions = JsonConvert.SerializeObject(albumOptions);
string serializedAlbumOptionsResponse = SendRequest(HttpMethod.POST, $"https://photoslibrary.googleapis.com/v1/albums/{AlbumID}:share", serializedAlbumOptions, RequestHelpers.ContentTypeJSON, albumOptionsResponseArgs, GoogleAuth.GetAuthHeaders());
GooglePhotosAlbumOptionsResponse albumOptionsResponse = JsonConvert.DeserializeObject(serializedAlbumOptionsResponse);
result.URL = albumOptionsResponse.shareInfo.shareableUrl;
}
NameValueCollection uploadTokenHeaders = new NameValueCollection
{
{ "X-Goog-Upload-File-Name", fileName },
{ "X-Goog-Upload-Protocol", "raw" },
{ "Authorization", GoogleAuth.GetAuthHeaders()["Authorization"] }
};
string uploadToken = SendRequest(HttpMethod.POST, "https://photoslibrary.googleapis.com/v1/uploads", stream, RequestHelpers.ContentTypeOctetStream, null, uploadTokenHeaders);
GooglePhotosNewMediaItemRequest newMediaItemRequest = new GooglePhotosNewMediaItemRequest
{
albumId = AlbumID,
newMediaItems = new GooglePhotosNewMediaItem[]
{
new GooglePhotosNewMediaItem
{
simpleMediaItem = new GooglePhotosSimpleMediaItem
{
uploadToken = uploadToken
}
}
}
};
Dictionary newMediaItemRequestArgs = new Dictionary
{
{ "fields", "newMediaItemResults(mediaItem/productUrl)" }
};
string serializedNewMediaItemRequest = JsonConvert.SerializeObject(newMediaItemRequest);
result.Response = SendRequest(HttpMethod.POST, "https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate", serializedNewMediaItemRequest, RequestHelpers.ContentTypeJSON, newMediaItemRequestArgs, GoogleAuth.GetAuthHeaders());
GooglePhotosNewMediaItemResults newMediaItemResult = JsonConvert.DeserializeObject(result.Response);
if (!IsPublic)
{
result.URL = newMediaItemResult.newMediaItemResults[0].mediaItem.productUrl;
}
return result;
}
}
public class GooglePhotosAlbumInfo
{
public string ID { get; set; }
public string Name { get; set; }
public string Summary { get; set; }
}
public class GooglePhotosAlbums
{
public GooglePhotosAlbum[] albums { get; set; }
public string nextPageToken { get; set; }
}
public class GooglePhotosAlbum
{
public string id { get; set; }
public string title { get; set; }
public string productUrl { get; set; }
public string coverPhotoBaseUrl { get; set; }
public string coverPhotoMediaItemId { get; set; }
public string isWriteable { get; set; }
public GooglePhotosShareInfo shareInfo { get; set; }
public string mediaItemsCount { get; set; }
}
public class GooglePhotosNewMediaItemRequest
{
public string albumId { get; set; }
public GooglePhotosNewMediaItem[] newMediaItems { get; set; }
}
public class GooglePhotosNewMediaItem
{
public string description { get; set; }
public GooglePhotosSimpleMediaItem simpleMediaItem { get; set; }
}
public class GooglePhotosSimpleMediaItem
{
public string uploadToken { get; set; }
}
public class GooglePhotosNewMediaItemResults
{
public GooglePhotosNewMediaItemResult[] newMediaItemResults { get; set; }
}
public class GooglePhotosNewMediaItemResult
{
public string uploadToken { get; set; }
public GooglePhotosStatus status { get; set; }
public GooglePhotosMediaItem mediaItem { get; set; }
}
public class GooglePhotosStatus
{
public string message { get; set; }
public int code { get; set; }
}
public class GooglePhotosMediaItem
{
public string id { get; set; }
public string productUrl { get; set; }
public string description { get; set; }
public string baseUrl { get; set; }
public GooglePhotosMediaMetaData mediaMetadata { get; set; }
}
public class GooglePhotosMediaMetaData
{
public string width { get; set; }
public string height { get; set; }
public string creationTime { get; set; }
public GooglePhotosPhoto photo { get; set; }
}
public class GooglePhotosPhoto
{
}
public class GooglePhotosNewAlbum
{
public GooglePhotosAlbum album { get; set; }
}
public class GooglePhotosAlbumOptions
{
public GooglePhotosSharedAlbumOptions sharedAlbumOptions { get; set; }
}
public class GooglePhotosSharedAlbumOptions
{
public string isCollaborative { get; set; }
public string isCommentable { get; set; }
}
public class GooglePhotosAlbumOptionsResponse
{
public GooglePhotosShareInfo shareInfo { get; set; }
}
public class GooglePhotosShareInfo
{
public GooglePhotosSharedAlbumOptions sharedAlbumOptions { get; set; }
public string shareableUrl { get; set; }
public string shareToken { get; set; }
public string isJoined { get; set; }
}
}