概要
Twitterが140秒までの動画ツイートに対応したと聞いたので,以前からあるエンドポイントも含めてアップロード系のものをまとめてみました.
サンプルには拙作のTwistOAuthを用いたコードを掲載します.
POST statuses/update_with_media
単一の画像のアップロードに使えます.
echo "Uploading and tweeting...\n";
$to->postMultipart('statuses/update_with_media', [
'status' => 'hello',
'@media[]' => 'photo.jpg',
]);
echo "Done!\n";
- 現在非推奨
- サーバとの通信が1回で済む
- multipart/form-dataが強制される
- エンドポイント固有のパラメータは
oauth_signature
の生成対象に含まれない
- エンドポイント固有のパラメータは
-
media[]
というパラメータ名であるにも関わらず,単一の画像しか受け付けない
POST media/upload (コマンド無し)
1枚以上の画像のアップロードに使えます.
$media_ids = [];
echo "Uploading A.jpg...\n";
$media_ids[] = $to->postMultipart('media/upload', [
'@media' => 'A.jpg',
])->media_id_string;
echo "Uploading B.jpg...\n";
$media_ids[] = $to->post('media/upload', [
'@media' => 'B.jpg', // 自動的にデータがBase64エンコードされる
])->media_id_string;
echo "Tweeting...\n";
$to->post('statuses/update', [
'status' => 'hello',
'media_ids' => implode(',', $media_ids),
]);
echo "Done!\n";
- サーバとの通信が2回以上必要
- multipart/form-dataとapplication/x-www-form-urlencodedから選べる
- multipart/form-dataの場合,エンドポイント固有のパラメータは
oauth_signature
の生成対象に含まれない - application/x-www-form-urlencodedの場合,メディアデータのみBase64エンコードする必要がある
- multipart/form-dataの場合,エンドポイント固有のパラメータは
オーバーヘッドの小さいmultipart/form-dataを推奨します.
POST media/upload (コマンドあり・同期)
いろいろなデータのアップロードに使えます.
- 1枚以上の画像
- 1つのアニメGIF (0.5秒〜30秒)
- 1つの動画 (0.5秒〜30秒)
以下のコマンドを順番にコールする必要があります.
$filename = 'small_video.mp4';
echo "Initializing...\n";
$info = $to->post('media/upload', [
'command' => 'INIT',
'media_type' => 'video/mp4',
'total_bytes' => filesize($filename),
]);
echo "Uploading video...\n";
$to->postMultipart('media/upload', [
'command' => 'APPEND',
'media_id' => $info->media_id_string,
'segment_index' => 0,
'@media' => $filename,
]);
echo "Finalizing...\n";
$to->post('media/upload', [
'command' => 'FINALIZE',
'media_id' => $info->media_id_string,
]);
echo "Tweeting...\n";
$to->post('statuses/update', [
'status' => 'hello',
'media_ids' => $info->media_id_string,
]);
echo "Done!\n";
- サーバとの通信が4回以上必要
- multipart/form-dataとapplication/x-www-form-urlencodedから選べる
- multipart/form-dataの場合,エンドポイント固有のパラメータは
oauth_signature
の生成対象に含まれない - application/x-www-form-urlencodedの場合,メディアデータのみBase64エンコードする必要がある
- multipart/form-dataの場合,エンドポイント固有のパラメータは
オーバーヘッドの小さいmultipart/form-dataを推奨します.
GET|POST media/upload (コマンドあり・非同期)
いろいろなデータのアップロードに使えます.こちらは大きなデータをアップロードする前提なので,チャンク分割を入れます.分割を行わないと,413 Request Entity Too Large
が返されてしまう場合があります.
- 1枚以上の画像
media_category=tweet_image
- 1つのアニメGIF (0.5秒〜140秒)
media_category=tweet_gif
- 1つの動画 (0.5秒〜140秒)
media_category=tweet_video
以下のコマンドを順番にコールする必要があります.
$file = new \SplFileObject('large_video.mp4', 'rb');
$chunk_size = 262144; // 適当に調節してください
echo "Initializing...\n";
$info = $to->post('media/upload', [
'command' => 'INIT',
'media_type' => 'video/mp4',
'total_bytes' => $file->getSize(),
'media_category' => 'tweet_video', // これを忘れると非同期のほうにならない
]);
$curls = [];
for ($i = 0; '' !== $buffer = $file->fread($chunk_size); ++$i) { // チャンクサイズごとに分割
$curls[] = $to->curlPostMultipart('media/upload', [
'command' => 'APPEND',
'media_id' => $info->media_id_string,
'segment_index' => $i,
'#media' => $buffer,
]); // リクエストせずにリクエスト用のcURLリソースだけを用意
}
echo "Uploading chunks...\n";
$to->curlMultiExec($curls, true); // 1チャンクごとに待ってると時間がかかるので並列化
echo "Finalizing...\n";
$info = $to->post('media/upload', [
'command' => 'FINALIZE',
'media_id' => $info->media_id_string,
]);
echo "Waiting for processing...\n";
while ($info->processing_info->state === 'pending' || $info->processing_info->state === 'in_progress') { // 終わるか失敗するまで繰り返す
$percent = isset($info->processing_info->progress_percent) // 場合によってはパーセント表記が返ってくる
? "({$info->processing_info->progress_percent}%)"
: ''
;
echo "State: {$info->processing_info->state} {$percent}\n";
sleep($info->processing_info->check_after_secs); // 待つように指示されたぶんだけ待つ
$info = $to->get('media/upload', [
'command' => 'STATUS',
'media_id' => $info->media_id_string,
]); // 情報を更新
}
if ($info->processing_info->state === 'failed') {
// 失敗時は例外をスロー
throw new \RuntimeException($info->processing_info->error->name);
}
echo "Tweeting...\n";
$to->post('statuses/update', [
'status' => 'hello',
'media_ids' => $info->media_id_string,
]);
echo "Done!\n";
- サーバとの通信がかなりの回数必要
- multipart/form-dataとapplication/x-www-form-urlencodedから選べる
- multipart/form-dataの場合,エンドポイント固有のパラメータは
oauth_signature
の生成対象に含まれない - application/x-www-form-urlencodedの場合,メディアデータのみBase64エンコードする必要がある
- multipart/form-dataの場合,エンドポイント固有のパラメータは
- 失敗した時に
$info->processing->state
が"fail"
になることがある- しかし,そのときのHTTPステータスコードは
200 OK
- エラー内容次第では従来の
{"errors":[{"code":1,"message":"xx"}]}
が400 Bad Request
で来ることもある - 失敗したメディアで
statuses/update
しようとするとしっかり400 Bad Request
のエラーになるので,必ずしもこのエラーハンドリングを特別扱いして行う必要はない
- しかし,そのときのHTTPステータスコードは
オーバーヘッドの小さいmultipart/form-dataを推奨します.
追記: TwistOAuthの後継であるCowitterでは,面倒なアップロードのための記述を丸投げできます
Cowitterのメソッドを活用する場合
Co::wait(function () use ($client) {
$file = new \SplFileObject('large_video.mp4', 'rb');
$on_uploading = function ($percent) {
echo "Uploading ... ({$percent}%)\n";
};
$on_processing = function ($percent) {
echo "Processing ... ({$percent}%)\n";
};
yield $client->postAsync('statuses/update', [
'status' => 'My video',
'media_ids' => (yield $client->uploadVideoAsync($file, $on_uploading, $on_processing))->media_id_string,
]);
echo "Done!\n";
});