Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,20 +78,22 @@
/**
* Upload content to the Google Photos servers' APIs - be it photos, video, etc.
*
* APIs offered aim to be agnostic to file types, and try to be the general wrapper for all upload
* needs for the Photos SDKs, is in contrast to the predecessors used in the DTP codebase like
* {@link PhotosLibraryClient} or {@link GooglePhotosInterface} which are each used and/or managed
* for a specific use-case and we hope to delete in favor of classes in this package.
* <p>APIs offered aim to be agnostic to file types, and try to be the general wrapper for all
* upload needs for the Photos SDKs, is in contrast to the predecessors used in the DTP codebase
* like {@link PhotosLibraryClient} or {@link GooglePhotosInterface} which are each used and/or
* managed for a specific use-case and we hope to delete in favor of classes in this package.
*
* WARNING: this should be constructed PER request so as to not conflate job IDs or auth data across
* processes. That is: do NOT cache an instance of this object across your requests, say by storing
* the instance as a member of your adapter's Importer or Exporter implementations.
* <p>WARNING: this should be constructed PER request so as to not conflate job IDs or auth data
* across processes. That is: do NOT cache an instance of this object across your requests, say by
* storing the instance as a member of your adapter's Importer or Exporter implementations.
*/
// TODO(aksingh737,jzacsh) finish refactoring Google{Photos,Video,Media}{Importer,Exporter} classes
// so they're not all drifting-forks of each other, and instead share code with the help of small
// interfaces. We can start by using some of the de-duplication that happened in
// org.datatransferproject.datatransfer.google.common.gphotos package
public class GPhotosUpload {
private final static String ALBUMLESS_IDENTIFIER = "%s_ALBUMLESS_ITEMS";

private UUID jobId;
private IdempotentImportExecutor executor;
private TokensAndUrlAuthData authData;
Expand All @@ -107,9 +109,7 @@ public class GPhotosUpload {
* storing the instance as a member of your adapter's Importer or Exporter implementations.
*/
public GPhotosUpload(
UUID jobId,
IdempotentImportExecutor executor,
TokensAndUrlAuthData authData) {
UUID jobId, IdempotentImportExecutor executor, TokensAndUrlAuthData authData) {
this.jobId = jobId;
this.executor = executor;
this.authData = authData;
Expand All @@ -118,28 +118,34 @@ public GPhotosUpload(
/**
* Imports all `items` by fanning out to `batchImporter` upload calls as specified by the.
*
* Returns the number of uploaded bytes, as summed across all `items` that were uploaded.
* <p>Returns the number of uploaded bytes, as summed across all `items` that were uploaded.
*/
// TODO(aksingh737,jzacsh) WARNING: delete the duplicated GooglePhotosImporter code by pulling
// this out of Media into a new GphotoMedia class that exposes these methods for _both_
// GoogleMediaImporter _and_ GooglePhotosImporter to use.
public <T extends DownloadableFile> long uploadItemsViaBatching(
Collection<T> items,
ItemBatchUploader<T> importer)
throws Exception {
Collection<T> items, ItemBatchUploader<T> importer) throws Exception {
long bytes = 0L;
if (items == null || items.size() <= 0) {
return bytes;
}
Map<String, List<T>> itemsByAlbumId =
items.stream()
.filter(item -> !executor.isKeyCached(item.getIdempotentId()))
.filter(
item -> !executor.isKeyCached(item.getIdempotentId()) && item.getFolderId() != null)
.collect(Collectors.groupingBy(DownloadableFile::getFolderId));
// Null album-id items get sent here into the empty string key
itemsByAlbumId.put(
format(ALBUMLESS_IDENTIFIER, jobId),
items.stream()
.filter(
item -> !executor.isKeyCached(item.getIdempotentId()) && item.getFolderId() == null)
.collect(Collectors.toList()));

for (Entry<String, List<T>> albumEntry : itemsByAlbumId.entrySet()) {
String originalAlbumId = albumEntry.getKey();
String googleAlbumId;
if (Strings.isNullOrEmpty(originalAlbumId)) {
if (Strings.isNullOrEmpty(originalAlbumId) || originalAlbumId.equals(format(ALBUMLESS_IDENTIFIER, jobId))) {
// This is ok, since NewMediaItemUpload will ignore all null values and it's possible to
// upload a NewMediaItem without a corresponding album id.
googleAlbumId = null;
Expand All @@ -150,8 +156,7 @@ public <T extends DownloadableFile> long uploadItemsViaBatching(
}

UnmodifiableIterator<List<T>> batches =
Iterators.partition(albumEntry.getValue().iterator(),
BATCH_UPLOAD_SIZE);
Iterators.partition(albumEntry.getValue().iterator(), BATCH_UPLOAD_SIZE);

while (batches.hasNext()) {
long batchBytes =
Expand Down Expand Up @@ -179,6 +184,7 @@ public long uploadToAlbum(
TokensAndUrlAuthData authData,
List<T> batch,
IdempotentImportExecutor executor,
String targetAlbumId) throws Exception;
String targetAlbumId)
throws Exception;
}
}