GASでYouTubeの動画を時間指定で限定公開・非公開にする

本記事は2025/01/20現在の情報です。実行時は自己責任でお願いいたします。

# 前置き
YouTubeでは、動画をアップロードした後の公開・非公開・限定公開を切り替えできます。
スケジュールで公開することもできますが、限定公開・非公開をスケジュールで切り替えることは現時点ではできません。
![スクリーンショット 2025-01-20 110431.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/7e331718-c642-9282-3354-73a3e167d2f7.png)

そこで、限定公開・非公開をスケジュールで切り替えたい皆さんのため、GASで切り替える方法を開発しましたので共有いたします。
なかなか調べても出てこなかったので、Googleのドキュメンテーションを調べてやっとできました。
比較的需要がありそうなので、分かりやすくまとめました。
最後までご閲覧いただけますと幸いです。

# GASについて
GAS（Google App Script）は、Googleのあらゆるサービスやアプリをスクリプトで操作できるサービスです。
GAS自体がスクリプト言語としても扱われますが、基本的な文法はJavaScriptと同様です。

# 公開・非公開を操作する方法
それでは公開・非公開を操作する方法を紹介します。
以下の環境を前提とします。
- Gmailアカウント（~@gmail.com / Workspaceアカウント）を所持していること
- そのGmailアカウントがYouTubeチャンネルを所持していること
- 動画を投稿していること

## 1. GASにアクセスする

以下のサイトにアクセスします。

https://script.google.com/home

Googleアカウントのログインを求められたら、任意のアカウントでログインします。

## 2. GASの新しいプロジェクトを作成

ホーム画面が開いたら、GASの新しいプロジェクトを作成します。
左上のボタンを押して作成します。
![スクリーンショット 2025-01-20 110657.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/642748d4-3df1-3072-0dc5-6a78e0b4945f.png)

## 3. プロジェクト名を変更

新しく作成するとコードの画面になります。
左上のプロジェクト名を変更できますので、分かりやすい名前にしましょう。
![スクリーンショット 2025-01-20 111044.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/7dce3001-b7de-68d8-911b-7f6bcb2a5f9a.png)

## 4. YouTube Data API v3を有効化にする
YouTube Data API v3（アプリを操作するツール）が使えるように設定します。
左のサービスの隣の「+」マークを押します。
![スクリーンショット 2025-01-20 111432.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/2908e15f-d50b-1e4f-2331-f14232aac214.png)

サービスを追加から、「YouTubeData API v3」を選択し、バージョンをv3、IDを「YouTube」にします。
![スクリーンショット 2025-01-20 111539.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/e911a45f-3d67-0355-2fc4-ecd62b674a95.png)

サービスに「YouTube」と表示されたら準備完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/7120a78c-faaa-ea99-3b28-856e95d7a587.png)

## 5. コードを書く
今回、サンプルコードを用意しましたので、まずはそのままコピー＆ペーストしましょう。

```js
// 指定された動画IDの公開・非公開を設定するコードです
function updateYouTubeStatus(youTubeId, inputPrivacyStatus) {
  try {
    // youTubeIdを用いて動画情報を取得します
    let ym = YouTube.Videos.list(["status"], { "id": youTubeId });

    // IDで取得できた動画の1個目を取得します
    let yitem = ym.items[0];

    // 公開情報を指定されたものに変更します
    yitem.status.privacyStatus = inputPrivacyStatus;

    // 変更を反映します
    let yresult = YouTube.Videos.update(yitem, ["status"]);

    // 実行状況ログを出力します
    console.log('実行に成功しました。ログをご確認ください。');
    console.log(yresult);
  } catch (e) {
    // エラーが発生した場合はログを出力します
    console.error('公開・非公開設定が失敗しました。引数の入力内容に誤りがないかご確認ください。YouTubeの稼働状況により失敗する可能性があります。');
    console.log(e);
  }
}

// 呼び出し用の関数（後のトリガー設定に必要です）
function youtubeURLOpenTest() {
  updateYouTubeStatus('XXXXXXXXXX', 'unlisted');
}
```
## 6. 呼び出し用関数の設定方法
呼び出し用関数は、後の実行設定に必要なコードです。
引数の1番目：YouTube動画URLの `https://youtu.be/XXXXXXX` の XXXXXXX の部分）
引数の2番目：公開は `public` 、非公開は `private` 、限定公開は `unlisted` と指定します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/fcba0605-00a5-28b9-3de5-3aeea4892c38.png)

 ※ 複数作りたい場合は、最下部に上記と同じコードを複製し、関数名（「youtubeURLOpenTest」の部分）を被らないように設定してください

## 7. 保存する
コードができたら保存しましょう。
上部の保存ボタンを押すか、ショートカットキー `Ctrl + S` を押しましょう。
![スクリーンショット 2025-01-20 114133.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/806c5bdd-a03f-c783-dda9-23668c3bfe6e.png)

