上传媒体

上传媒体内容的过程分为两个步骤:

  1. 使用上传端点将媒体文件的字节上传到 Google 服务器。 此方法会返回一个上传令牌,用于标识上传的字节。
  2. 使用带有上传令牌的 batchCreate 调用 在用户的 Google 相册账号中创建媒体内容。

以下步骤概述了上传单个媒体内容的流程。如果您 上传多项媒体内容(很适合任何生产应用)、 请查看上传的最佳做法, 上传效率

准备工作

必需的授权范围

要将媒体内容上传到用户的媒体库或影集,您需要使用 photoslibrary.appendonlyphotoslibrary 范围。

还可以使用 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 支持 可续传上传。可续传 上传功能可以将媒体文件拆分成多个部分,然后上传一个 部分。

第 2 步:创建媒体内容

上传完媒体文件的字节后,您可以将其创建为媒体 Google 相册中的内容上传。上传令牌有效 创建后一天内有效。媒体项始终会添加到用户的 库。媒体项只能 已添加到影集 由您的应用创建而成如需了解详情,请参阅授权范围

要创建新的媒体项,请调用 mediaItems.batchCreate 方法是指定 newMediaItems 列表。每个 newMediaItem 均包含一个上传内容 simpleMediaItem 中指定的令牌,以及可选的说明 向用户显示的信息

说明字段不得超过 1000 个字符,且只能包含 用户创建的有意义文本。例如,“我们的公园之旅”或 “节日晚餐”。请勿包含元数据,例如文件名、程序化交易 标记或其他自动生成的文本。

为获得最佳效果,请将调用次数减少到 mediaItems.batchCreate 您需要通过在一次调用中添加多项媒体项来实现。始终等待 直到前一个请求完成后再针对 同一用户

您可以在用户的媒体库中创建单个或多个媒体项 方法是指定说明和相应的上传令牌:

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();
        // ...
    }
}

如果成功添加项,系统将返回 mediaItem,其中包含其 mediaItemIdproductUrlmediaMetadata。如需了解详情,请参阅 访问媒体内容

如果媒体内容是视频,则必须先对其进行处理。mediaItem mediaMetadata 中包含一个 status,用于描述处理过程 视频文件的状态。新上传的文件会返回 PROCESSING 状态 ,然后再设为 READY,以供使用。有关详情,请参阅 访问媒体内容

如果您在此次通话中遇到错误,请按照 最佳做法,然后重试您的请求。 您可能希望跟踪成功添加的内容,以便图片可以插入 发送到相册中的正确位置。有关 请参阅 创建影集

返回结果的顺序始终与上传令牌的顺序相同 提交。

上传的最佳做法

以下最佳做法和资源有助于提高您的整体效率 :

  • 使用我们支持的某个客户端库
  • 请遵循重试和错误处理最佳做法, 请注意以下几点: <ph type="x-smartling-placeholder">
      </ph>
    • 您的配额已用尽时,可能会出现 429 错误 或者因过快拨打过多电话而受到限制。请确保 您不会为同一用户调用 batchCreate,直到上一条 请求已完成。
    • 429 个错误要求至少延迟 30s,然后重试。使用 指数退避算法 策略。
    • 服务器遇到错误时会发生 500 错误。上传时, 这很可能是因为进行了多次写入调用(例如 batchCreate)。查看以下项的详细信息: 切勿并行调用 batchCreate
  • 使用可续传上传流程执行以下操作: 让你的上传在出现网络中断时更稳健 恢复部分完成的上传,从而减少带宽用量。 从客户端移动设备上传内容时,这一点很重要;或者 。

此外,对于上传流程的每一步,也请考虑以下提示: 上传字节,然后创建媒体内容

上传字节

创建媒体内容

  • 请勿为单个用户并行调用 batchCreate

    • 对于每个用户,依次调用 batchCreate(在 序列号)。
    • 对于多名用户,请始终针对每个用户进行 batchCreate 调用 一个又一个。仅并行调用不同的用户
  • 添加尽可能多的NewMediaItems 在与 batchCreate 的每次通话中,尽可能减少通话总数 。您最多可以添加 50 项。

  • 设置有意义的说明文字 创建的新文件请勿添加元数据,例如 文件名、程序化代码或 说明字段。

示例演示

此示例使用伪代码来逐步上传多个 用户。目的是概述上传流程的两个步骤(将原始文件上传至 字节创建媒体项)和 详细说明构建高效、弹性上传的最佳做法 集成。

第 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 步中,您一次只能为每位用户拨打一个电话。

伪代码

// 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.

继续此过程,直到完成所有上传和媒体创建调用。