メディアをアップロードする

メディア アイテムのアップロードは 2 段階で行います。

  1. アップロード エンドポイントを使用して、メディア ファイルのバイトを Google サーバーにアップロードします。これは、アップロードされたバイトを識別するアップロード トークンを返します。
  2. アップロード トークンを含む batchCreate 呼び出しを使用して、ユーザーの Google フォト アカウントにメディア アイテムを作成します。

以下では、単一のメディア アイテムをアップロードするプロセスの概要を示します。複数のメディア アイテムをアップロードする場合(あらゆる製品版アプリケーションでよく見られます)は、アップロードのベスト プラクティスを確認してアップロード効率を高めてください。

始める前に

必要な認可スコープ

ユーザーのライブラリまたはアルバムにメディア アイテムをアップロードするには、photoslibrary.appendonly スコープまたは photoslibrary スコープが必要です。

photoslibrary.sharing スコープを使用してメディア アイテムを作成することもできます。photoslibrary.sharing スコープを使用してアイテムを作成するには、まず shareAlbum を使用してアルバムを作成し、共有としてマークする必要があります。その後、アルバム内でユーザーと共有するメディア アイテムを作成できます。アプリが共有していないユーザーのライブラリやアルバム内に、アイテムを直接作成することはできません。

アルバムを一覧表示する場合、isWriteable プロパティは、アプリが特定のアルバムにメディアを作成できるかどうかを示します。

使用できるファイル形式とサイズ

アップロードできるファイル形式は下の表のとおりです。

メディアタイプ 使用できるファイル形式 最大ファイルサイズ
写真 AVIF、BMP、GIF、HEIC、ICO、JPG、PNG、TIFF、WEBP、一部の RAW ファイル。 200 MB
動画 3GP、3G2、ASF、AVI、DIVX、M2T、M2TS、M4V、MKV、MMV、MOD、MOV、MP4、MPG、MTS、TOD、WMV。 20 GB

ステップ 1: バイトのアップロード

アップロード リクエストを使用して Google にバイトをアップロードします。アップロード リクエストが成功すると、アップロード トークンが未加工のテキスト文字列の形式で返されます。これらのアップロード トークンを使用して、batchCreate 呼び出しでメディア アイテムを作成します。

REST

POST リクエスト ヘッダーに次のフィールドを含めます。

ヘッダー フィールド
Content-type application/octet-stream に設定します。
X-Goog-Upload-Content-Type (推奨)。アップロードするバイトの MIME タイプに設定します。一般的な MIME タイプには、image/jpegimage/pngimage/gif などがあります。
X-Goog-Upload-Protocol raw に設定します。

POST リクエスト ヘッダーは次のとおりです。

POST https://photoslibrary.googleapis.com/v1/uploads
Authorization: Bearer oauth2-token
Content-type: application/octet-stream
X-Goog-Upload-Content-Type: mime-type
X-Goog-Upload-Protocol: raw

リクエストの本文にファイルのバイナリを含めます。

media-binary-data

この POST リクエストが成功すると、未加工のテキスト文字列の形式のアップロード トークンがレスポンスの本文として返されます。メディア アイテムを作成するには、batchCreate 呼び出しでこれらのテキスト文字列を使用します。

upload-token

Java

// Open the file and automatically close it after upload
try (RandomAccessFile file = new RandomAccessFile(pathToFile, "r")) {
  // Create a new upload request
  UploadMediaItemRequest uploadRequest =
      UploadMediaItemRequest.newBuilder()
              // The media type (e.g. "image/png")
              .setMimeType(mimeType)
              // The file to upload
              .setDataFile(file)
          .build();
  // Upload and capture the response
  UploadMediaItemResponse uploadResponse = photosLibraryClient.uploadMediaItem(uploadRequest);
  if (uploadResponse.getError().isPresent()) {
    // If the upload results in an error, handle it
    Error error = uploadResponse.getError().get();
  } else {
    // If the upload is successful, get the uploadToken
    String uploadToken = uploadResponse.getUploadToken().get();
    // Use this upload token to create a media item
  }
} catch (ApiException e) {
  // Handle error
} catch (IOException e) {
  // Error accessing the local file
}

PHP

try {
    // Create a new upload request by opening the file
    // and specifying the media type (e.g. "image/png")
    $uploadToken = $photosLibraryClient->upload(file_get_contents($localFilePath), null, $mimeType);
} catch (\GuzzleHttp\Exception\GuzzleException $e) {
    // Handle error
}

画像の推奨ファイルサイズは 50 MB 未満です。ファイルが 50 MB を超えると、パフォーマンスの問題が生じやすくなります。

