f2calv / cascap.apis.googlephotos Goto Github PK
View Code? Open in Web Editor NEW*unofficial* Google Photos REST API library for .NET projects.
License: MIT License
*unofficial* Google Photos REST API library for .NET projects.
License: MIT License
Hi
would it be possible to built an app with this library, that would calculate storage usage per Month and possibly per day for all the photos stored in the account?
something like 'du -sh *' in bash
ConsoleApp sample code works fine as a .NET Core 3.1 console app.
Same code in an UWP app crashes deep in LoginAsync, seems async-related trying to access a disposed Socket object.
I could post a project to reproduce but you already have the code, it's a pretty hard crash and burn.
Let me know if you have questions.
Lars
I want to add a huge amount of photos (let's say 1000) which will takes a long time. After a while I get Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential
error when calling any method on the library.
How do I find out when the OAuth access token is expiring?
P.S. My current workaround is to basically new up GooglePhotosService. Is there a better way?
Sometimes when uploading files with names that contain non-English characters fails.
For example, uploading of file a "D:\2003.02.06 - (Открытый) Урок английского.jpg" fails and the server returns an HTML page
<title>Error 400 (Bad Request)!!1</title>
which eventually results in Newtonsoft.Json.JsonReaderException
Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
The reason for this is the HTTP standard that doesn't support non-ISO-8859-1 characters directly in an HTTP header. Thus characters should be encoded to be passed in the header.
Suggested fix: use HttpUtility.UrlPathEncode in GooglePhotosServiceBase.UploadMediaAsync:
headers.Add((X_Goog_Upload_File_Name, HttpUtility.UrlPathEncode(Path.GetFileName(path))));
Could not convert string to double: 0.050s. Path 'mediaItems[0].mediaMetadata.photo.exposureTime', line 18, position 34. | Newtonsoft.Json.JsonReaderException: Could not convert string to double: 0.050s. Path 'mediaItems[0].mediaMetadata.photo.exposureTime', line 18, position 34.
at Newtonsoft.Json.JsonReader.ReadDoubleString(String s)
at Newtonsoft.Json.JsonTextReader.FinishReadQuotedNumber(ReadType readType)
at Newtonsoft.Json.JsonTextReader.ReadAsDouble()
at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value)
at CasCap.Common.Extensions.Helpers.FromJSON[T](String json)
at CasCap.Services.HttpClientBase.HandleResult[TResult,TError](HttpResponseMessage response)
at CasCap.Services.HttpClientBase.Get[TResult,TError](String requestUri, Nullable1 timeout, List
1 headers)
at CasCap.Services.GooglePhotosServiceBase._GetMediaItemsAsync(Int32 pageSize, Int32 maxPageCount, Boolean excludeNonAppCreatedData, String requestUri, CancellationToken cancellationToken)
Uploading files with sizes more than 2 GB fails in ResumableMultipart mode with JsonReaderException:
Error parsing Infinity value. Path '', line 1, position 2.
The reason is that variable offset in the method GooglePhotosServiceBase.UploadMediaAsync is Int32. As a result when loading files with sizes greater than Int32.MaxValue, offset overflows to a negative value passed to the HTTP header.
The solution would be to change the type of offset variable to Int64:
var offset = 0L;
Thanks a lot for your effort in creating a proper library for C#. Google API Documentation does not have any examples on consuming the their REST API in C#.
I'm trying to use your library in one of my Winforms project that targets .net Framework 4.5. Installing from nuget does not seem to work since there is some compatibility issues with .Net 5. I have tried manually adding the DLLs but still there are some reference issues. Is there an official way to make this work with .Net Framework 4.5 ?
Is it possible to know the owner of each media item, e.g. loaded by GetMediaItemsByAlbumAsync method, in Google Photos?
I mean, is there a property in some class?
I've found the property contributorInfo in class MediaItem, but, as written in summary, that field is only populated if the media item is in a shared album created by the app that use the library.
Do you confirm that is present only that property? Doesn't Google provide this useful information?
Otherwise, is it possible in method GetMediaItemsByAlbumAsync for a shared album to load only media items owned by the user used in the login?
I hope you can help me and thanks in advance.
I would like to be able to use the API to filter my media, but haven't figured out the appropriate filters. The two filters I'm looking for are:
Those are easy enough to do in the Google Photos app or web site, but I can't figure out how to do that via the API. Any/all help appreciated.
(Note: I've asked this question on Stack Overflow as well. I'm not 100% certain which is the better place for it.)
If you have not enabled the Photos Library API
permission on your google app, the request fails with a 403, but the library ignores the error and just returns zero results.
Sample result from Fiddler.
HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=UTF-8
Date: Mon, 27 Jul 2020 00:41:39 GMT
{
"error": {
"code": 403,
"message": "Photos Library API has not been used in project XXX before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/photoslibrary.googleapis.com/overview?project=XXX then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.",
"status": "PERMISSION_DENIED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.Help",
"links": [
{
"description": "Google developers console API activation",
"url": "https://console.developers.google.com/apis/api/photoslibrary.googleapis.com/overview?project=XXX"
}
]
}
]
}
}
Note: I only verified this behavior with GetAlbumsAsync(...)
.
"Live Photo" is an iPhone construct where the camera records 2 seconds of video and using some algorithm picks the best frame and that is what displays on phone's Photos app. When you long tap the photo, the entire 2 second video plays.
When Google Photos app backs up this "Live Photo", it shows up as a photo on the website, however, it has a "Turn on motion" button, that allows you to play the entire video, just like on the phone.
I have this "Live Photo" file on my desktop and Google Photos exports it as an mp4. However, when I upload the photo using _googlePhotosSvc.UploadMediaAsync
and _googlePhotosSvc.AddMediaItemAsync
combo, it just shows up as another video.
Is there a way to tell Google Photos that it's a "Live Photo"?
Hi, would be great to add optional parameter MaxPages to GetMediaItemsAsync. So get stops requesting after defined number of pages. The same could be reached by using the cancel token. But Cancel token would be for "surprising" user cancellation while max pages would be for deterministic stop.
Use case would be if you pull the whole MediaList you might get thousands of pages a) this can take very long and b) if you want to show them until pictures are downloaded download link has expired.
You are already tracking page numbers. So just add it to condition a la
var pageNumber = 1;
while (pageToken is object && !cancellationToken.IsCancellationRequested && maxPageNumber <= pageNumber)
Hello,
Thanks a lot for the .Net Wrapper :) .
I recently came across an issue when trying to upload photos to existing google albums(created from Google Photos web UI/elsewhere) . I keep getting the following error
No permission to add media items to this album
Even when the following permissions are granted in the Google security section
I'm using version 1.1.2 of CasCap.Apis.GooglePhotos
Please advice
Hi, would be great to add Cancellation support to (the long running) methods like _GetMediaItemsAsync. Could
see
https://johnthiriet.com/cancel-asynchronous-operation-in-csharp/
Because if you accidentally tried to download the whole media library ... you might want to be able to cancel :-)
@k0qed I'm looking for testers for this new Google Photos .NET Library, are you interested?
I am trying to do the following:
So I do the following:
// boilerplate to connect to google api
List<MediaItem> mediaItems = await googlePhotosSvc.GetMediaItemsAsync();
Album album= await googlePhotosSvc.CreateAlbumAsync(albumName);
foreach (var item in mediaItems) {
bool success = await googlePhotosSvc.AddMediaItemsToAlbumAsync(album.id, new string[] { item.id });
}
It blows up on googlePhotosSvc.AddMediaItemsToAlbumAsync
with Request contains an invalid media item id
.
I've played around with adding scopes and at this point I have GooglePhotosScope.AppendOnly, GooglePhotosScope.ReadOnly, GooglePhotosScope.AppCreatedData, GooglePhotosScope.Sharing
. But I am not sure what exactly is the problem. I've also tried adding photos in batches, but I get the same error.
The API call looks like this in Fiddler:
POST /v1/albums/ALvc__nJoKD2Rfh9rav5sQ7U9lm5ClQ3F_tVQ-mBANpi0pjGMfs5wn8eJ1gD2ibjQNbLsD3SHeI3:batchAddMediaItems HTTP/1.1
with the body of:
{"mediaItemIds":["ALvc__kuVUBPmBfk8AkGiXLrvxLj1tOdkGaoMtp0AmPqEbcP-hI13wILoiFpCzUXc9xe6zk2eMnsTGry-3SaS4znQZa_qFQwxQ"]}
And it returns
{
"error": {
"code": 400,
"message": "Request contains an invalid media item id.",
"status": "INVALID_ARGUMENT"
}
}
What am I missing?
It would be nice if the DownloadBytes would preserve the exif data, it currently does not, This can be accomplished by adding the "ip" parameter to the url you are creating to download the media item. (Found the info here https://gist.github.com/Sauerstoffdioxid/2a0206da9f44dde1fdfce290f38d2703)
Hello,
Thanks for the excellent .net library.
Try to upload the RW2 file which is supported by google photo but get System.NotSupportedException.
System.NotSupportedException: 'Cannot match file extension '.RW2' from 'd:/temp/GooglePhotos/P1000195.RW2' to a known image or video mime type.'
The AcceptedMimeTypesImage needs to include a more supported format.
static readonly HashSet<string> AcceptedMimeTypesImage = new(StringComparer.OrdinalIgnoreCase)
{
{ "image/bmp" },
{ "image/gif" },
{ "image/heic" },
{ "image/vnd.microsoft.icon" },
{ "image/jpeg" },
{ "image/jpeg" },
{ "image/png" },
{ "image/tiff" },
{ "image/webp" },
};
I have a big library with 10k+ items. When I run _googlePhotosSvc.GetMediaItemsByAlbumAsync(album.id, 25); It take long time...hangs. What am I doing wrong since paging is not working for me. Could you please help? Also, is there a easy way to get filenames? Thanks.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.