[Google Photos Library API] JavaでGoogleフォトのメディアアイテム(写真や動画)を追加・更新する

Google Photos Library API(Java)を使用して、
Googleフォトのメディアアイテム(写真や動画)を追加・更新する方法
についてご紹介します。

メディアアイテムを追加できるアルバムはPhotos Library APIで作成したアルバムのみになります。
アルバムの作成方法は
[⧉[Google Photos Library API] JavaでGoogleフォトのアルバムを作成・更新する](https://qiita.com/doran/items/b5ecc7005f19fbf0a35a)
を参照ください。

:::note info
APIを利用する環境の準備から始める場合や、コードを実行する際は、
[⧉[Google Photos Library API(V1)] JavaでPhotos Library APIを使う](https://qiita.com/doran/items/8695e6007765ab5b382c)
を参照ください。
:::

|No|||目次|
|---|---|---|---|
|1|||[メディアアイテムを追加](#1-メディアアイテムを追加)|
||1||[ファイルをアップロード](#11-ファイルをアップロード)|
|||1|[スコープ](#111-スコープ)|
|||2|[アップロードできるファイル](#112-アップロードできるファイル)|
|||3|[実行](#113-実行)|
|||4|[レスポンスの内容](#114-レスポンスの内容)|
||2||[メディアアイテムを作成](#12-メディアアイテムを作成)|
|||1|[スコープ](#121-スコープ)|
|||2|[実行](#122-実行)|
|||3|[レスポンスの内容](#123-レスポンスの内容)|
|2|||[メディアアイテムを更新](#2-メディアアイテムを更新)|
||1||[スコープ](#21-スコープ)|
||2||[実行](#22-実行)|
|||1|[HTTPリクエスト](#221-httpリクエスト)|
|||2|[クエリパラメータ](#222-クエリパラメータ)|
|||3|[レスポンスの内容](#23-レスポンスの内容)|

## 1. メディアアイテムを追加
メディアアイテム(写真や動画)を追加します。

メディアアイテムを追加するには下記の手順が必要です。
1.[メディアファイルのバイトをGoogleサーバーにアップロード](#11-ファイルをアップロード)
2.[Googleフォトにメディアアイテムを作成](#12-メディアアイテムを作成)

### 1.1. ファイルをアップロード
Googleサーバーにファイルをアップロードします。

アップロード後のメディアアイテム作成には
[1.1.3. レスポンスの内容(UploadMediaItemResponse)](#uploadmediaitemresponse)
で取得できるuploadTokenが必要になります。

### 1.1.1. スコープ
このAPIを実行するには、以下のいずれかのスコープを指定してください。
```
https://www.googleapis.com/auth/photoslibrary
https://www.googleapis.com/auth/photoslibrary.appendonly
```
[⧉[Google Photos Library API(V1)] JavaでPhotos Library APIを使う(2.2. PhotosLibraryClientインスタンスを取得)](https://qiita.com/doran/items/8695e6007765ab5b382c#22-photoslibraryclientインスタンスを取得)
でスコープを指定してください。

### 1.1.2. アップロードできるファイル
APIでアップロードできるファイルの種類とアップロード可能な最大サイズは下記です。
|メディアタイプ|ファイルの種類|最大ファイルサイズ|
|---|---|---|
|写真|AVIF、BMP、GIF、HEIC、ICO、JPG、PNG、TIFF、WEBP、一部の RAW ファイル|200MB|
|動画|3GP、3G2、ASF、AVI、DIVX、M2T、M2TS、M4V、MKV、MMV、MOD、MOV、MP4、MPG、MTS、TOD、WMV|20GB|

### 1.1.3. 実行

```java
public static void main(String[] args) throws Exception{
    try(PhotosLibraryClient client = getPhotosLibraryClient();
        RandomAccessFile file = new RandomAccessFile("ファイルパス", "r")){
        UploadMediaItemRequest.Builder build = UploadMediaItemRequest.newBuilder();
        build.setMimeType("Mimeタイプ");
        build.setDataFile(file);
        
        UploadMediaItemResponse response = client.uploadMediaItem(build.build());
        if (!response.getError().isPresent()) {
            System.out.println(response.getUploadToken().get());
        }
    }
}
```
#### 1.1.3.1. リクエストボディ
UploadMediaItemRequest.Builderのsetメソッドにより、
リクエストボディを追加できます。

build()メソッドでUploadMediaItemRequestインスタンスを取得し、
uploadMediaItem()に渡します。

|メソッド|引数|説明|
|---|---|---|
|setMimeType|String|アップロードするファイルのMimeタイプ|
|setDataFile|RandomAccessFile|アップロードするファイル|

### 1.1.4. レスポンスの内容
#### UploadMediaItemResponse
|メソッド|戻り値|説明|
|---|---|---|
|getError|Optional\<[UploadMediaItemResponse.Error](#uploadmediaitemresponseerror)\>|失敗時のエラー情報|
|getUploadToken|String|アップロードトークン|

#### UploadMediaItemResponse.Error
|メソッド|戻り値|説明|
|---|---|---|
|getCause|java.lang.Throwable|エラーの原因|
|getResumeUrl|Optional\<String\>|アップロードを再試行するためのURL|

### 1.2. メディアアイテムを作成
アップロードしたファイルのメディアアイテムを作成します。

メディアアイテムを作成する際にアルバムIDの指定が必須になりますが、
指定可能奈アルバムはPhotos Library APIで作成したアルバムのみになります。
アルバムの作成方法は
[⧉[Google Photos Library API] JavaでGoogleフォトのアルバムを作成・更新する](https://qiita.com/doran/items/b5ecc7005f19fbf0a35a)
を参照ください。

メディアアイテムは1度のAPI実行で複数作成することができます。
複数のファイルを追加したい場合は、[1.1. ファイルをアップロード](#11-ファイルをアップロード)をファイル数分実行し、
その後に[1.2. メディアアイテムを作成](#12-メディアアイテムを作成)を実行します。

### 1.2.1. スコープ
このAPIを実行するには、以下のいずれかのスコープを指定してください。
```
https://www.googleapis.com/auth/photoslibrary
https://www.googleapis.com/auth/photoslibrary.appendonly
https://www.googleapis.com/auth/photoslibrary.sharing
```
[⧉[Google Photos Library API(V1)] JavaでPhotos Library APIを使う(2.2. PhotosLibraryClientインスタンスを取得)](https://qiita.com/doran/items/8695e6007765ab5b382c#22-photoslibraryclientインスタンスを取得)
でスコープを指定してください。

### 1.2.2. 実行

```java
public static void main(String[] args) throws Exception{
    try(PhotosLibraryClient client = getPhotosLibraryClient()){
        SimpleMediaItem.Builder builder_item = SimpleMediaItem.newBuilder();
        builder_item.setUploadToken("アップロードトークン");
        builder_item.setFileName("ファイル名");
    
        NewMediaItem.Builder builder_media = NewMediaItem.newBuilder();
        builder_media.setDescription("説明");
        builder_media.setSimpleMediaItem(builder_item.build());
        
        AlbumPosition.Builder builder_position = AlbumPosition.newBuilder();
        
        BatchCreateMediaItemsResponse response = client.batchCreateMediaItems(
            "アルバムID",
            Arrays.asList(builder_media.build()),
            builder_position.build());
        for(NewMediaItemResult result : response.getNewMediaItemResultsList()) {
            System.out.println(result.getUploadToken());
            System.out.println(result.getStatus());
            System.out.println(result.getMediaItem());
        }
    }
}
```
#### 1.2.2.1. HTTPリクエスト
POST:　https:\//photoslibrary.googleapis.com/v1/mediaItems:batchCreate
が実行されます。

#### 1.2.2.2. リクエストボディ
NewMediaItem.Builderのsetメソッドにより、リクエストボディを追加できます。

build()メソッドでNewMediaItemインスタンスを取得し、
batchCreateMediaItems()にListで渡します。最大50個まで設定できます。

|メソッド|引数|説明|
|---|---|---|
|setDescription|String|メディアアイテムの説明|
|setSimpleMediaItem|[SimpleMediaItem](#simplemediaitem)|メディアアイテム|

#### SimpleMediaItem
|メソッド|引数|説明|
|---|---|---|
|setUploadToken|String|アップロードトークン|
|setFileName|String|メディアアイテムの拡張子を持つファイル名|

AlbumPosition.Builderのsetメソッドにより、リクエストボディを追加できます。
メディアアイテムが追加されるアルバム内の位置を指定できます。

build()メソッドでAlbumPositionインスタンスを取得し、
batchCreateMediaItems()に渡します。

|メソッド|引数|説明|
|---|---|---|
|setPosition|[PositionType(enum)](#positiontype)|メディアアイテムまたはエンリッチメントアイテムの位置のタイプ|
|setRelativeMediaItemId|String|位置の基準となるメディアアイテム<br>setPosition("AFTER_MEDIA_ITEM")の場合のみ適用|
|setRelativeEnrichmentItemId|String|位置が相対的に表されているエンリッチメントアイテム<br>setPosition("AFTER_ENRICHMENT_ITEM")の場合のみ適用|

#### PositionType
|定義値|内容|
|---|---|
|POSITION_TYPE_UNSPECIFIED|未設定|
|FIRST_IN_ALBUM|アルバムの先頭|
|LAST_IN_ALBUM|アルバムの最後|
|AFTER_MEDIA_ITEM|メディアアイテムの後|
|AFTER_ENRICHMENT_ITEM|エンリッチメントアイテムの後|

### 1.2.3. レスポンスの内容
#### BatchCreateMediaItemsResponse
|メソッド|戻り値|説明|
|---|---|---|
|getNewMediaItemResultsList|List\<[NewMediaItemResult](#newmediaitemresult)\>|作成されたメディア アイテムのリスト|

#### NewMediaItemResult
|メソッド|戻り値|説明|
|---|---|---|
|getUploadToken|String|アップロードトークン|
|getStatus|[Status](#status)|エラー発生時のエラー情報|
|getMediaItem|[MediaItem](#mediaitem)|作成されたメディアアイテム|

#### MediaItem
|メソッド|戻り値|説明|
|---|---|---|
|getId|String|メディアアイテムID|
|getDescription|String|メディアアイテムの説明|
|getProductUrl|String|メディアアイテムの GoogleフォトURL|
|getBaseUrl|String|メディアアイテムのバイトへのURL|
|getMimeType|String|メディアアイテムのMIMEタイプ|
|getMediaMetadata|[MediaMetadata](#mediametadata)|メディアアイテムに関連するメタデータ|
|getContributorInfo|[ContributorInfo](#contributorinfo)|メディアアイテムを追加したユーザーの情報|
|getFilename|String|メディアアイテムのファイル名|

#### MediaMetadata
|メソッド|戻り値|説明|
|---|---|---|
|getCreationTime|Timestamp|メディアアイテムが最初に作成された時刻|
|getWidth|Long|メディアアイテムの元の幅（ピクセル単位）|
|getHeight|Long|メディアアイテムの元の高さ（ピクセル単位）|
|getPhoto|[Photo](#photo)|写真のメディアタイプのメタデータ|
|getVideo|[Video](#video)|動画のメディアタイプのメタデータ|

#### Photo
|メソッド|戻り値|説明|
|---|---|---|
|getCameraMake|String|写真を撮影したカメラのブランド|
|getCameraModel|String|写真を撮影したカメラのモデル|
|getFocalLength|Float|写真を撮影したカメラのレンズの焦点距離|
|getApertureFNumber|Float|写真を撮影したカメラレンズの絞りのf値|
|getIsoEquivalent|Integer|写真を撮影したカメラのISO|
|getExposureTime|Duration|写真が撮影されたときのカメラの絞りの露出時間|

#### Video
|メソッド|戻り値|説明|
|---|---|---|
|getCameraMake|String|動画を撮影したカメラのブランド|
|getCameraModel|String|動画を撮影したカメラのモデル|
|getFps|Double|動画のフレームレート|
|getStatus|[VideoProcessingStatus(enum)](#videoprocessingstatus)|動画の処理ステータス|

#### ContributorInfo
|メソッド|戻り値|説明|
|---|---|---|
|getProfilePictureBaseUrl|String|投稿者のプロフィール写真のURL|
|getDisplayName|String|表示名|

#### VideoProcessingStatus
|定義値|内容|
|---|---|
|UNSPECIFIED|動画の処理ステータスが不明|
|PROCESSING|動画の処理中|
|READY|動画の処理が完了し、表示できるようになった|
|FAILED|エラーが発生したため、動画を処理できなかった|

#### Status
|メソッド|戻り値|説明|
|---|---|---|
|getCode|Integer|ステータス コード<br>[⧉ google.rpc.Codeの列挙値](https://cloud.google.com/apis/design/errors?hl=ja#handling_errors)|
|getMessage|String|デベロッパー向けのエラー メッセージ|
|getDetailsList|List\<com.google.protobuf.Any\>|エラーの詳細を保持するメッセージのリスト|

### 2. メディアアイテムを更新
指定したメディアアイテムを更新します。
更新可能なのは「description」のみです。

Photos Library APIで追加したメディアアイテムのみ更新できます。

### 2.1. スコープ
このAPIを実行するには、以下のスコープを指定してください。
```
https://www.googleapis.com/auth/photoslibrary.edit.appcreateddata
```
[⧉[Google Photos Library API(V1)] JavaでPhotos Library APIを使う(2.2. PhotosLibraryClientインスタンスを取得)](https://qiita.com/doran/items/8695e6007765ab5b382c#22-photoslibraryclientインスタンスを取得)
でスコープを指定してください。

### 2.2. 実行

```java
public static void main(String[] args) throws Exception{
    try(PhotosLibraryClient client = getPhotosLibraryClient()){
        MediaItem.Builder builder_media = MediaItem.newBuilder();
        builder_media.setId("メディアアイテムID");
        builder_media.setDescription("説明");
        
        FieldMask.Builder builder_field = FieldMask.newBuilder();
        builder_field.addPaths("description");
        
        MediaItem response = client.updateMediaItem(builder_media.build(), builder_field.build());
        System.out.println(response);
    }
}
```
#### 2.2.1. HTTPリクエスト
PATCH:　https:\//photoslibrary.googleapis.com/v1/mediaItems/{メディアアイテムID}
が実行されます。

#### 2.2.2. クエリパラメータ
MediaItem.Builderのsetメソッドにより、
クエリパラメータを追加できます。
build()メソッドでMediaItemインスタンスを取得し、
updateMediaItem()に渡します。

|メソッド|引数|説明|
|---|---|---|
|setId|String|【必須】メディアアイテムID|
|setDescription|String|メディアアイテムの説明|

FieldMask.Builderのsetメソッドにより、
クエリパラメータを追加できます。
build()メソッドでFieldMaskインスタンスを取得し、
updateMediaItem()に渡します。

|メソッド|引数|説明|
|---|---|---|
|addPaths|String|【必須】どのフィールドを更新するかを指定<br>「description」のみ指定可能|

### 2.3. レスポンスの内容
#### MediaItem

[1.2.3. レスポンスの内容(MediaItem)](#mediaitem)と同じです。

<br>
<br>
おしまい。。