Google Photos Library API では、再開可能なアップロードがサポートされています。再開可能なアップロードでは、メディア ファイルを複数のセクションに分割し、一度に 1 つのセクションをアップロードできます。

ステップ 2: メディア アイテムを作成する

メディア ファイルのバイトをアップロードした後、アップロード トークンを使用して Google フォトでメディア アイテムとしてファイルを作成できます。アップロード トークンは、作成後 1 日間有効です。メディア アイテムは常にユーザーのライブラリに追加されます。メディア アイテムは、アプリによって作成されたアルバムに追加できます。詳細については、認可スコープをご覧ください。

新しいメディア アイテムを作成するには、newMediaItems のリストを指定して mediaItems.batchCreate を呼び出します。各 newMediaItem には、simpleMediaItem 内で指定されたアップロード トークンと、ユーザーに表示されるオプションの説明が含まれます。

説明フィールドは 1,000 文字以内に制限されており、ユーザーが作成した意味のあるテキストのみを含める必要があります。たとえば、「公園への旅行」や「ホリデー ディナー」などです。ファイル名、プログラマティックなタグ、その他の自動生成されたテキストなどのメタデータは含めないでください。

最適なパフォーマンスを得るには、1 回の呼び出しに複数のメディア アイテムを含めることで、mediaItems.batchCreate の呼び出し回数を減らします。前のリクエストが完了するまで、必ず同じユーザーに対して後続の呼び出しを行ってください。

ユーザーのライブラリ内に 1 つのメディア アイテムまたは複数のメディア アイテムを作成するには、説明と対応するアップロード トークンを指定します。

REST

POST リクエスト ヘッダーは次のとおりです。

POST https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate
Content-type: application/json
Authorization: Bearer oauth2-token

リクエストの本文には newMediaItems のリストを指定する必要があります。

{
  "newMediaItems": [
    {
      "description": "item-description",
      "simpleMediaItem": {
        "fileName": "filename",
        "uploadToken": "upload-token"
      }
    }
   , ...
  ]
}

Java

try {
  // Create a NewMediaItem with the following components:
  // - uploadToken obtained from the previous upload request
  // - filename that will be shown to the user in Google Photos
  // - description that will be shown to the user in Google Photos
  NewMediaItem newMediaItem = NewMediaItemFactory
          .createNewMediaItem(uploadToken, fileName, itemDescription);
  List<NewMediaItem> newItems = Arrays.asList(newMediaItem);

  BatchCreateMediaItemsResponse response = photosLibraryClient.batchCreateMediaItems(newItems);
  for (NewMediaItemResult itemsResponse : response.getNewMediaItemResultsList()) {
    Status status = itemsResponse.getStatus();
    if (status.getCode() == Code.OK_VALUE) {
      // The item is successfully created in the user's library
      MediaItem createdItem = itemsResponse.getMediaItem();
    } else {
      // The item could not be created. Check the status and try again
    }
  }
} catch (ApiException e) {
  // Handle error
}

PHP

try {
    $newMediaItems = [];
    // Create a NewMediaItem with the following components:
    // - uploadToken obtained from the previous upload request
    // - filename that will be shown to the user in Google Photos
    // - description that will be shown to the user in Google Photos
    $newMediaItems[0] = PhotosLibraryResourceFactory::newMediaItemWithDescriptionAndFileName(
            $uploadToken, $itemDescription, $fileName);

    $response = $photosLibraryClient->batchCreateMediaItems($newMediaItems);
    foreach ($response->getNewMediaItemResults() as $itemResult) {
        $status = $itemResult->getStatus();
        if ($status->getCode() != Code::OK) {
            // Error while creating the item.
        }
    }
} catch (\Google\ApiCore\ApiException $e) {
    // Handle error
}


アルバム id を指定して、ライブラリとアルバムにメディア アイテムを追加できます。詳しくは、アルバムを作成するをご覧ください。

各アルバムには最大 20,000 個のメディア アイテムを含めることができます。この上限を超えるメディア アイテムをアルバム内に作成するリクエストは失敗します。

REST

{
  "albumId": "album-id",
  "newMediaItems": [
    {
      "description": "item-description",
      "simpleMediaItem": {
        "fileName": "filename",
        "uploadToken": "upload-token"
      }
    }
   , ...
  ]
}

Java

try {
  // Create new media items in a specific album
  BatchCreateMediaItemsResponse response = photosLibraryClient
      .batchCreateMediaItems(albumId, newItems);
  // Check the response
} catch (ApiException e) {
  // Handle error
}

PHP

try {
    $response = $photosLibraryClient->batchCreateMediaItems($newMediaItems, ['albumId' => $albumId]);
} catch (\Google\ApiCore\ApiException $e) {
    // Handle error
}