## 8. テスト実行する
設定した関数がしっかり実行できているか確認します。
まずは上部からテストする関数を選択します。
![スクリーンショット 2025-01-20 114448.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/28a51600-651a-91a9-8b5c-ca9d012c14dd.png)

次に横の「実行」を押します。
![スクリーンショット 2025-01-20 114553.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/c2078226-c4a5-3b3a-4544-4840311ea5f4.png)

最初の実行は承認が必要です。「権限を確認」を押してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/188ce2a7-2cac-f58b-9de4-c471001de01d.png)

ユーザーを選択します。
![スクリーンショット 2025-01-20 114916.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/2b0f0108-3ef2-e3ad-e729-df0d3afdb97c.png)

この画面が出ても問題はありません。詳細を押します。
![スクリーンショット 2025-01-20 115012.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/ca485f60-6800-a44d-15fa-82cec5708d81.png)

詳細の下の「○○に移動」を押します。
![スクリーンショット 2025-01-20 115056.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/d56953ef-22be-6fd7-919c-b8def18e65cb.png)

この画面が出たら、「続行」ボタンを押します。
![スクリーンショット 2025-01-20 115324.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/39a9f90b-0571-3a7d-afad-f1b819a98611.png)

実行され、実行ログに「実行に成功しました」と表示されたら完了です。
![スクリーンショット 2025-01-20 120434.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/ed1bd789-114b-b8ad-52b6-b7ba9c6c155e.png)

YouTubeにも限定公開にされているのがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/4a611c1e-ec99-2a05-650f-02b4ca212a49.png)


# 実行設定
組み立てたコードをもとに実行設定をしましょう。

## トリガー設定
左のメニューから「トリガー」を選択します。
![スクリーンショット 2025-01-20 114413.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/812450ac-8ed2-8f89-43a6-1dc7c3de1508.png)

右下のトリガーを追加するボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/eeb9d751-d171-d869-15d2-98c794a895cd.png)

以下のような設定にして、「保存」を押します。
![スクリーンショット 2025-01-20 134346.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/8d9d33e6-a755-761f-3fbf-16802e0a6e47.png)

このようにして、トリガーは設定することができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/7faf158c-3f9a-40b3-5aee-bb382275d6d6.png)

 ※ 必ずしもその時間に公開状態が変わることを保証できないため、設定時間より1分早めに設定することをおすすめします。

## 実行後の様子
実行後は以下のような画面になります。
「前回の実行」が無効になっていて、「エラー率」が0%になっていると、実行は成功しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/78f4b235-b00a-2404-3bb8-d75c9c57e323.png)

# 仕組みについて
## 全体像
大まかな処理の流れは以下のような形です。
![s.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990230/c73cfb0c-8337-d59e-31c2-84095a86c9b5.png)

## YouTube.Videos.list
動画情報を取得します。

```js
YouTube.Videos.list([part, ...], { option })
```
`YouTube.Videos.list`は、特定条件に則り、チャンネル内の動画の検索及びリストを返します。
このコードによる返却値は、成功の場合は以下の形式で返されます。
```json
{
  "kind": "youtube#videoListResponse",
  "etag": etag,
  "nextPageToken": string,
  "prevPageToken": string,
  "pageInfo": {
    "totalResults": integer,
    "resultsPerPage": integer
  },
  "items": [
    video Resource
  ]
}
```
JSON形式で返される値から、item内の動画情報 `Videos` を取得しています。

## Videos
取得した動画情報オブジェクト `Videos` は、動画に関する様々な情報を扱っています。
ここで紹介すると長いため、オブジェクトの詳細は以下のドキュメンテーションから参照してください。

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

このオブジェクトは取得したら書き換えが可能なため、内容を上書きしてから `update` メソッドを実行します。

## YouTube.Videos.update
動画情報を指定したオブジェクトで更新します。

```js
YouTube.Videos.update(Videos, [part, ...])
```

ただし、書き換えできる情報には限りがありますので、詳しくは以下のページのリクエスト本文をご確認ください。

https://developers.google.com/youtube/v3/docs/videos/update?hl=ja#request-body


# 注意事項
- 実行するユーザー（スクリプトを所有するユーザー）は、**動画をアップロードしたチャンネルの管理ユーザー**と同じである必要があります。
- 動画をアップロードした本人以外がスクリプト上で公開・非公開を設定することはできません（APIの特性上）。
- もし作成するユーザーを誤った場合は、ユーザーを切り替えて再度作成して実行してください。

# まとめ
今回はAPIで呼び出しできるスクリプトを紹介しました。
YouTube Data APIは、公開設定のほかにも、タイトル・説明文・翻訳文章等変えることができます。
開発者の皆さんは、ぜひYouTube Data APIの構造体に触れてみてはいかがでしょうか？

# 関連ページ

YouTube Data APIの概要

https://developers.google.com/youtube/v3/getting-started?hl=ja

Videos構造体の詳細

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