use of com.google.photos.library.v1.PhotosLibraryClient in project data-transfer-project by google.
the class GoogleVideosImporterTest method importTwoVideos.
@Test
public void importTwoVideos() throws Exception {
PhotosLibraryClient photosLibraryClient = mock(PhotosLibraryClient.class);
// Mock uploads
when(photosLibraryClient.uploadMediaItem(any())).thenReturn(UploadMediaItemResponse.newBuilder().setUploadToken("token1").build(), UploadMediaItemResponse.newBuilder().setUploadToken("token2").build());
// Mock creation response
final NewMediaItemResult newMediaItemResult = NewMediaItemResult.newBuilder().setStatus(Status.newBuilder().setCode(Code.OK_VALUE).build()).setMediaItem(MediaItem.newBuilder().setId("RESULT_ID_1").build()).setUploadToken("token1").build();
final NewMediaItemResult newMediaItemResult2 = NewMediaItemResult.newBuilder().setStatus(Status.newBuilder().setCode(Code.OK_VALUE).build()).setMediaItem(MediaItem.newBuilder().setId("RESULT_ID_2").build()).setUploadToken("token2").build();
BatchCreateMediaItemsResponse response = BatchCreateMediaItemsResponse.newBuilder().addNewMediaItemResults(newMediaItemResult).addNewMediaItemResults(newMediaItemResult2).build();
when(photosLibraryClient.batchCreateMediaItems(ArgumentMatchers.anyList())).thenReturn(response);
InMemoryIdempotentImportExecutor executor = new InMemoryIdempotentImportExecutor(mock(Monitor.class));
long length = googleVideosImporter.importVideoBatch(Lists.newArrayList(new VideoModel(VIDEO_TITLE, VIDEO_URI, VIDEO_DESCRIPTION, MP4_MEDIA_TYPE, VIDEO_ID, null, false), new VideoModel(VIDEO_TITLE, VIDEO_URI, VIDEO_DESCRIPTION, MP4_MEDIA_TYPE, "myId2", null, false)), photosLibraryClient, executor);
assertEquals("Expected the number of bytes to be the two files of 32L.", 64L, length);
assertEquals("Expected executor to have no errors.", 0, executor.getErrors().size());
}
use of com.google.photos.library.v1.PhotosLibraryClient in project data-transfer-project by google.
the class GoogleVideosImporterTest method skipNotFoundVideo.
@Test
public void skipNotFoundVideo() throws Exception {
PhotosLibraryClient photosLibraryClient = mock(PhotosLibraryClient.class);
HttpURLConnection httpURLConnection = mock(HttpURLConnection.class);
when(httpURLConnection.getInputStream()).thenThrow(new FileNotFoundException());
when(streamProvider.getConnection(any())).thenReturn(httpURLConnection);
InMemoryIdempotentImportExecutor executor = new InMemoryIdempotentImportExecutor(mock(Monitor.class));
long length = googleVideosImporter.importVideoBatch(Lists.newArrayList(new VideoModel(VIDEO_TITLE, VIDEO_URI, VIDEO_DESCRIPTION, MP4_MEDIA_TYPE, VIDEO_ID, null, false)), photosLibraryClient, executor);
assertEquals("Expected the number of bytes to be 0L.", 0L, length);
assertEquals("Expected executor to have no errors.", 0, executor.getErrors().size());
}
use of com.google.photos.library.v1.PhotosLibraryClient in project data-transfer-project by google.
the class GoogleVideosImporter method importItem.
@Override
public ImportResult importItem(UUID jobId, IdempotentImportExecutor executor, TokensAndUrlAuthData authData, VideosContainerResource data) throws Exception {
if (data == null) {
// Nothing to do
return ImportResult.OK;
}
PhotosLibraryClient client;
if (clientsMap.containsKey(jobId)) {
client = clientsMap.get(jobId);
} else {
PhotosLibrarySettings settings = PhotosLibrarySettings.newBuilder().setCredentialsProvider(FixedCredentialsProvider.create(UserCredentials.newBuilder().setClientId(appCredentials.getKey()).setClientSecret(appCredentials.getSecret()).setAccessToken(new AccessToken(authData.getAccessToken(), new Date())).setRefreshToken(authData.getRefreshToken()).build())).build();
client = PhotosLibraryClient.initialize(settings);
clientsMap.put(jobId, client);
}
long bytes = 0L;
// Uploads videos
final Collection<VideoModel> videos = data.getVideos();
if (videos != null && videos.size() > 0) {
Stream<VideoModel> stream = videos.stream().filter(video -> shouldImport(video, executor)).map(this::transformVideoName);
// We partition into groups of 49 as 50 is the maximum number of items that can be created in
// one call. (We use 49 to avoid potential off by one errors)
// https://developers.google.com/photos/library/guides/upload-media#creating-media-item
final UnmodifiableIterator<List<VideoModel>> batches = Iterators.partition(stream.iterator(), 49);
while (batches.hasNext()) {
long batchBytes = importVideoBatch(batches.next(), client, executor);
bytes += batchBytes;
}
}
final ImportResult result = ImportResult.OK;
return result.copyWithBytes(bytes);
}
use of com.google.photos.library.v1.PhotosLibraryClient in project data-transfer-project by google.
the class GoogleVideosImporter method uploadMediaItem.
private Pair<String, Long> uploadMediaItem(MediaObject inputVideo, PhotosLibraryClient photosLibraryClient) throws IOException, UploadErrorException {
final File tmp;
try (InputStream inputStream = this.videoStreamProvider.getConnection(inputVideo.getContentUrl().toString()).getInputStream()) {
tmp = dataStore.getTempFileFromInputStream(inputStream, inputVideo.getName(), ".mp4");
}
try {
UploadMediaItemRequest uploadRequest = UploadMediaItemRequest.newBuilder().setFileName(inputVideo.getName()).setDataFile(new RandomAccessFile(tmp, "r")).build();
UploadMediaItemResponse uploadResponse = photosLibraryClient.uploadMediaItem(uploadRequest);
String uploadToken;
if (uploadResponse.getError().isPresent() || !uploadResponse.getUploadToken().isPresent()) {
Error error = uploadResponse.getError().orElse(null);
if (error != null && error.getCause().getMessage().contains("The upload url is either finalized or rejected by the server")) {
throw new UploadErrorException("Upload was terminated because of error", error.getCause());
}
throw new IOException("An error was encountered while uploading the video.", error != null ? error.getCause() : null);
} else {
uploadToken = uploadResponse.getUploadToken().get();
}
return Pair.of(uploadToken, tmp.length());
} finally {
// noinspection ResultOfMethodCallIgnored
tmp.delete();
}
}
use of com.google.photos.library.v1.PhotosLibraryClient in project data-transfer-project by google.
the class GoogleVideosImporter method importVideoBatch.
long importVideoBatch(List<VideoModel> batchedVideos, PhotosLibraryClient client, IdempotentImportExecutor executor) throws Exception {
final ArrayList<NewMediaItem> mediaItems = new ArrayList<>();
final HashMap<String, VideoModel> uploadTokenToDataId = new HashMap<>();
final HashMap<String, Long> uploadTokenToLength = new HashMap<>();
// calls of the client to handle the InvalidArgumentException when the user's storage is full.
try {
for (VideoModel video : batchedVideos) {
try {
Pair<String, Long> pair = uploadMediaItem(video, client);
final String uploadToken = pair.getLeft();
mediaItems.add(buildMediaItem(video, uploadToken));
uploadTokenToDataId.put(uploadToken, video);
uploadTokenToLength.put(uploadToken, pair.getRight());
} catch (IOException e) {
if (e instanceof FileNotFoundException) {
// If the video file is no longer available then skip the video. We see this in a small
// number of videos where the video has been deleted.
monitor.info(() -> String.format("Video resource was missing for id: %s", video.getDataId()), e);
continue;
}
executor.executeAndSwallowIOExceptions(video.getDataId(), video.getName(), () -> {
throw e;
});
}
}
if (mediaItems.isEmpty()) {
// Either we were not passed in any videos or we failed upload on all of them.
return 0L;
}
BatchCreateMediaItemsResponse response = client.batchCreateMediaItems(mediaItems);
final List<NewMediaItemResult> resultsList = response.getNewMediaItemResultsList();
long bytes = 0L;
for (NewMediaItemResult result : resultsList) {
String uploadToken = result.getUploadToken();
Status status = result.getStatus();
final VideoModel video = uploadTokenToDataId.get(uploadToken);
Preconditions.checkNotNull(video);
final int code = status.getCode();
if (code == Code.OK_VALUE) {
executor.executeAndSwallowIOExceptions(video.getDataId(), video.getName(), () -> result.getMediaItem().getId());
Long length = uploadTokenToLength.get(uploadToken);
if (length != null) {
bytes += length;
}
} else {
executor.executeAndSwallowIOExceptions(video.getDataId(), video.getName(), () -> {
throw new IOException(String.format("Video item could not be created. Code: %d Message: %s", code, result.getStatus().getMessage()));
});
}
uploadTokenToDataId.remove(uploadToken);
}
if (!uploadTokenToDataId.isEmpty()) {
for (VideoModel video : uploadTokenToDataId.values()) {
executor.executeAndSwallowIOExceptions(video.getDataId(), video.getName(), () -> {
throw new IOException("Video item was missing from results list.");
});
}
}
return bytes;
} catch (InvalidArgumentException e) {
if (e.getMessage().contains("The remaining storage in the user's account is not enough")) {
throw new DestinationMemoryFullException("Google destination storage full", e);
} else {
throw e;
}
}
}
Aggregations