上傳媒體內容

上傳媒體項目包含兩個步驟:

  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 相簿中使用上傳權杖,建立這些檔案做為媒體項目。上傳憑證在建立後一天有效。媒體項目一律會新增至使用者的程式庫。媒體項目只能新增至由應用程式建立的相簿,詳情請參閱「授權範圍」一文。

如要建立新的媒體項目,請指定 newMediaItems 清單來呼叫 mediaItems.batchCreate。每個 newMediaItem 都包含在 simpleMediaItem 中指定的上傳憑證,以及向使用者顯示的說明 (選用)。

說明欄位的字數上限為 1,000 個字元,而且只能包含使用者建立的有意義的文字。例如「我們的公園之旅」或「假日晚餐」。請勿加入檔案名稱、程式輔助標記或其他自動產生的文字等中繼資料。

為獲得最佳效能,請在一次呼叫中加入多個媒體項目,減少對 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。詳情請參閱「存取媒體項目」。

如果媒體項目是影片,就必須先進行處理。mediaItemmediaMetadata 中包含 status,用於說明影片檔案的處理狀態。新上傳的檔案會先傳回 PROCESSING 狀態,然後再傳回 READY 以供使用。詳情請參閱「存取媒體項目」。

如果在此呼叫期間發生錯誤,請按照最佳做法重新提出要求。您可能想要追蹤成功新增的項目,以便在下次要求時,將圖片插入相簿中的正確位置。詳情請參閱「建立相簿」。

結果一律會按照提交憑證的提交順序傳回。

上傳的最佳做法

下列最佳做法和資源有助於改善上傳的整體效率:

  • 使用我們支援的用戶端程式庫
  • 請按照重試和錯誤處理最佳做法操作,請留意以下要點:
    • 如果配額用盡,或快速呼叫次數過多,也可能會發生 429 錯誤。在先前的要求完成前,請勿為同一使用者呼叫 batchCreate
    • 429 錯誤需要至少延遲 30s 才能重試。如要重試要求,請使用指數輪詢策略。
    • 伺服器發生錯誤時會發生 500 錯誤。上傳時,最有可能的原因是同時對同一位使用者發出多次寫入呼叫 (例如 batchCreate)。請查看要求的詳細資料,不要並行呼叫 batchCreate
  • 使用支援續傳的上傳流程,讓上傳作業在網路中斷時能更穩健,並讓您繼續完成部分完成的上傳作業,藉此減少頻寬用量。從用戶端行動裝置上傳,或上傳大型檔案時,這一點非常重要。

同樣地,請考慮在上傳過程中的每個步驟,參考下列提示:上傳位元組,然後建立媒體項目

正在上傳位元組數

  • 上傳位元組 (以擷取上傳權杖) 可以平行完成。
  • 針對每個上傳呼叫,請一律在 X-Goog-Upload-Content-Type 標頭中設定正確的 MIME 類型。

正在建立媒體項目

  • 請勿對單一使用者同時呼叫 batchCreate

    • 針對每個使用者,逐一呼叫 batchCreate (依序呼叫)。
    • 如有多位使用者,請逐一對每位使用者發出 batchCreate 呼叫。只對「不同使用者」同時發出呼叫。
  • 請在每次呼叫 batchCreate盡量加入 NewMediaItems,以盡量減少所需的呼叫總數。您最多可以加入 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.

繼續此程序,直到所有上傳和媒體建立呼叫都完成。