今まで、おうちで撮った写真はFlashAir W-04やPQI Air Cardによって、おうちのGentooサーバーを経由してPicasa Webにアップロードされていました。
gentoolinux.hatenablog.comgentoolinux.hatenablog.com
しかし、2019年1月の3連休中に、突如アップロードされなくなってしまいました。
当初は2段階認証を導入したせいだと思っていたのですが、アップロード後に返ってくるjsonの応答を見ると、
The Picasa API is deprecated. See https://developers.google.com/picasa-web/ for more details and the migration guide.
ざっくり言うと、「Picasa APIはもう使えないよ! 詳しくはこのURLとマイグレーションガイドを見てね。」って言っています。
で、このキーワードでググると、Picasa APIからPhotos Library APIに移行するそうな。
あー面倒・・・。
Googleさんはすぐにいままでのことをヤメたり仕様を変えたりと、変わり身が早い企業ですよね。
で、FlashAirやPQI Air Cardから画像をサーバーに引っ張ってくるところなどは変更せず、今までPicasaにアップロードしていた"upload_images_in_dir.sh"のスクリプトを中心に変更していきます。
参考にしたのはコチラのサイト
qiita.com
ひとつひとつ丁寧に解説していただいております。大変助かります。
基本的に、今までのOAuth2の認証情報は変更せず、Photos Library APIを有効化し、スコープをPhotos Libraryにします。
Googleデベロッパーコンソールにアクセスします。
console.developers.google.com
ログインするとこんな感じだと思います。
左の「ライブラリ」をクリックします。
APIライブラリが膨大にあるため絞り込みます。
検索窓に"photos"とでも入れます。
このPhotos Library APIをクリックします。
"有効にする"をクリックします。
認証情報を作成することを勧めていますが、これはPicasa APIの時に作った認証情報が流用できるのでやりません。
(実は、最初わからなくて途中まで新しい認証情報を作りかけたのですが、最後の最後で「似たような既存の認証情報があります」って出てきました。そこで作るのをやめました。紛らわしいわ。)
さて、このPhotos Library APIのスコープを有効化して、新しいリフレッシュトークンを準備します。
ここからGentoo Linuxにsshでアクセスして作業します。
まずは、Photos Libraryを読み書きする権限を有するスコープ、"https://www.googleapis.com/auth/photoslibrary"の認証情報を取得します。
認証情報をブラウザでも取得できるように、URLを生成するbashスクリプトを活用します。
#!/bin/sh #デベロッパーコンソールの認証情報に記載されているクライアントID CLIENT_ID="yourClientID.apps.googleusercontent.com" # ブラウザでAuthorization_Codeを取得できるおまじない REDIRECT_URI="urn:ietf:wg:oauth:2.0:oob" # Photos Library APIのスコープ情報 SCOPE="https://www.googleapis.com/auth/photoslibrary" # URLに整形して出力 echo "https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&scope=$SCOPE&access_type=offline"
これを実行します。
./get_authorization_code.sh
そうすると、次のような文字列が出てきます。
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=yourClientID.apps.googleusercontent.com&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/photoslibrary&access_type=offline
これをブラウザにコピペすると、ログイン後に認証情報が出ます。
許可します。
さて、この認証情報を使って、リフレッシュトークンを取得します。
これも過去のスクリプトを使い回しましょう。
"get_access_token_and_refresh_token.sh"というスクリプトを作成します。
#/bin/bash #デベロッパーコンソールの認証情報に記載されているクライアントID CLIENT_ID="yourClientID.apps.googleusercontent.com" #デベロッパーコンソールの認証情報に記載されているクライアントシークレット CLIENT_SECRET="yourClientSecret" #先ほどのブラウザに表示されていた認証コード AUTHORIZATION_CODE="NewAuthorizationCodeFromBrowser" # HTTPサーバを起動しなくてもトークンを取得できるおまじない REDIRECT_URI="urn:ietf:wg:oauth:2.0:oob" # 実際にリフレッシュトークンを取得 curl --data "code=${AUTHORIZATION_CODE}" \ --data "client_id=${CLIENT_ID}" \ --data "client_secret=${CLIENT_SECRET}" \ --data "redirect_uri=${REDIRECT_URI}" \ --data "grant_type=authorization_code" \ --data "access_type=offline" \ https://www.googleapis.com/oauth2/v4/token
これを実行すると、json形式でアクセストークンとリフレッシュトークンが出力されます。
./get_access_token_and_refresh_token.sh
出力例
{ "access_token" => "NewAccessToken", "token_type" => "Bearer", "expires_in" => 3600, "refresh_token" : "RefreshTokenIsPermanent" }
Photos Library APIではこのリフレッシュトークンを使っていきます。
で、Photos Library APIを使ってアルバムにアップロードする場合、Photos Library APIを使って作成したアルバムじゃないと、アップロード出来ません。
アルバム作成のAPI解説
developers.google.com
まずは、アルバムを作成するスクリプトとして、create_album.shというスクリプトを作りました。
#/bin/bash CLIENT_ID="yourClientID.apps.googleusercontent.com" CLIENT_SECRET="yourClientSecret" REFRESH_TOKEN="RefreshTokenAcquiredEarlier" #アクセストークン取得 curl -s --data "refresh_token=${REFRESH_TOKEN}" --data "client_id=${CLIENT_ID}" --data "client_secret=${CLIENT_SECRET}" --data "grant_type=refresh_token" https://www.googleapis.com/oauth2/v4/token > token.JSON ACCESS_TOKEN=`cat token.JSON | jq -r '.access_token'` echo "Access token is " ${ACCESS_TOKEN} # アルバム名を指定 ALBUMNAME="NewAlbum" ENDPOINT="https://photoslibrary.googleapis.com/v1/albums" #アルバムを作成してAlbumIdを取得 ALBUMID=$(curl -s -X POST -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-type: application/json" \ -d '{ "album": { "title":"${ALBUMNAME}" } }' ${ENDPOINT}) echo ${ALBUMID} echo ${ALBUMID} >> albumid.txt
これを実行します。
./create_album.sh
すると、json形式でアルバム名とアルバムIDが表示されます。
念のため、albumid.txtというファイルにも追記していくことにしました。
出力例
{ "id": "NewAlbumIDisLongLongString", "title": "${ALBUMNAME}", "productUrl": "https://photos.google.com/lr/album/NewAlbumURLisAlsoLongLongString", "isWriteable": true }
あらら、なぜかアルバムタイトルが${ALBUMNAME}になっちゃった。
でも、これはGoogleフォトアプリやサイト上で直せます。
大事なのはidです。
ちなみに、ここは余談ですが、既存のアルバムIDとアルバム名を取得するスクリプトget_albumid.shも作ってしまいました。
#/bin/bash CLIENT_ID="yourClientID.apps.googleusercontent.com" CLIENT_SECRET="yourClientSecret" REFRESH_TOKEN="RefreshTokenAcquiredEarlier" #アクセストークン取得 curl -s --data "refresh_token=${REFRESH_TOKEN}" \ --data "client_id=${CLIENT_ID}" \ --data "client_secret=${CLIENT_SECRET}" \ --data "grant_type=refresh_token" \ https://www.googleapis.com/oauth2/v4/token > token.JSON ACCESS_TOKEN=`cat token.JSON | jq -r '.access_token'` echo "Access token is " ${ACCESS_TOKEN} ENDPOINT="https://photoslibrary.googleapis.com/v1/albums?pageSize=50" ALBUMLIST=$(curl -s -H "Authorization: Bearer $ACCESS_TOKEN" ${ENDPOINT}) echo ${ALBUMLIST} | jq -c '.albums[] | [.id, .title]'
jqを使ってアルバムIDとアルバム名を1行に出力するので、grepを使って目的のアルバムIDを取得できます。
が、先ほども書きましたが、Photos Library APIでアップロードできるアルバム先は、Photos Library APIで作成したアルバムだけです。
あんまり役にたたないですが、一応・・・。
アルバム等のリスト取得の解説
developers.google.com
さて、新たなPhotos Library APIは、アルバムに写真をアップロードするのに、2段階の手順を踏みます。
- 写真をアップロードしupload tokenを取得
- upload tokenを使ってアップロード先のアルバムを指定
アップロード先のURLはhttps://photoslibrary.googleapis.com/v1/uploadsになり、ここに必要なデータをポストします。
いままでのPicasa APIはURLに認証情報などを埋め込んでいましたが、今回からはヘッダーに入れるようになっています。
curlを使ってfile.JPGという写真をアップロードするなら次のようなイメージになります。
curl -s -X POST \ -H "Authorization: Bearer yourAccessToken" \ -H "Content-type: application/octet-stream" \ -H "X-Goog-Upload-File-Name: $(basename file.JPG)" \ -H "X-Goog-Upload-Protocol: raw" \ --upload-file "file.JPG" \ https://photoslibrary.googleapis.com/v1/uploads
アップロードに成功すると、upload tokenが返ってきます。そのupload tokenとアルバムIDを指定して、アルバムに移動させます。
移動を指示するURLは"https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate"です。
curl -H "Content-type: application/json" \ -H "Authorization: Bearer yourAccessToken" \ -d '{"albumId": "'NewAlbumIDisLongLongString'", "newMediaItems":[{"simpleMediaItem":{"uploadToken": "'UploadTokenIsAlsoLongLongStoring'"}}]}' \ -X POST "https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate"
新しく生まれ変わったupload_images_in_dir.shは次の通りです。
これは、指定したディレクトリ上にある全ての.JPG/.jpg/.bmp/.pngをGoogle Photosにアップロードします。
#/bin/bash CLIENT_ID="yourClientID.apps.googleusercontent.com" CLIENT_SECRET="yourClientSecret" REFRESH_TOKEN="RefreshTokenAcquiredEarlier" ALBUM_ID="NewAlbumIDisLongLongString" #アクセストークン取得 curl -s --data "refresh_token=${REFRESH_TOKEN}" \ --data "client_id=${CLIENT_ID}" --data "client_secret=${CLIENT_SECRET}" \ --data "grant_type=refresh_token" https://www.googleapis.com/oauth2/v4/token > token.JSON ACCESS_TOKEN=`cat token.JSON | jq -r '.access_token'` #echo "Access token is " ${ACCESS_TOKEN} ENDPOINT="https://photoslibrary.googleapis.com/v1/uploads" MEDIAITEMS="https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate" DIR="./" # 任意のディレクトリを指定 IFS_BAK=${IFS} IFS=" " FILES=`ls -1 ${DIR}` for FILE in ${FILES} do if [ "${FILE}" != "" ]; then TYPE="UNKNOWN" case "${FILE}" in *\.bmp) TYPE="image/bmp";; *\.JPG | *\.jpg) TYPE="image/jpeg";; *\.png) TYPE="image/png";; *) TYPE="UNKNOWN";; esac # echo "$TYPE $FILE $LENGTH" if [ "${TYPE}" = "UNKNOWN" ]; then continue; fi echo "Uploading to Google Photos " ${FILE} UPLOAD_TOKEN=$(curl -s -X POST \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-type: application/octet-stream" \ -H "X-Goog-Upload-File-Name: $(basename $FILE)" \ -H "X-Goog-Upload-Protocol: raw" \ --upload-file "${FILE}" \ ${ENDPOINT}) # echo "UPLOAD_TOKEN: ${UPLOAD_TOKEN} " echo "Move Alubums " ${FILE} curl -H "Content-type: application/json" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -d '{"albumId": "'${ALBUM_ID}'", "newMediaItems":[{"simpleMediaItem":{"uploadToken": "'${UPLOAD_TOKEN}'"}}]}' \ -s -o /dev/null \ -X POST "${MEDIAITEMS}" sleep 1 fi done IFS=$IFS_BAK
あ、もちろん、"yourClientID.apps.googleusercontent.com"、"yourClientSecret"、"RefreshTokenAcquiredEarlier"、"NewAlbumIDisLongLongString"などは、あなたがお持ちの認証情報に書き換えないと動きませんよ。