LINEBotから送られてきた動画をGoogle Apps ScriptでバイナリのままYouTubeにアップロードする。

デカい学びになったのでメモて程度に。
こんにちは。マグロです。

前にPythonでLINEの動画オウム返しBotを作成していましたが、今回はGASを利用してオウム返しします。

https://qiita.com/maguro-alternative/items/7c9f1d3024bec6082ff0

# 経緯
前回上げた画像オウム返しBotは、バイナリデータを直接アップロードすることでオウム返しを実現しました。

https://qiita.com/maguro-alternative/items/57a8781fdf2b2ef41a3e

この時はバイナリデータからはすげーなーって思ってたのですが、リファレンス内の```multipart/form-data```の形式が気になったので調べることにしました。
何でも複数のデータを扱えるHTMLフォームの形式らしく、ファイルはバイナリデータで送られてくるとのこと。
なるほど、これを想定しているからバイナリデータを扱えるのか。

ん？じゃあ他のアップロードサービスはどうなんだろう？？
例えば、YouTubeとかは、、、、？

https://developers.google.com/youtube/v3/docs/videos/insert?hl=ja

> 利用可能なメディアの MIME タイプ: video/*、application/octet-stream

お、バイナリデータから直接アップロードできるっぽい。
サンプルコードはPythonやJavaなどから動画ファイルをアップロードしていますが、見た感じバイナリデータには変えてそうです。

確かGASでもYouTube Data APIを使えたはずなので、これは行けるのでは？？

# 設計
Google Apps Scriptを使用します。
GASでLINEBotを動かす説明は省略します。
GASでYouTube Data APIを使用するので、サービスの+をクリックして導入しておきましょう。
また、LINE以外のAPIの申請は特に必要ありません。

https://developers.line.biz/ja/reference/messaging-api/#get-content

送られてきたバイナリデータを取得する際、messageIdをURLに含めてリクエストして取得します。
```
GET https://api-data.line.me/v2/bot/message/{messageId}/content
```

取得した動画バイナリを```YouTube.Videos.insert```でアップロードします。

レスポンスとして、下記リンクのようなjsonが返ってきます。

https://developers.google.com/youtube/v3/docs/videos?hl=ja#resource

ここの動画idをURLに当てはめ、動画リンクをLINEに返信します。

# コーディング
```js:main.gs
//LINEBotのトークン
const LINE_CHANNEL_ACCESS_TOKEN = ""
function doPost(e) {
  try{
    // LINEBotから送信されたメッセージを取得
    const message = JSON.parse(e.postData.contents).events[0].message;

    // LINE Messaging APIから動画ファイルを取得
    const contentUrl = 'https://api-data.line.me/v2/bot/message/' + message.id + '/content';
    const videoBlob = UrlFetchApp.fetch(contentUrl, {
      headers: {
        'Authorization': 'Bearer ' + LINE_CHANNEL_ACCESS_TOKEN
      }
    });

    // YouTubeに動画をアップロード
    const video = YouTube.Videos.insert(
      {
        snippet: {
          title: 'LINEBotからの動画',
          description: 'LINEBotから送信された動画です。'
        },
        status: {
          //"public"で公開、 "private"で非公開、 "unlisted"で限定公開
          privacyStatus: 'private'
        }
      },
      // 動画をアップロードする際のパラメータ。snippetはタイトルや説明、statusは公開範囲の指定
      'snippet,status',
      // 動画のバイナリデータ
      videoBlob.getBlob()
    );

    // アップロードした動画のURLを取得
    const videoUrl = 'https://www.youtube.com/watch?v=' + video.id;

    // LINEBotに動画のURLを返信
    const replyToken = JSON.parse(e.postData.contents).events[0].replyToken;
    UrlFetchApp.fetch('https://api.line.me/v2/bot/message/reply', {
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + LINE_CHANNEL_ACCESS_TOKEN
      },
      method: 'post',
      payload: JSON.stringify({
        replyToken: replyToken,
        messages: [{
          type: 'text',
          text: '動画をアップロードしました。'
        }, {
          type: 'text',
          text: videoUrl
        }]
      })
    });
  }catch(e){
    if(e=="TypeError: Cannot read properties of undefined (reading 'contents')") return 
    return
  }
}
```

コーディングが終わったらデプロイします。
その際に認証が必要になります。認証することで自動的にYouTubeAPIの申請が完了し、GASからのアップロードが可能になります。
また、トリガーとLINE側のWebHookの設定もお忘れなく。

# 完成！！
動画を送信しましょう。
LINEの上限である5分の動画もアップロードできるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2853914/19354cdf-234f-e603-d70b-109c4f9f7b77.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2853914/e573b8b1-85bc-7fa7-6fde-faaba7099ebf.png)

# あとがき
いやぁほんとYouTubeとGASってすごいなぁって思います。
アップロードのスクリプトがこんなに簡単に作れるのは衝撃でした。
加えてGCPでの認証なしでこういったことができるのも魅力だと思います。

また、バイナリデータから直接アップロードできることが分かったので、「DiscordとLINEの連携」のLINEからDiscordへの動画は一旦作り直して後日記事にしたいと思います。

それではまた次回の記事でお会いしましょう。