PythonでGoogle Photos APIを使う

![HW Raspberry Pi 4 Model B Rev 1.4](https://img.shields.io/badge/HW-Raspberry Pi 4 Model B Rev 1.4-brightgreen) ![OS-Ubuntu 20.04.1 LTS](https://img.shields.io/badge/OS-Ubuntu 20.04.1 LTS-brightgreen) ![Python-3.8.7](https://img.shields.io/badge/python-3.8.7-brightgreen) 


# はじめに

PythonでGoogle Photos APIを叩こうと思ってネットを調べていたところ、google-api-python-clientのバージョンが2になっていたため上手く動かずに時間を使ってしまったので、記事投稿時点で動くコードを上げておく。
事前にGoogle Photos APIを有効化し、OAuth 2.0 Clientを作成してclient_secret.jsonを取得しておく必要がありますが、ここでは割愛します。

# エラー

下記のようなコードでphotoslibraryを叩こうとすると、
buildのところでコケる。

``` python:sample.py
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build

SCOPES = ["https://www.googleapis.com/auth/photoslibrary"]
API_SERVICE_NAME = "photoslibrary"
API_VERSION = 'v1'
CLIENT_SECRET_FILE = './secret/client_secret.json'

creds = InstalledAppFlow.from_client_secrets_file(
            CLIENT_SECRET_FILE, SCOPES).run_local_server()

with build(API_SERVICE_NAME, API_VERSION, credentials=creds) as service:
    print(service.albums().list(pageSize=50).execute())
```

何やらこんなAPIは知らんと怒られた。
Google Photos Libraryはgoogle-api-python-clientで定義されていないようだ。

```
googleapiclient.errors.UnknownApiNameOrVersion: name: photoslibrary  version: v1
```

# 結論

version 2.0.0以降は、指定しない場合デフォルトでライブラリ内を見るように変更されていた。GooglePhotosLibraryはローカルでは見つからないので、インターネット経由でDiscoveryかけるようにbuild時に<b>static_discovery=False</b>を指定してあげればよい。

下記はGoogle Photos APIを叩いてアルバムのリストを取得して表示するサンプル。

``` python:sample.py
import pickle
from pathlib import Path

from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build

SCOPES = ["https://www.googleapis.com/auth/photoslibrary"]
API_SERVICE_NAME = "photoslibrary"
API_VERSION = 'v1'
CLIENT_SECRET_FILE = './secret/client_secret.json'
TOKEN_PICKLE = "./secret/token.pickle"

def get_authenticated_service() -> object:
    if Path(TOKEN_PICKLE).exists():
        # TOKENファイルを読み込み
        with open(TOKEN_PICKLE, "rb") as token:
            creds = pickle.load(token)
        if creds.valid:
            return creds
        if creds and creds.expired and creds.refresh_token:
            # TOKENをリフレッシュ
            creds.refresh(Request())
    else:
        # TOKENファイルがないので認証フローを起動する(Default: host=localhost, port=8080)
        creds = InstalledAppFlow.from_client_secrets_file(
                    CLIENT_SECRET_FILE, SCOPES).run_local_server()

    # CredentialをTOKENファイルとして保存
    with open(TOKEN_PICKLE, 'wb') as token:
        pickle.dump(creds, token)

    return creds

def main():
    with build(API_SERVICE_NAME, API_VERSION, credentials=get_authenticated_service(), static_discovery=False) as service:
        print(service.albums().list(pageSize=50).execute())

if __name__ == "__main__":
    main()
```

# google-api-python-clientのv1系とv2系の違い

MigrationGuideにBraking Changeとして明記されている。
下記は該当箇所の抜粋

### v1系
``` 
from googleapiclient.discovery import build

# Retrieve discovery artifacts from the internet
with build('drive', 'v3') as service:
```
### v2系
```
from googleapiclient.discovery import build

# Retrieve discovery artifacts from the client library
with build('drive', 'v3') as service:
    # ...

# Retrieve discovery artifacts from the internet
with build('drive', 'v3', static_discovery=False) as service:
    # ...
```
https://github.com/googleapis/google-api-python-client/blob/master/UPGRADING.md