一眼レフで撮った写真をGoogle Photosに自動アップロード その2 サーバースクリプト設置
<2019年1月にPicasa Photos APIの廃止準備(2019年3月に完全停止)に伴い、ここに記載の方法では写真をアップロード出来なくなりました。Google Photos APIに変更する必要があります。が、本ブログではまだbashスクリプトによるアップロード方法を模索中(勉強中)です。>
その1では、PQI AirCardを自宅のWiFiで使うための設定を行いました。
今回は、サーバー側の設定をしていきます。
サーバーで実現することは、
・活性後、PQI AirCard内の画像のうち、JPGだけをFTPで取得。その後に重複取得しないようにJPEGファイル名称をとあるファイルにアペンド(追加)
・Google APIの認証情報(CLIENT ID,CLIENT SECRET,REFRESH TOKEN)に基づき、ACCESSS TOKENを取得します。
・Google PhotosのアルバムIDに対してACCESS TOKENで認証し、JPEGをアップロードします。
・アップロードが終わったら、撮影日ごとにフォルダを作成してファイルを移動。
これをずーっとループでやっていきます。
まずは、Google APIの認証情報を取得します。Googleアカウント(Gmailアドレス)があることが前提です。
こちらに書いてあることをそのままやることで、Google Photos用の認証情報が全て得られます。
そう、パクりです。
デベロッパーコンソールにアクセスします。
https://console.developers.google.com
私は既に一度アクセスしているので、こんな画面になります。
おそらく、先に適当なプロジェクト名を指定しなければならないと思います。
私の場合はGooglePhotosAPIとつけていまして、上部に表示されています。
左側の「認証情報」をクリックします。
大きく青く「認証情報を作成」と出ていますね。ここから「クライアントIDの作成」を選びます。
アプリケーションの種類は「その他」を選び、適当な名前をつけます。
私の場合は「GooglePhotosUploader」とつけてみました。
「作成」を押します。
このように、クライアントIDとクライアントシークレットが取得できました。これをどこかにコピーしておきます。
(Googleデベロッパーコンソールサイト上でももう一度確認できます。)
続いては、Webサーバー上のでの作業です。
これこそ、先のtamanobiさんの記事の通りに実行します。
まずは、クライアントIDとクライアントシークレットを使ってオーソリゼーションコードを取得します。
私はGentoo Linuxをサーバに使っている変な人なので、Gentoo上で作業します。(といってもほとんどのLinuxディストリビューションで変わらない作業だと思いますが)
作業ディレクトリとして、/home/homephotoとしました。
ここにget_authorization_code.shという名前でtamanobiさんのスクリプトを作成します。
# mkdir /home/homephoto
# cd /home/homephoto
# nano get_authorization_code.sh
すみません。なんの芸もなく、tamanobiさんのスクリプトを引用させていただきます。
下記のYOUR_CLIENT_IDは、上記で取得したクライアントIDに置き換えてください。
CLIENT_ID="YOUR_CLIENT_ID"
REDIRECT_URI="urn:ietf:wg:oauth:2.0:oob"
SCOPE="https://picasaweb.google.com/data/"
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"
これは、認証ページにアクセスするためのURLを生成するスクリプトです。
実行権限を与えて、実行します。
# chmod +x get_authorization_code.sh
# ./get_authorization_code.sh
こんなURLが出てきます。
はい、このYOUR_CLIENT_IDの部分を書き換えてブラウザでアクセスしても同じことです。はい。
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=$CLIENT_ID redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://picasaweb.google.com/data/&access_type=offline
こんな画面が出てきますので、許可しましょう
許可を押すと、味気なくオーソリゼーションコードが表示されますので、どこかにコピペしましょう。
続いて、リフレッシュトークンとアクセストークンを取得します。
この2つのトークンのうち、リフレッシュトークンは明示的に変更をしない限り変わりませんが、アクセストークンの有効期限が3600秒です。
またまたtamanobiさんの記事をパクります。
スクリプトを作りましょう。
# nano get_access_token_and_refresh_token.sh
スクリプトの中身は次の通りですが、YOUR_CLIENT_ID、YOUR_CLIENT_SECRET、先ほど取得したオーソリゼーションコードをYOUR_CODEに入れ替えましょう。
CLIENT_ID="YOUR_CLIENT_ID" # クライアントID
CLIENT_SECRET="YOUR_CLIENT_SECRET" # クライアントシークレット
AUTHORIZATION_CODE="YOUR_CODE" # 認可コード
REDIRECT_URI="urn:ietf:wg:oauth:2.0:oob" # HTTPサーバを起動しなくてもAuthorization_Codeを取得できる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
で、実行権限を付与して実行します。
# chmod +x get_access_token_and_refresh_token.sh
# ./get_access_token_and_refresh_token.sh
そうするとJSON形式でリフレッシュトークンとアクセストークンが取得できます。
このリフレッシュトークンが大事になります。
そして、Google Photosの特定のアルバムにアップロードしたいので、アルバムIDを調べましょう。
ブラウザで次のURLにアクセスします。
USER_IDの部分はGoogleのユーザーIDに書き換えてください。ユーザーIDはGmailアドレスの@より前ですね。
https://picasaweb.google.com/data/feed/api/user/
USER_ID
そうすると、アルバムのリストが現れます。
アルバムのリンクURLを見ると、次のような法則になっています。
https://picasaweb.google.com/"Picasaのユーザー識別"/"アルバムID"?locked=true
このアルバムIDを控えておきます。
さて、ここからはオリジナルだったりtamanobiさんのスクリプトの改変だったりです。
まず、PQI AirCardの死活監視を行い、アクセスできたらFTPでJPGだけをGETします。
GETし終わったら、同じファイルをGETしないよう、GETしたファイルリストを作ります。
アクセストークンを取得し、JPEGファイルをGoogle Photosにアップロードします。
その後、exiftoolというアプリケーションを使って、年月日(YYYYMMDD)のディレクトリに分けて保存します。
というのを繰り返します。
お気づきの方もいらっしゃると思いますが、デジカメでファイルを連番で記録するようにしていると、XXX_9999.JPGの次は新しくディレクトリを作成し、たとえばDCIM/200CANONの次はDCIM/201CANONに保存されます。
もし10000枚目だとしたらあきらめてください((^^ゞ)
ちなみに、DCIM/200CANONディレクトリの中身を全て消去し、DCIM/201CANONのディレクトリ自体を消去すると、次からデジカメはDCIM/200CANONに撮影写真を保存していきます。
あと、なぜDCIM200CANONなのかというと、PQI AirCardにはDCIM/199WIFIという制御用ディレクトリがあるため、200CANONにしないと199WIFIに保存してしまいます。制御用のJPEGもダウンロードしてしまうことになるためです。
getophoto.shという名前のスクリプトにしました。
#/bin/bash
PQI_DIR="sd/DCIM/200CANON"
USER_ID="USER_ID"
CLIENT_ID="YOUR_CLIENT_ID"
CLIENT_SECRET="YOUR_CLIENT_SECRET"
REFRESH_TOKEN="YOUR_REFRESH_TOKEN"ALBUM_ID="YOUR_ALBUM_ID"
#自身のディレクトリに移動
cd `dirname $0`#プロセス番号をpid.txtに保存
echo $$ > pid.txt
#ここからループ
while :
do
#PQI AirCarにhttp出来るかどうか試す
ALIVE=$(/usr/bin/wget -nv --spider --timeout 60 -t 1 http://${PQI_AIR_IP}/ 2>&1 | grep -c '200 OK')
#PQI AirCadが生きていた場合の処理
if [ $ALIVE -eq 1 ]; then
#過去にGETしたJPGファイルのリストdonelist.txtを読み込む。念のため改行を削る
DONELIST=`cat donelist.txt | sed -e ':loop; N; $!b loop; s/\n//g'`
#FTPでJPGをGET
/usr/bin/wget -m -q -N --reject=${DONELIST} --no-host-directories --no-directories -A .JPG ftp://${PQI_AIR_IP}/${PQI_DIR}
#GETしたJPGを改行などを削除してdonelistに保存
JPGLIST=`/bin/ls | grep .JPG`
if [ -n "$JPGLIST" ]; then
/bin/echo "," >> donelist.txt
/bin/ls | grep .JPG | sed -e ':loop; N; $!b loop; s/\n/,/g' >> donelist.txt
sed -i -e ':loop; N; $!b loop; s/\n//g' donelist.txt
fi
#アクセストークン取得
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'`
ENDPOINT="https://picasaweb.google.com/data/feed/api/user/${USER_ID}/albumid/${ALBUM_ID}?access_token=${ACCESS_TOKEN} "
DIR="./" # FTPでGETしたJPGファイルが保存してあるディレクトリを指定
IFS_BAK=${IFS}
IFS="
"
#ファイル数だけループ
FILES=`ls -1 ${DIR}`
for FILE in ${FILES}
do
#MIMEタイプの指定
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
LENGTH=`ls -l "${DIR}/${FILE}" | tail -n1 | sed -E 's/ +/ /g' | cut -d' ' -f5`
#ファイルをアップロード
curl -s -XPOST "${ENDPOINT}" \
-H "Content-Type:${TYPE}" \
-H "Content-Length:${LENGTH}" \
-H "Slug:${FILE}" \
--data-binary "@${DIR}/${FILE}" > /dev/null
sleep 1
fi
done
IFS=$IFS_BAK
#ファイルのアップロードが全て終わったら、撮影日でYYYYMMDDというディレクトリを作ってファイルを移動
/usr/bin/exiftool -q '-Directory < CreateDate' -d %Y%m%d *.JPG
fisleep 10
done
これも実行権限をつけて実行しましょう。
chmod +x getophoto.sh
./getophoto.sh &
これで、サーバーと同じネットワークセグメントにいる限り、つまり、室内では、撮影する度にGoogle Photosの指定したアルバムにアップロードされます。
たしかGoogle Photosの仕様で、1アルバム1000枚までしか保存できないはずですので、上限に達したら新しいアルバムに変えましょう。