Google Drive上の画像（のサムネイル）URLを取得する方法

2020/11/20 追記: 以下の方法は、どれも割とすぐに URL が Expire するので、恒久的に使いたい場合には使えないです。

## Google Driveの画像をどうしてもGoogle Chatに投稿したかった

Google Apps Script で、SpreadSheet を読み込んで、そこに書かれたテキストや Google Drive に格納された画像ファイルをいい感じにまとめて Google Chat にポストしたかった。
全部 Google だし、楽勝だろうと思っていたが、Google Drive の画像がなかなか表示できなかった。

ググると、Share URL にパラメータをつければ見れる！みたいなことがそこらじゅうに書いてあったが、どれもうまく行かなかった。たぶん、かつてはうまく行っていたんだろうと思う。
そこで、まずは素直に DriveApp を使ってみた。

> [Class File](https://developers.google.com/apps-script/reference/drive/file)

が、DriveApp で取得できる URL は、そのままでは Chat ではうまく表示できない URL（getUrl メソッド）か、ダウンロードが始まる URL（getDownloadUrl メソッド）だけで、欲しいものではなかった。

最終的に、Google Drive API v3 を利用して、サムネイル画像をなんとか引っ張ってきて表示することができた。サムネイルだけなのは、AWS S3 みたいに画像ストレージとしては使えないよってことなんだろうと理解した。

この記事は「サムネイルじゃダメなんだ！」という方の参考にはならない。

## 手っ取り早く1つのファイルのリンクだけ取得する

1つだけ分かれば良いという人は、ここ([Files: get](https://developers.google.com/drive/api/v3/reference/files/get))に行って、fields に thumbnailLink と入れて実行すれば良い。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245908/fad93a1b-f737-fea9-2751-fcb2a74fdf13.png" width="400" alt="Try this API">

その他の値は、ここ（[Files](https://developers.google.com/drive/api/v3/reference/files)）に、どんなものが返ってくるか書いてあるので、それを参考に。



## Google Drive API

まずは、Google Drive API を使えるようにする。
最初に、Google Apps Script の Editor のメニューで、Resources > Advanced Google Serviceにて、Drive API を On にする。
次に、Token を取得する。

> [Google API OAuth2.0のアクセストークン&リフレッシュトークン取得手順 2017年2月版](https://qiita.com/iwaseasahi/items/2363dc1d246bc06baeae)

3年前の記事で、画面が色々と変わっていたが、だいたいこの手順でできた。

```json
{
  "access_token": "ya29.A0A...",
  "expires_in": 3599,
  "refresh_token": "1//0e5...",
  "scope": "https://www.googleapis.com/auth/drive",
  "token_type": "Bearer"
}%
```

こんなようなものが返ってくる。割とすぐ Expire しちゃうので、アプリケーション内で使う場合は、リフレッシュする仕組みも実装しておかないといけない。
refresh_token はどれくらいで Expire するのか分からないが、6ヶ月くらいらしい。

> [アプリで「ログインしっぱなし」はどのように実現されているか？](https://qiita.com/yosshi4486/items/7ec5fdd53577c8663603)

ここにあるように、refresh_token も毎回取り替えるのが良いようだ。Google Apps Script だと…と悩ましいところではあるが、まぁ美しくなくてもなんとかなるだろう。今回は省略。


## Google Apps Script

```javascript
function getDriveImageUrlById(id) {
  const accesstoken = "ya29.A0A...";
  const fetchUrl = "https://www.googleapis.com/drive/v3/files/" + id + "?fields=thumbnailLink";
  const option = {
    "method": "GET",
    "headers": {
      "Authorization": "Bearer " + accesstoken,
      "Accept": "application/json",
    }
  }
  var response = UrlFetchApp.fetch(fetchUrl, option);
  var result = JSON.parse(response);
  return result["thumbnailLink"];
}
```

Token の取り替えは一旦忘れると、こんな感じにすればサムネイルの URL が取れる。
Option は、前述の Try this API を実行すると出てくる curl コマンドの例で、API key を無視したものになっている。他の言語でも同様のことをすれば良い。

Google Drive API の戻り値は、

```json
{
  "thumbnailLink": "https://..."
}
```

という感じで、Object で返ってくるので、そのままプロパティにアクセスできるかと思ったが、parse しないとアクセスできなかった。なんか、このあたりの扱いはいまいち良く分かっていない。

ともあれ、サムネイルの URL が取得できたので、Cards のフォーマットに整形する。

> [Card Formatting Messages](https://developers.google.com/hangouts/chat/reference/message-formats/cards)

フォーマットはここを見ながら。

```javascript
function getCard(title, image, text) {
  return {
    "cards": [
      {
        "header": {
          "title": title,
          "subtitle": "Holiday Knowledge Sharing",
          "imageUrl": "https://....",
          "imageStyle": "IMAGE"
        },
        "sections": [
          {
            "widgets": [
              {
                "image": {
                  "imageUrl": image
                }
              }
            ]
          },
          {
            "widgets": [
              {
                "textParagraph": {
                  "text": text
                }
              }
            ]
          }
        ]
      }
    ]
  }
}
```

## 結果と余談

上記の実行結果ではないが、結果として、こんなようなものが Google Chat にポストされる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245908/041f8942-c825-ba5d-1bc8-7f914cf4abfd.png" width="400" alt="Card">
今回の内容は、私の会社は、日本とベトナムにオフィスがあり、お互いの国の祝日の情報をシェアしようという企画で作った。

Globalization の流れの中、大事だと思うのは言葉、ではなく、やはりカルチャーの相互理解である。言葉が理解出来ても、コンテキストおよびそのコンテキストが成立し得る背景が分からないと、全然何いってるのか分からないということは、しょっちゅうある。なので、こういうのは割と効く。

おしまい。