albumIdalbumPosition を指定して、アルバム内の特定の場所にメディア アイテムを挿入することもできます。

REST

{
  "albumId": "album-id",
  "newMediaItems": [
    {
      "description": "item-description",
      "simpleMediaItem": {
        "fileName": "filename",
        "uploadToken": "upload-token"
      }
    }
    , ...
  ],
  "albumPosition": {
    "position": "after-media-item",
    "relativeMediaItemId": "media-item-id"
  }
}

Java

try {
  // Create new media items in a specific album, positioned after a media item
  AlbumPosition positionInAlbum = AlbumPositionFactory.createFirstInAlbum();
  BatchCreateMediaItemsResponse response = photosLibraryClient
      .batchCreateMediaItems(albumId, newItems, positionInAlbum);
  // Check the response
} catch (ApiException e) {
  // Handle error
}

PHP

try {
    $albumPosition = PhotosLibraryResourceFactory::albumPositionAfterMediaItem($mediaItemId);
    $response = $photosLibraryClient->batchCreateMediaItems($newMediaItems,
        ['albumId' => $albumId, 'albumPosition' => $albumPosition]);
} catch (\Google\ApiCore\ApiException $e) {
    // Handle error
}

アルバム内の配置の詳細については、エンリッチメントを追加するをご覧ください。

アイテム作成レスポンス

mediaItems.batchCreate を呼び出すと、作成しようとしたメディア アイテムごとに結果が返されます。newMediaItemResults のリストはステータスを示し、リクエストの uploadToken を含みます。ゼロ以外のステータス コードはエラーを示します。

REST

すべてのメディア アイテムが正常に作成された場合、リクエストは HTTP ステータス 200 OK を返します。作成できないメディア アイテムがある場合、リクエストは部分的な成功を示す HTTP ステータス 207 MULTI-STATUS を返します。

{
  "newMediaItemResults": [
    {
      "uploadToken": "upload-token",
      "status": {
        "message": "Success"
      },
      "mediaItem": {
        "id": "media-item-id",
        "description": "item-description",
        "productUrl": "https://photos.google.com/photo/photo-path",
        "mimeType": "mime-type",
        "mediaMetadata": {
          "width": "media-width-in-px",
          "height": "media-height-in-px",
          "creationTime": "creation-time",
          "photo": {}
        },
        "filename": "filename"
      }
    },
    {
      "uploadToken": "upload-token",
      "status": {
        "code": 13,
        "message": "Internal error"
      }
    }
  ]
}

Java

BatchCreateMediaItemsResponse response = photosLibraryClient.batchCreateMediaItems(newItems);

// The response contains a list of NewMediaItemResults
for (NewMediaItemResult result : response.getNewMediaItemResultsList()) {
  // Each result item is identified by its uploadToken
  String uploadToken = result.getUploadToken();
  Status status = result.getStatus();

  if (status.getCode() == Code.OK_VALUE) {
    // If the request is successful, a MediaItem is returned
    MediaItem mediaItem = result.getMediaItem();
    String id = mediaItem.getId();
    String productUrl = mediaItem.getProductUrl();
    // ...
  }
}

PHP

// The response from a call to batchCreateMediaItems returns a list of NewMediaItemResults
foreach ($response->getNewMediaItemResults() as $itemResult) {
    // Each result item is identified by its uploadToken
    $itemUploadToken = $itemResult->getUploadToken();
    // Verify the status of each entry to ensure that the item has been uploaded correctly
    $itemStatus = $itemResult->getStatus();
    if ($itemStatus->getCode() != Code::OK) {
        // Error when item is being created
    } else {
        // Media item is successfully created
        // Get the MediaItem object from the response
        $mediaItem = $itemResult->getMediaItem();
        // It contains details such as the Id of the item, productUrl
        $id = $mediaItem->getId();
        $productUrl = $mediaItem->getProductUrl();
        // ...
    }
}

アイテムが正常に追加すると、mediaItemIdproductUrlmediaMetadata を含む mediaItem が返されます。詳しくは、メディア アイテムにアクセスするをご覧ください。

メディア アイテムが動画の場合は、最初に処理する必要があります。mediaItemmediaMetadata 内には、動画ファイルの処理状態を記述する status が含まれています。新しくアップロードされたファイルは、まず PROCESSING ステータスを返してから、READY で使用可能になります。詳しくは、メディア アイテムにアクセスするをご覧ください。

この呼び出し中にエラーが発生した場合は、ベスト プラクティスに沿ってリクエストを再試行してください。次のリクエスト時に画像をアルバムの正しい位置に挿入できるように、成功した追加を記録することをおすすめします。詳しくは、アルバムを作成するをご覧ください。

