はじめに
GASを使って、今話題のThreadsに自動投稿してみたい!そう思ってAPIのドキュメントを読み始めたあなたへ。
面倒な申請プロセスを乗り越え、Meta社からアクセストークンを手に入れた瞬間、きっとこう思ったはずです。「やった!これで自動化は完成したも同然だ」と。
僕もそうでした。しかし、それは壮大な勘違いだったのです。
テキスト投稿は、驚くほど簡単でした。静止画の投稿もすぐに成功しました。しかし、「動画投稿」という、たったそれだけの機能が、僕を数日間にわたるデバッグの沼へと引きずり込むことになったのです。
この記事は、そんな僕の試行錯誤の全記録です。
この記事を最後まで読めば、あなたが僕と同じ「沼」にハマるのを未然に防ぎ、貴重な数日分の時間を節約できるはずです。原因究明の旅に、どうかお付き合いください。
【第1章】 メディア置き場探しの旅 - 3つのプラットフォームと謎のエラー
さて、テキストと静止画の投稿は無事にクリア。いよいよ本丸の「動画投稿」です。コード自体は静止画とほとんど同じはず。ファイルのURLを渡せば、それで終わり…のはずでした。
しかし、ここから「メディアファイルをどこに置くか?」という、長い旅が始まったのです。
試行1:Googleドライブ - 誰もがハマる最初の罠
まず最初に思いついたのが、みんな大好きGoogleドライブです。GASとの連携も簡単ですし、これ以上ない選択肢に思えました。早速、共有リンクを取得してAPIに投げてみると…返ってきたのは無情なエラー。
「フォーマットが不正です」
一瞬、動画ファイルが壊れているのかと焦りましたが、原因は単純でした。APIがファイルを取得しにいくと、Googleはまず「このファイルはウイルススキャンできません」という旨の警告ページ(HTML)を表示します。APIはそれを動画ファイルとして読み取れず、エラーになっていたのです。
これはよくある話ですが、僕の長い戦いの序曲に過ぎませんでした。
試行2:WordPress - 避けられなかった費用の壁
次に試したのは、自分が運営しているWordPressサイトのサーバーです。これならGoogleのような警告ページは出ません。
しかし、ここで新たな壁にぶつかります。僕が契約していたプランでは、動画のような大きなファイルをアップロードするには、有料プランへのアップグレードが必要だったのです。
たった1本の動画をテストするためだけに、サーバーの月額料金を上げるのはさすがに割に合わない…。そう判断し、この選択肢も断念せざるを得ませんでした。
試行3:GitHub - そして、謎のエラーと遭遇する
「そうだ、開発者ならGitHubがあるじゃないか」
これぞ灯台下暗し。公開リポジトリに動画ファイルを置き、そのURLを使えば完璧なはず。今度こそ終わりだと思いました。
しかし、APIから返ってきたのは、これまでで最も不可解なエラーでした。
「原因不明のエラー(UNKNOWN)」
何度やっても同じ!
意味が分かりません。URLをコピーしてブラウザで開けば、動画は問題なく表示され、ダウンロードもできます。なのに、API経由でだけ失敗する。
この現象の根本原因は、残念ながら最後まで特定できませんでした。しかし、この試行錯誤から得られた、血の滲むような教訓はただ一つ。
「GitHubは、APIから安定してファイルを取得するための置き場所としては向いていない」
この事実だけが、重くのしかかってきました。
【第2章】 大いなる回り道 - 犯人は動画ファイルだという誤解
GitHubでの不可解な失敗を受け、僕は完全に手詰まりになっていました。 「ファイルの置き場所が原因じゃないとしたら、一体何が悪いんだ…?」
追い詰められた僕の頭に、ある仮説が浮かびます。
「もしかして、APIを拒絶する何かが、動画ファイルの中身そのものにあるのでは?」
苦し紛れの仮説と、AIが囁いたもっともらしい「嘘」
今思えば苦しい言い訳のような仮説ですが、当時は唯一の光明に見えました。藁にもすがる思いで、この仮説を生成AIに相談してみることに。
すると、AIは非常に説得力のある答えを返してきました。 「動画のエンコード形式が、APIの厳格な仕様を満たしていない可能性があります。例えば、音声トラックがなかったり、特定のコーデックでないと弾かれたりすることがあります」
なるほど、それだ! 僕の動画はMidjourneyで生成したもので、音声トラックがありませんでした。原因はこれに違いない。AIの言葉を信じた僕は、ここから長く、そして全く無意味な「回り道」を始めることになります。
HandBrake、ffmpeg… 深い沼への第一歩
AIの助言に基づき、僕は専門的な動画エンコードの世界へ足を踏み入れました。
まずは有名な動画変換ソフト「HandBrake」をインストール。GUIでポチポチと設定を変え、無音の音声トラックを追加してみます。しかし、結果は変わらず。
「HandBrake」で無音の音声トラックを追加など…
「もっと低レベルな制御が必要なのか…?」
次に僕は、黒い画面でおなじみの「ffmpeg」を使い始めました。コマンドを一つ一つ調べ、WebM形式やH.264コーデックなど、様々な形式への変換を試します。まるで動画を「聖別」するかのように、完璧なファイルを作ろうと必死でした。
ffmpegを使ってみても…
徒労の果てに見た、同じエラー
数時間後。僕はついに「完璧」だと思える動画ファイルを手にしました。これならどんなAPIでも文句は言えまい。
祈るような気持ちで、その「聖別」された動画をGitHubに再アップロードし、APIを実行。
しかし、画面に表示されたのは、数時間前と寸分違わぬ「原因不明のエラー(UNKNOWN)」でした。
この瞬間、僕は悟りました。費やした数時間、エンコードについて学んだ知識、そのすべてが、全くの無駄足だったことを。犯人は、動画ファイルではなかったのです。
【第3章】 解決編 - 本当の犯人と最後の罠
動画ファイルは、無実。 僕の数時間にも及ぶ格闘は、全くの見当違いでした。
途方に暮れながら、僕は前の章で相談した生成AIとのやり取りを思い出していました。「そういえば、あのAIはGitHubを第一候補として挙げていたけど、確か第二候補も提案してきていたな…」
その名は、「Cloudflare R2」。 AIがGitHubの方を先に勧めてきたせいで、僕は完全にR2の存在を無視してGitHubの沼にハマっていたのです。
真の解決策:忘れられていた第二候補
藁にもすがる思いで、僕は忘れかけていた第二候補、「Cloudflare R2」を試すことにしました。
Cloudflare R2は、Amazon S3などと同じ「オブジェクトストレージ」と呼ばれるサービスです。APIなどプログラムからの直接アクセスに強く、面倒な認証や警告ページを挟むことなく、ファイルそのものに直接アクセスできるのが特徴です。
衝撃の結末と、本当の「犯人」
まずは、あのffmpegで「聖別」した、完璧なはずの動画ファイルをR2にアップロード。そのURLをGASのコードに貼り付け、実行します。
…成功。
驚くほどあっさりと、僕のThreadsアカウントに動画が投稿されました。 やはり、ファイルの「置き場所」が正解だったのです。安堵のため息をついたその時、ふと、ある疑問が頭をよぎります。
「Cloudflare R2」様!
「待てよ。R2が正解だったのは分かった。でも、あの数時間にわたる動画の編集作業は、本当に必要だったのか…?」
僕は恐る恐る、Midjourneyで生成されたままの、何も編集していない元の動画ファイルをR2にアップロードし、もう一度APIを実行してみました。
…成功。
何の編集もしていない、ただの動画ファイルが、何の問題もなく投稿されてしまったのです。
動画の編集は不要だった!
この瞬間、天を仰ぎました。 何日も僕を苦しめたエラーの根本原因は、ただ純粋に「ファイルの置き場所」の問題でした。
そして、僕をエンコードという深い沼に突き落とした犯人は、もっともらしい一般論を第一候補として提示してきた、あの生成AIだったのかもしれません。
ちなみに、僕がMidjourneyで生成した動画は、サイト上で動画のリンクをコピーし、そのURLを直接使うことでも投稿に成功しました。つまり、ファイルの置き場所としてMidjourneyのURLがそのまま使えた、ということです。生成した動画を直接使う場合は、こちらの方法が最も簡単です。
生成した動画を直接使うなら簡単!
最後の罠:なぜか消えるハッシュタグ
すべてが解決したと思った、その最後の最後。小さな罠が待っていました。
投稿するテキストの行頭に「#テスト」のようにハッシュタグを付けて投稿すると、なぜか行頭の「#」だけが消え、「テスト」というただのテキストになってしまうのです。
色々試した結果、これはAPIの小さな「癖」のようなもので、行頭にハッシュタグを付けたい場合は「##」と2つ重ねることで解決できました。最後まで、気を抜かせてはくれませんね。
【終章】 この戦いから得られた本当の学び
長かった戦いが、ついに終わりました。 たった一つの動画投稿機能に数日間を費やすことになりましたが、このデバッグの沼からは、お金では買えない貴重な教訓を得ることができました。
これから同じ道を通るかもしれないあなたに、僕からの学びを共有します。
教訓1:
メディアを扱うAPIでは、ファイルの中身を疑う前に、まず「置き場所(ホスティング)」がAPIからの直接アクセスに安定して対応しているかを最優先で確認すべし。
今回の原因は、99%これでした。小手先のエンコードを試す前に、まずAPIフレンドリーなストレージ(今回はCloudflare R2)で試す。それだけで、僕が溶かした数日を、あなたは節約できるはずです。
教訓2:
生成AIは、原因不明のエラーに対しては「可能性の高い一般論」を提示するが、それが真因とは限らない。AIの提案で「遠回り」することもある。
AIは素晴らしい壁打ち相手ですが、万能ではありません。今回のように、より一般的(だが間違っている)な答えを優先して提示することもあります。AIの言うことを鵜呑みにせず、常に「別の可能性はないか?」と疑う視点を持つことが重要です。
最終的に、僕のシステムは「Google Apps Script (GAS) + Cloudflare R2」という構成で、安定して動作するようになりました。この格闘の記録が、あなたの開発時間を少しでも短縮できれば、僕が沼で過ごした時間も報われます。
今回の開発で得た知見や、こうした試行錯誤の過程を、これからも発信していきます。有益だと思っていただけたら、ぜひnいいねやフォローで応援していただけると、次の記事を書く大きな励みになります!
【note有料記事のご案内】
この記事で解説した内容を、すぐにあなたの環境で再現できるよう、note有料記事に以下の付録をご用意しました。
-
付録1:スプレ-ッドシート(PostQueueシート)の最終構成
-
投稿予約、ステータス管理、投稿後URLの記録まで、すべてを管理できるシートの最終的な列構成を解説します。
-
-
付録2:実際に動作したGASの全コード(詳細コメント付き)
-
コピペして、いくつかの設定値(アクセストークンやR2のURLなど)を書き換えるだけですぐに動かせる、全コードを公開します。各処理が何をしているのか、詳細なコメントを付けているので、カスタマイズも容易です。
-
-
付録3:スクリプトを定時実行するためのトリガー設定ガイド
-
「毎日朝8時に自動投稿する」といった、スクリプトの自動実行に欠かせないGASの「トリガー」設定方法を分かりやすく解説します。
-
ご興味あれば下記のリンクをクリックしてください!






