Youtube Data APIでNode.jsから動画をアップロードする


Youtubeへの動画アップロードの自動化を行いたいなと思って調べてましたが、ある程度まとまってきたので記事にしてみます。

調べてもあまり実装サンプルが見当たらないですね、Youtubeに動画をアップロードするサンプルは調べてすぐ出てくるものが古いものが多くて調べるのに苦労した感あります苦笑

未来の自分やどなたかの参考になれば幸いです。

## Youtube Data API

Youtubeは

* Player API
* Data API
* Analytics API
* Live Streaming API

などに大きく分けられるみたいです。

> 参考: [YouTube Developer Documentation](https://developers.google.com/youtube/documentation?hl=ja)

その中でもData APIが動画アップロードに関連します。

[こちら](https://developers.google.com/youtube/v3/getting-started?hl=ja)がYoutube Data API(v3)のページです。

## 環境

* Node.js v16.0.0

出たばかりですね〜

> https://twitter.com/bethgriggs_/status/1384540641007448065?s=21

## 実装手順

基本的には他のGoogle API系と同じです。

> [Google DriveのAPIをNode.jsから触るメモ](https://qiita.com/n0bisuke/items/4af8f17fb4fe3b9b4831)

### credentials.jsonを取得

チュートリアルを参考にAPIを有効にし、credentials.jsonを手元に保存しましょう。

> https://developers.google.com/youtube/v3/quickstart/nodejs

執筆時点のこちらのチュートリアルだと、`client_secret.json`というファイル名になっていますが、`credentials.json`にリネームします。

### google-auth-token-generatorでtoken.jsonを作成

```bash
$ npx google-auth-token-generator@0.0.11
```

Youtubeを選択します。

> ![スクリーンショット 2021-04-21 22.21.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/8453d6f9-4d79-87fe-eaaf-5ec45608c5df.png "スクリーンショット 2021-04-21 22.21.51.png")

**`youtube.readlonly`以外**を選択します。（アップロードするときはreadonlyにチェックを入れるとパーミッションエラーで怒られます。）

> ![スクリーンショット 2021-04-21 22.23.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/39fd22ad-73b2-d659-9f6e-4e20eebab018.png "スクリーンショット 2021-04-21 22.23.30.png")

認証用のURLが発行されるのでブラウザでアクセスしましょう。

> ![スクリーンショット 2021-04-21 22.24.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/e28a6754-6233-089d-6a01-fdb3bb783f71.png "スクリーンショット 2021-04-21 22.24.59.png")

ブラウザでアカウントなどを選択して進み、許可ボタンを押します。

> ![スクリーンショット 2021-04-21 22.26.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/625076dc-bf86-ab44-5a5a-7134191b43c0.png "スクリーンショット 2021-04-21 22.26.14.png")

コードが発行されるのでコピーして、ターミナルに戻ってコードを貼り付けます。

> ![スクリーンショット 2021-04-21 22.27.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/fc7e7adf-0df6-868b-de31-8039a887d302.png "スクリーンショット 2021-04-21 22.27.20.png")

そうすると`token.json`が発行されます。

### 動画をアップロードするコード

公式のupload.jsサンプルはこちらです。これを参考にサンプルを作成しています。

> https://github.com/googleapis/google-api-nodejs-client/blob/master/samples/youtube/upload.js

```upload.js
'use strict';

const fs = require('fs');
const readline = require('readline');
const {google} = require('googleapis');

const googleAuth = () => {
    const CREDENTIALS_PATH = 'credentials.json';
    const TOKEN_PATH = 'token.json';  
    const credentials = JSON.parse(fs.readFileSync(CREDENTIALS_PATH, 'utf8'));
    const token = JSON.parse(fs.readFileSync(TOKEN_PATH, 'utf8'));

    const {client_secret, client_id, redirect_uris} = credentials.installed;
    const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]);
    oAuth2Client.setCredentials(token);

    return oAuth2Client;
};

(async () => {
    const auth = googleAuth();
    const youtube = google.youtube({version: 'v3', auth});
    console.log(youtube.channels)
    try {
        const fileName = 'tanaka.mov'; //アップロードする動画ファイル名

        const fileSize = fs.statSync(fileName).size;
        const res = await youtube.videos.insert(
            {
              part: 'id,snippet,status',
              notifySubscribers: false,
              requestBody: {
                snippet: {
                  title: 'Node.js YouTube Upload Test',
                  description: 'Testing YouTube upload via Google APIs Node.js Client',
                },
                status: {
                  privacyStatus: 'private',
                },
              },
              media: {
                body: fs.createReadStream(fileName),
              },
            },
            {
              // Use the `onUploadProgress` event from Axios to track the
              // number of bytes uploaded to this point.
              onUploadProgress: evt => {
                const progress = (evt.bytesRead / fileSize) * 100;
                readline.clearLine(process.stdout, 0);
                readline.cursorTo(process.stdout, 0, null);
                process.stdout.write(`${Math.round(progress)}% complete`);
              },
            }
          );
          console.log('\n\n');
          console.log(res.data);
          return res.data;

    } catch (error) {
        console.log('The API returned an error: ' + error);
    }
})();
```

実行

```bash
$ node upload.js
```

## 無事にアップロードできた

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Node.jsからYoutubeに動画をアップロードするテストいけたっぽい <a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://t.co/MAWtv3GgyM">pic.twitter.com/MAWtv3GgyM</a></p>&mdash; 菅原のびすけ (@n0bisuke) <a href="https://twitter.com/n0bisuke/status/1383348268780834819?ref_src=twsrc%5Etfw">April 17, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

タイトルだったりは適宜コードを変更すればいけそうですね。

## 所感

チュートリアルのサンプルが、Google Driveなどのサンプルより絶妙に古いのと、APIを有効にした際のウィザードが少し他のAPIとフローが違っていて、YoutubeのAPIの独特さを感じました。

元々別だったけど統合していこう、、、みたいな流れなのかマージ途中な雰囲気を感じるという苦笑