YouTube Data APIで動画をアップロードするには、Google CloudでOAuthクライアントを作り、一度ブラウザで許可してトークンを保存したうえで、videos.insertに動画ファイルとタイトル・公開範囲を渡します。この記事では、Claude Codeと一緒にPythonでこの処理を組み、サムネイルの設定、再生リストへの追加、予約公開、夜間の自動実行まで動かした手順を紹介します。
APIでのアップロードは、公式のサンプルを動かすところまでは難しくありません。つまずくのはその先です。認証が数日で切れる、別のチャンネルに上げそうになる、サムネイルだけ403で失敗する、途中で止まって再実行したら同じ動画が2本になる、といったことが、自動で回し始めてから起こります。
筆者は2026年10月に、この記事のスクリプトで本編の動画2本をアップロードして公開し、ショート1本を予約公開しました。仕様の数値と記述は、2026年10月19日にGoogleの公式ドキュメントで確認したものです。チャンネルIDなどの識別子は、すべて例の値に置き換えています。
全体の流れ|6つの工程を1本のスクリプトにする
APIでのアップロードは、準備・認証・アップロード・サムネイル・再生リスト・公開の6工程に分かれます。このうちGoogle Cloudの準備と初回の許可だけは手作業で、残りはスクリプトで自動にできます。
| 工程 | やること | 使うAPI・手段 | 自動にできるか |
|---|---|---|---|
| 1. 準備 | APIの有効化・OAuth同意画面・OAuthクライアントの作成 | Google Cloudコンソール | 手作業(最初の1回) |
| 2. 認証 | ブラウザで許可してトークンを保存 | google-auth-oauthlib | 初回と再認証のときだけ手作業 |
| 3. アップロード | 動画ファイルとタイトル・説明・公開範囲を送る | videos.insert | 自動 |
| 4. サムネイル | カスタムサムネイルを設定 | thumbnails.set | 自動 |
| 5. 再生リスト | 再生リストに追加 | playlistItems.insert | 自動 |
| 6. 公開 | 非公開のまま確認して公開、または予約公開 | YouTube Studio/videos.update | 予約公開は自動、即時公開は人が押す |
工程3〜6のスクリプトはClaude Codeに書かせました。工程1と2の画面操作は自分で行います。Claude Codeに外部のアプリを直接操作させる別の例は、ClaudeでPhotoshopを操作する方法で紹介しています。
先に決めておく運用ルール|非公開でアップして公開は人が押す
スクリプトを書く前に、公開範囲と申告の扱いを決めておくと、自動化してから慌てずに済みます。筆者は次の3つを先に決めました。
- アップロードは必ずprivate(非公開)で行い、公開ボタンは人がYouTube Studioで押す。予約公開するものだけ、公開日時をスクリプトで入れる
- 生成AIなどで作った、現実と見分けにくい内容を含む動画は、アップロード時にcontainsSyntheticMediaで申告する
- 公開範囲や申告の値はコードに直接書かず、動画ごとの設定ファイル(metadata.json)から読む
privacyStatusを指定しないと、動画は公開(public)でアップロードされます。videos.insertのリファレンスにも「指定しない場合の既定はpublic」と書かれています。テスト中に間違って公開しないよう、privateを明示してください。
containsSyntheticMediaは、YouTube Data APIの変更履歴によると2024年10月30日に追加された項目です。videosリソースのリファレンスでは「チャンネル所有者が、現実と見分けにくい改変・合成コンテンツを含むことを申告するもの」と定義されています。AIで動画を作る手順はAI動画のカット割りの作り方にまとめています。
Google Cloudの準備|APIの有効化とOAuthクライアント
Google Cloudでは、プロジェクトを作ってYouTube Data API v3を有効にし、OAuth同意画面とOAuthクライアントを用意します。画面の操作は次の順番です。
- Google Cloudコンソールでプロジェクトを作る
- 「APIとサービス」からYouTube Data API v3を有効にする
- OAuth同意画面を作る。ユーザーの種類は「外部」、公開ステータスは最初はテストにする
- テストユーザーに、アップロード先のチャンネルを持っているGoogleアカウントを追加する
- 認証情報からOAuthクライアントIDを作る。アプリケーションの種類は「デスクトップアプリ」
- JSONをダウンロードし、
secrets/client_secret.jsonとして保存する
個人のチャンネルでは、サービスアカウントではなくユーザーのOAuth認証を使います。インストール型アプリの認証ガイドは、YouTube Data APIがサービスアカウントに対応するのは複数チャンネルを所有・管理するコンテンツ所有者だけだと説明しています。
テストのままだと、7日ごとに再認証が必要になります。筆者はテストで動作を確かめてから本番に切り替えました。手順は後の「テストから本番へ」の節で説明します。
Claude Codeへの頼み方|条件を先に書いて渡す
Claude Codeには、何を作るかだけでなく、止まる条件と秘密情報の置き場所まで最初に書いて渡します。あとから足すと、二重アップロードの防止やチャンネルの照合が抜けやすくなるためです。次のように書いて渡すと、必要な条件が最初から入ります。
YouTube Data API v3 で動画をアップロードするPythonスクリプトを scripts/upload.py に作って。
- 認証はOAuth(デスクトップアプリ)。secrets/client_secret.json を読み、トークンは secrets/token.json に保存(権限は600)。secrets/ は .gitignore に入れる
- 公開範囲は private 固定。公開は自分がYouTube Studioで押す
- アップロードの前に channels.list(mine=true) で送り先のチャンネルIDを照合し、違っていたら止める
- 再開可能なアップロードにして、動画IDはすぐ uploaded.json に書く(再実行で二重にアップしない)
- --no-browser を付けたときは、認証が切れていてもブラウザを開かずにエラーで止まる
- 動作確認は短いテスト動画で、private のまま行う認証情報とトークンは、gitに入れないよう最初に.gitignoreへ入れます。
# .gitignore
secrets/この記事ではMCPサーバーを使わず、APIを直接呼ぶPythonスクリプトにしています。使うエンドポイントが少なく、夜間に人がいなくても同じスクリプトで動かせるためです。MCPで外部サービスとつなぐ方法はClaude CodeのMCP連携ガイド一覧にまとめています。
初回認証とトークンの保存|スコープは2つに絞る
初回だけブラウザで許可し、受け取ったトークンをファイルに保存して、2回目以降はそれを使い回します。必要なPythonのライブラリはgoogle-api-python-clientとgoogle-auth-oauthlibの2つです。Pythonを動かす環境がまだなら、先にPython入門で準備してください。
pip install google-api-python-client google-auth-oauthlibスコープは、アップロード用のyoutube.uploadと、チャンネルの照合や再生リストへの追加に使うyoutube.force-sslの2つにしました。
from pathlib import Path
from google.auth.exceptions import RefreshError
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
SECRETS_DIR = Path("secrets") # .gitignore対象
CLIENT_SECRET = SECRETS_DIR / "client_secret.json"
TOKEN = SECRETS_DIR / "token.json"
SCOPES = [
"https://www.googleapis.com/auth/youtube.upload",
"https://www.googleapis.com/auth/youtube.force-ssl", # チャンネルの照合・再生リストへの追加
]
class ReauthRequired(Exception):
pass
def credentials(allow_browser: bool = True) -> Credentials:
creds = Credentials.from_authorized_user_file(str(TOKEN), SCOPES) if TOKEN.exists() else None
if creds and creds.expired and creds.refresh_token:
try:
creds.refresh(Request())
except RefreshError as error: # テスト状態のアプリは7日で失効する
raise ReauthRequired(f"認証が切れています({error})") from error
elif not creds or not creds.valid:
if not allow_browser:
raise ReauthRequired("認証がありません")
creds = InstalledAppFlow.from_client_secrets_file(str(CLIENT_SECRET), SCOPES).run_local_server(port=0)
TOKEN.write_text(creds.to_json())
TOKEN.chmod(0o600)
return credsrun_local_server(port=0)を呼ぶとブラウザが開きます。テストユーザーに登録したアカウントでログインし、チャンネルを選んで許可すると、token.jsonが作られます。
スコープを後から足すときは、再認証と同じタイミングにしてください。足したスコープは今のトークンには含まれていないので、許可し直すまで使えません。
再生回数などをYouTube Analytics APIで取りたい場合は、スコープ(yt-analytics.readonly)を足すだけでは足りません。Google CloudでYouTube Analytics APIも別に有効にしてください。筆者は有効にする前に呼んで、403が返りました。
動画のアップロード|再開可能・非公開・二重アップロード防止
videos.insertには、動画ファイルを再開可能なアップロード(resumable)で渡し、返ってきた動画IDをすぐファイルに書きます。途中で通信が切れても続きから送れるうえ、再実行したときに同じ動画をもう一度上げずに済みます。
import json
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
CHUNK_BYTES = 64 * 1024 * 1024
def upload(video_dir: Path, allow_browser: bool) -> str:
record = video_dir / "uploaded.json"
if record.exists(): # 再実行で二重にアップしない
return json.loads(record.read_text())["video_id"]
metadata = json.loads((video_dir / "metadata.json").read_text(encoding="utf-8"))
youtube = build("youtube", "v3", credentials=credentials(allow_browser))
verify_channel(youtube) # 送り先チャンネルの照合(後述)
body = {
"snippet": {
"title": metadata["title"],
"description": metadata["description"],
"tags": metadata["tags"],
"categoryId": metadata["category_id"],
"defaultLanguage": "ja",
},
"status": {
"privacyStatus": "private",
"selfDeclaredMadeForKids": False,
"containsSyntheticMedia": metadata["contains_synthetic_media"],
},
}
media = MediaFileUpload(str(video_dir / "video.mp4"), chunksize=CHUNK_BYTES, resumable=True)
request = youtube.videos().insert(part="snippet,status", body=body, media_body=media)
response = None
while response is None:
status, response = request.next_chunk()
if status:
print(f"アップロード {status.progress() * 100:.0f}%", flush=True)
video_id = response["id"]
record.write_text(json.dumps({"video_id": video_id}, indent=2))
return video_id公式のアップロードガイドのPythonサンプルはchunksize=-1(1回で全部送る)です。この記事では64MBずつに分けて送り、進み具合を表示しています。なお公式サンプルは古いapiclientという名前でimportしているので、そのまま写さずgoogleapiclientに直してください。
アップロードできたかの確かめ方
アップロードが終わったら、次の3つで確かめます。
uploaded.jsonに動画IDが書かれているhttps://studio.youtube.com/video/<動画ID>/editを開くと、YouTube Studioにその動画が非公開で表示される- 同じコマンドをもう一度実行しても新しい動画が増えず、同じ動画IDが返る
3つ目は必ず一度試してください。自動で回すと、後の工程で止まって再実行することがよくあります。そのたびに動画が増えると、Studioで手で消すことになります。
サムネイルと再生リスト|工程ごとに済んだ記録を残す
サムネイルの設定と再生リストへの追加は、アップロードとは別の工程にして、それぞれ済んだ記録をファイルに残します。サムネイルだけ失敗したときに、アップロードからやり直さずに済みます。
def set_thumbnail(video_dir: Path, video_id: str, allow_browser: bool) -> None:
record = video_dir / "thumbnail_set.json"
if record.exists():
return
youtube = build("youtube", "v3", credentials=credentials(allow_browser))
youtube.thumbnails().set(videoId=video_id, media_body=MediaFileUpload(str(video_dir / "thumbnail.jpg"))).execute()
record.write_text(json.dumps({"video_id": video_id}, indent=2))
def add_to_playlist(video_dir: Path, video_id: str, playlist_id: str, allow_browser: bool) -> None:
record = video_dir / "playlist_added.json"
if record.exists():
return
youtube = build("youtube", "v3", credentials=credentials(allow_browser))
youtube.playlistItems().insert(part="snippet", body={"snippet": {
"playlistId": playlist_id,
"resourceId": {"kind": "youtube#video", "videoId": video_id},
}}).execute()
record.write_text(json.dumps({"video_id": video_id, "playlist_id": playlist_id}, indent=2))thumbnails.setが403を返したら、まずチャンネルの電話番号確認が済んでいるかを見てください。YouTubeヘルプは、カスタムサムネイルを電話番号の確認で使えるようになる「中級機能」としています。thumbnails.setのリファレンスの403の説明は「カスタムサムネイルを設定する権限がない」です。
電話番号の確認は、操作しているチャンネルが正しいかを確かめてから行ってください。筆者は一度、別のチャンネルに確認を適用してしまいました。サムネイルの画像は、2026年9月14日から50MBまで設定できるようになっています。
予約公開|privateのままpublishAtを入れる
予約公開は、公開範囲をprivateにしたまま、status.publishAtに公開日時を入れて設定します。筆者はショート動画をこの方法で予約公開しました。
from datetime import datetime, timezone
def schedule(youtube, video_id: str, publish_at: str, contains_synthetic_media: bool) -> str:
when = datetime.fromisoformat(publish_at).astimezone(timezone.utc)
if when <= datetime.now(timezone.utc):
raise ValueError(f"公開日時が過去です: {publish_at}")
# statusは丸ごと置き換わるので、アップロード時の値も入れ直す
status = {
"privacyStatus": "private",
"publishAt": when.strftime("%Y-%m-%dT%H:%M:%SZ"),
"selfDeclaredMadeForKids": False,
"containsSyntheticMedia": contains_synthetic_media,
}
res = youtube.videos().update(part="status", body={"id": video_id, "status": status}).execute()
return res["status"].get("publishAt", "")videosリソースのリファレンスによると、publishAtは「公開範囲がprivateで、一度も公開されていない動画」にだけ設定できます。過去の日時を入れると、その場で公開されます。間違えて即時公開しないよう、スクリプト側で過去の日時を弾いています。
videos.updateでpartにstatusを指定すると、status全体が送った内容に置き換わります。publishAtだけを送ると、アップロード時に入れたcontainsSyntheticMediaなどが消えるので、まとめて入れ直してください。
送り先チャンネルの照合|複数チャンネルがあるときは必須
同じGoogleアカウントで複数のチャンネルを持っているなら、アップロードの前に、認証中のチャンネルIDが送りたいチャンネルと一致するかを確かめます。許可画面で選ぶチャンネルを間違えると、別のチャンネルにそのまま上がってしまうためです。
EXPECTED_CHANNEL_ID = "UCxxxxxxxxxxxxxxxxxxxxxx" # アップロード先のチャンネルID(例の値)
class WrongChannelError(Exception):
pass
def verify_channel(youtube) -> None:
items = youtube.channels().list(part="snippet", mine=True).execute().get("items", [])
if not items or items[0]["id"] != EXPECTED_CHANNEL_ID:
actual = items[0]["snippet"]["title"] if items else "不明"
raise WrongChannelError(
f"認証中のチャンネルが「{actual}」です。"
f"{TOKEN} を削除し、許可画面でチャンネルを選び直してください"
)channels.listのリファレンスでは、mine=trueを指定すると認証したユーザーが所有するチャンネルだけを返すと書かれています。照合に使うチャンネルIDは、正しいチャンネルで認証したときに一度この関数で取得し、控えておくと確実です。
ブラウザでYouTube Studioを操作するときも同じで、画面右上のアイコンが送りたいチャンネルになっているかを先に確かめてください。
夜間の自動実行|認証が切れていたらブラウザを開かずに止める
夜間に自動で動かすときは、認証が切れていてもブラウザを開かずに止め、理由をMacの通知で知らせます。誰も見ていない夜中にブラウザの許可画面が開いても、許可する人がいないためです。
import argparse
import subprocess
import sys
from googleapiclient.errors import HttpError
PLAYLIST_ID = "PLxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # 追加先の再生リストID(例の値)
def notify(title: str, message: str) -> None:
script = f'display notification "{message}" with title "{title}"'
subprocess.run(["osascript", "-e", script], check=False)
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("video_dir")
parser.add_argument("--no-browser", action="store_true", help="夜間用:認証切れならブラウザを開かず止まる")
args = parser.parse_args()
video_dir, allow_browser = Path(args.video_dir), not args.no_browser
try:
video_id = upload(video_dir, allow_browser)
set_thumbnail(video_dir, video_id, allow_browser)
add_to_playlist(video_dir, video_id, PLAYLIST_ID, allow_browser)
except ReauthRequired:
notify("アップロードが止まりました", "再認証が必要です")
return 1
except (FileNotFoundError, HttpError, WrongChannelError) as error:
notify("アップロードが止まりました", str(error)[:80])
return 1
notify("非公開でアップしました", "Studioで確認して公開してください")
return 0
if __name__ == "__main__":
sys.exit(main())macOSでは、launchdで決まった時刻に起動しました。起動するnightly.pyは、その夜に上げる動画のフォルダを決めてから、upload.pyを--no-browser付きで呼ぶだけのスクリプトです。処理の途中でMacがスリープしないよう、caffeinate -iで包んでいます。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.example.youtube-upload</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/caffeinate</string>
<string>-i</string>
<string>/opt/homebrew/bin/python3</string>
<string>/Users/you/youtube-upload/scripts/nightly.py</string>
</array>
<key>WorkingDirectory</key>
<string>/Users/you/youtube-upload</string>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>1</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>StandardOutPath</key>
<string>/Users/you/youtube-upload/logs/launchd.out.log</string>
<key>StandardErrorPath</key>
<string>/Users/you/youtube-upload/logs/launchd.err.log</string>
</dict>
</plist>このファイルを~/Library/LaunchAgents/に置き、launchctl loadで読み込みます。Macの外で決まった時刻に動かしたい場合は、Claude Code側の定期実行も選べます。使い分けはClaude Codeのスキル・ループ・ワークフローの使い分けで説明しています。
クォータは1日100回のアップロードが別枠
クォータの計算ページによると、2026年10月時点の既定の割り当ては、videos.insertが1日100回、search.listが1日100回、その他のエンドポイント全体で1日1万ユニットです。videos.insertは専用の枠で1回1ユニット、thumbnails.setとplaylistItems.insertとvideos.updateは各50ユニット、channels.listは1ユニットです。リセットは太平洋時間の0時です。
以前は、アップロード1回で約1600ユニットを使う計算でした。変更履歴によると、2025年12月4日に約100ユニットへ下がり、2026年6月1日からはアップロード専用の枠に分かれました。「1日6本まで」という古い説明は、今は当てはまりません。
テストから本番へ|7日ごとの再認証をなくす
OAuth同意画面が「外部」かつ「テスト」のままだと、リフレッシュトークンは7日で失効します。GoogleのOAuth 2.0のドキュメントにそう書かれていて、例外は名前・メールアドレス・プロフィールだけを求めるスコープの場合です。youtube.uploadはこの例外に入らないので、テストのままだと7日ごとに再認証が必要です。
筆者は最初テストで動かし、自動で回せることを確かめてから、公開ステータスを本番(In production)に切り替えました。審査(確認の申請)はしていません。切り替えの手順と、途中で出た画面は次のとおりです。
- Google Auth Platformの「対象」で「アプリを公開」を押す。最初は押せず、「ブランディング」にアプリのホームページとプライバシーポリシーのURLを登録すると押せるようになった
- 確認のダイアログに「機密性の高いスコープなどが必要な場合は、検証のための送信が必要」と表示される。審査を受けなくても、そのまま本番に切り替えられた
secrets/token.jsonを削除し、--no-browserを付けずにスクリプトを実行する- 許可画面に「Googleはこのアプリを確認していません」と警告が出るので、「詳細」から進んで許可する
- チャンネルの選択で、アップロード先のチャンネルを選ぶ。スクリプトのチャンネル照合が通り、アップロードまで進むことを確かめる
テスト中に取ったトークンが、本番に切り替えたあとも7日で切れるかどうかは、公式ドキュメントに書かれていません。切り替えたら一度再認証して、トークンを取り直しておくと確実です。
審査なしの本番で気をつけること
Googleのセンシティブスコープの確認ガイドは、自分だけ、または面識のある少人数が使うアプリなら、未確認の警告画面を進めて使ってよいと説明しています。Google Cloudのヘルプによると、警告画面を出すアプリは新規ユーザーが累計100人までに制限され、この上限はプロジェクトの存続期間を通じてリセットできません。自分のチャンネルに上げるだけなら、この範囲で収まります。
本番にしても、リフレッシュトークンが無期限になるわけではありません。OAuth 2.0のドキュメントには、次のような失効の条件が挙げられています。
- ユーザーがアプリへのアクセスを取り消した
- 6か月使われなかった
- 同じOAuthクライアントIDで、1つのGoogleアカウントに対して100個を超えて発行された(101個目を作ると、一番古いものが予告なく無効になる)
夜間の実行が数か月止まっていたあとに再開すると、6か月の条件に当たることがあります。認証が切れたらブラウザを開かずに止めて通知する作りは、本番に切り替えたあとも残しておいてください。
つまずいた点と確認方法
実際に動かして止まった点と、止まりかけた点を、症状・原因・確かめ方の順にまとめます。どれも自動で回し始めてから気づいたものです。
| 症状 | 原因 | 確かめ方・対処 |
|---|---|---|
| 夜間の実行がRefreshErrorで止まる | テスト状態のアプリでリフレッシュトークンが7日で失効した | 最後に認証した日から7日を過ぎていないか。token.jsonを消して再認証する。続けて使うなら本番に切り替える |
| 「アプリを公開」が押せない | ブランディングの必須項目が足りない | ホームページとプライバシーポリシーのURLを登録する |
| 許可画面に「Googleはこのアプリを確認していません」と出る | 審査を受けずに本番にした | 自分で使うだけなら「詳細」から進んで許可する |
| YouTube Analytics APIが403を返す | スコープは足したが、APIを有効にしていなかった | Google CloudでYouTube Analytics APIを有効にする |
| 別のチャンネルに上がりそうになる | 許可画面で選んだチャンネルが違っていた | channels.list(mine=true)のIDと送りたいチャンネルIDを照合して止める |
| サムネイルだけ403で失敗する | カスタムサムネイルを使う資格がない(電話番号確認が済んでいない) | Studioでチャンネルの機能の利用資格を確認する。確認後にthumbnails.setだけ再実行する |
| 再実行したら同じ動画が2本になる | アップロード済みの記録を残していなかった | 動画IDをすぐuploaded.jsonに書き、あれば飛ばす |
| 予約したのに即時公開された | publishAtに過去の日時を入れた | 送る前に現在時刻と比べて弾く |
| 予約公開したらAIの申告が外れた | videos.updateでstatusが丸ごと置き換わった | 更新するときもcontainsSyntheticMediaなどを入れ直す |
未審査のプロジェクトでも非公開に固定されなかった
筆者のGoogle Cloudプロジェクトは、YouTube APIの監査(審査)を受けていません。それでも、アップロードした動画をYouTube Studioとvideos.updateで公開でき、publishAtによる予約公開も設定できました。
これは、以前の公式の説明とは違います。変更履歴には「2020年7月28日以降に作られた未審査のプロジェクトからアップロードした動画は非公開に制限される」という項目が今も残っています。一方、2026年10月15日更新のvideos.insertのリファレンスは「未審査のAPIプロジェクトからアップロードした動画は、非公開に制限されない」と書いています。
記述が変わった理由と日付は、変更履歴にも告知がありません。古い記事の「監査を受けないと公開できない」という説明は、今のリファレンスとは合わないので注意してください。現在の監査は、既定を超えるクォータを申請するためのものです。
よくある質問
Q. サービスアカウントで動画をアップロードできますか?
個人のチャンネルではできません。YouTube Data APIがサービスアカウントに対応するのは、複数のチャンネルを所有・管理するコンテンツ所有者だけです。通常はOAuthでユーザーが許可したトークンを使います。
Q. 未審査のプロジェクトだと動画は非公開に固定されますか?
2026年10月15日更新のvideos.insertのリファレンスでは、未審査のプロジェクトからアップロードした動画は非公開に制限されないと書かれています。筆者も未審査のまま公開でき、予約公開も設定できました。
Q. 1日に何本までアップロードできますか?
既定の割り当てでは、videos.insertは1日100回までで、他のエンドポイントとは別の枠です。サムネイルの設定や再生リストへの追加は、共通の1日1万ユニットから各50ユニットずつ使います。リセットは太平洋時間の0時です。
Q. 7日ごとの再認証をなくすことはできますか?
OAuth同意画面の公開ステータスを本番に切り替えると、テスト状態の7日失効の条件から外れます。筆者は審査を受けずに切り替え、許可画面の未確認の警告を進めて使っています。切り替えたあとは一度再認証してトークンを取り直してください。
Q. 本番に切り替えるのに審査は必要ですか?
自分だけ、または面識のある少人数で使うなら、審査なしで本番に切り替えて使えます。その場合は許可画面に未確認アプリの警告が出て、新規ユーザーは累計100人までに制限されます。
Q. thumbnails.setで403が出たときはどうすればいいですか?
チャンネルの電話番号確認が済んでいるかを確認してください。カスタムサムネイルは電話番号の確認で使えるようになる中級機能です。確認が済んだら、サムネイルの工程だけを再実行します。
Q. 予約公開の日時を過去にするとどうなりますか?
その場で公開されます。publishAtはprivateで一度も公開されていない動画にだけ設定でき、過去の日時を入れると即時公開になると公式リファレンスに書かれています。送る前に現在時刻と比べて弾いてください。