結果は常にアップロード トークンの送信順序と同じ順序で返されます。

アップロードに関するおすすめの方法

次のベスト プラクティスとリソースは、アップロードの全体的な効率の向上に役立ちます。

  • サポートされているクライアント ライブラリのいずれかを使用します。
  • 次の点に注意してください。再試行とエラー処理のベスト プラクティスに従ってください。
    • 429 エラーは、割り当ての上限に達したか、呼び出し回数が多すぎるためにレート制限されている場合に発生します。前のリクエストが完了するまで、同じユーザーの batchCreate を呼び出さないでください。
    • 429 エラーが発生した場合は、再試行の前に少なくとも 30s の遅延が必要です。リクエストを再試行するときは、指数バックオフ戦略を使用します。
    • 500 エラーは、サーバーでエラーが発生したときに発生します。アップロードの際に、この原因として可能性が高いのは、同じユーザーに対して複数の書き込み呼び出し(batchCreate など)を同時に行っていることです。リクエストの詳細を確認し、batchCreate を並行して呼び出しないでください。
  • 再開可能なアップロード フローを使用して、ネットワークが中断した場合のアップロードの堅牢性を高め、部分的に完了したアップロードを再開できるようにすることで帯域幅の使用量を減らします。これは、クライアントのモバイル デバイスからアップロードする場合や、サイズの大きいファイルをアップロードする場合に重要です。

また、アップロード プロセスの各ステップで、バイトのアップロード後、メディア アイテムの作成に関するヒントも確認してください。

バイトをアップロードしています

  • バイトのアップロード(アップロード トークンの取得)は並行して実行できます。
  • アップロードの呼び出しごとに、X-Goog-Upload-Content-Type ヘッダーで常に正しい MIME タイプを設定します。

メディア アイテムの作成

  • 1 人のユーザーに対して batchCreate と並行して呼び出しを行わないでください。

    • ユーザーごとに batchCreate を順次(シリアル)呼び出します。
    • 複数のユーザーがいる場合は、必ずユーザーごとに batchCreate を 1 つずつ順番に呼び出してください。異なるユーザーに対してのみ、呼び出しを並行して行います。
  • batchCreate の呼び出しごとに可能な限り多くの NewMediaItems を指定することで、呼び出しの合計数を最小限に抑えることができます。最大 50 個のアイテムを含めることができます。

  • ユーザーが作成したわかりやすい説明テキストを設定します。説明フィールドには、ファイル名、プログラマティックなタグ、その他の自動生成されたテキストなどのメタデータを含めないでください。

サンプルのチュートリアル

この例では、疑似コードを使用して、複数のユーザー用にメディア アイテムをアップロードする手順について説明します。目標は、アップロード プロセス(RAW バイトのアップロードメディア アイテムの作成)の両方のステップと、効率的で復元力のあるアップロードの統合を構築するためのベスト プラクティスの詳細を説明することです。

ステップ 1: 未加工のバイトをアップロードする

まず、キューを作成し、すべてのユーザーのメディア アイテムの未加工のバイトをアップロードします。ユーザーごとに、返品された各 uploadToken 個を追跡します。以下の点にご注意ください。

  • 同時アップロードのスレッド数は、オペレーティング環境によって異なります。
  • 必要に応じてアップロード キューの順序を変更することを検討してください。たとえば、ユーザーごとの残りのアップロード数、ユーザーの全体的な進捗状況、その他の要件に基づいて、アップロードの優先度を設定できます。

擬似コード

CREATE uploadQueue FROM users, filesToUpload
// Upload media bytes in parallel.
START multiple THREADS
  WHILE uploadQueue is not empty
    POP uploadQueue
    UPLOAD file for user
    GET uploadToken
    CHECK and HANDLE errors
    STORE uploadToken for user in uploadTokensQueue
  END

ステップ 2: メディア アイテムを作成する

ステップ 1 では、複数のユーザーから複数のバイトを同時にアップロードできますが、ステップ 2 では、ユーザーごとに一度に 1 つの呼び出ししか行えません。

擬似コード

// For each user, create media items once 50 upload tokens have been
// saved, or no more uploads are left per user.
WHEN uploadTokensQueue for user is >= 50 OR no more pending uploads for user
  // Calls can be made in parallel for different users,
  // but only make a single call per user at a time.
  START new thread for (this) user if there is no thread yet
    POP 50 uploadTokens from uploadTokensQueue for user
    CALL mediaItems.batchCreate with uploadTokens
    WAIT UNTIL batchCreate call has completed
    CHECK and HANDLE errors (retry as needed)
  DONE.

すべてのアップロードとメディア作成の呼び出しが完了するまで、このプロセスを繰り返します。