GeekFactory

int128.hatenablog.com

Google Photos Library APIで写真をアップロードする

Google Photos Library APIが使えるようになったので、写真のアップロードを試してみました。

アクセストークンの取得

https://console.cloud.google.com/apis/credentials から新しいOAuth Clientを追加します。Client IDとClient Secretが表示されるのでメモしておきます。

アクセストークンを取得します。まず、ブラウザで以下のURLを開きます。YOUR_CLIENT_ID はClient IDに置き換えてください(以下同じです)。

https://accounts.google.com/o/oauth2/v2/auth?client_id=YOUR_CLIENT_ID.apps.googleusercontent.com&response_type=code&scope=https://www.googleapis.com/auth/photoslibrary&redirect_uri=urn:ietf:wg:oauth:2.0:oob

すると、ブラウザ上に認可コードが表示されます。以下のコマンドを実行します。

curl -X POST --data 'code=YOUR_AUTH_CODE&client_id=YOUR_CLIENT_ID.apps.googleusercontent.com&client_secret=YOUR_CLIENT_SECRET&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code' https://www.googleapis.com/oauth2/v4/token

アクセストークンを含むJSONが返されるのでメモしておきます。

{
 "access_token": "YOUR_ACCESS_TOKEN",
 "token_type": "Bearer",
 "expires_in": 3600,
 "refresh_token": "..."
}

写真のアップロード

ここからは Upload media にしたがって進みます。

まず、画像ファイルをアップロードします。

curl -v --upload-file YOUR_IMAGE.png -X POST -H 'Content-type: application/octet-stream' -H 'X-Goog-Upload-File-Name: YOUR_IMAGE.png' -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' https://photoslibrary.googleapis.com/v1/uploads

アップロードに成功するとトークンが返されるのでメモしておきます。

< HTTP/2 200
< x-guploader-uploadid: ...
< content-type: text/plain
< content-length: 510
< date: Wed, 06 Jun 2018 14:11:39 GMT
< server: UploadServer
< alt-svc: quic=":443"; ma=2592000; v="43,42,41,39,35"
<
UPLOAD_TOKEN

次に、アップロードした写真を自分のライブラリに追加します。

curl -v --data '{"newMediaItems":[{"simpleMediaItem":{"uploadToken":"UPLOAD_TOKEN"}}]}' -H 'Content-type: application/json' -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' "https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate"

ライブラリへの追加が成功すると以下のようなレスポンスが返されます。

< HTTP/2 200
< content-type: application/json; charset=UTF-8
< vary: X-Origin
< vary: Referer
< vary: Origin,Accept-Encoding
< date: Wed, 06 Jun 2018 14:14:27 GMT
< server: ESF
< cache-control: private
< x-xss-protection: 1; mode=block
< x-frame-options: SAMEORIGIN
< x-content-type-options: nosniff
< alt-svc: quic=":443"; ma=2592000; v="43,42,41,39,35"
< accept-ranges: none
<
{
  "newMediaItemResults": [
    {
      "uploadToken": "UPLOAD_TOKEN",
      "status": {
        "message": "OK"
      },
      "mediaItem": {
        "id": "...",
        "productUrl": "https://photos.google.com/lr/photo/...",
        "mimeType": "image/png",
        "mediaMetadata": {
          "creationTime": "2018-06-06T14:14:25Z",
          "width": "2462",
          "height": "1040"
        }
      }
    }
  ]
}

Googleフォトを開いてみましょう。新しい写真が追加されていれば成功です。

重複する写真のアップロード

ここで同じ写真を再度アップロードしてみます。

curl -v --upload-file YOUR_IMAGE.png -X POST -H 'Content-type: application/octet-stream' -H 'X-Goog-Upload-File-Name: YOUR_IMAGE..png' -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' https://photoslibrary.googleapis.com/v1/uploads

先ほどとは異なるトークンが返されました。このトークンを自分のライブラリに追加してみます。

curl -v --data '{"newMediaItems":[{"simpleMediaItem":{"uploadToken":"UPLOAD_TOKEN"}}]}' -H 'Content-type: application/json' -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' "https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate"

すると、不思議なことに先ほどと同じレスポンスが返されました。mediaItemidが同じ値になっています。

Googleフォトを開いてみましょう。やはり画像が重複することはなく、1枚だけ表示されているはずです。

ドキュメントによると同じ写真をアップロードした場合はトークンが発行されないはずですが、実際には一連のAPIは成功するが画像は重複しない振る舞いになるようです。冪等になるように工夫されているのですね。

(6/20追記)下記の記事も参考にしてください。

int128.hatenablog.com

See Also