tusプロトコルを使ってPHPで vimeo に動画をアップロードする
tusを使ったvimeoに動画アップロードを実装しました。WordPerssベースのシステムでの機能アップデートのため、PHP+JSでの開発になります。
経緯
vimeo から「従来のストリーミングアップロード方式が廃止となるため新しい実装方式に移行してください」とのアナウンスがあったとのことで、対応したいという案件をです。vimeo からのメールはこちら。
We’ve noticed **** is using the deprecated streaming upload approach. We’re writing to inform you that we’ll be sunsetting the streaming upload approach on January 31, 2023. We strongly encourage you to upgrade to the improved resumable/tus upload approach. For more information about the tus protocol at Vimeo, see our Working with Video Uploads guide.
If you’re currently using an Offical SDK, upgrade to the latest version to utilize the tus upload protocol.
Need help? Click here to contact our Support team and we will get back to you as soon as possible.
Best,
Vimeo Support
ドキュメントを見ながらやっていきます。
動画のアップロード方法として以下の3つのアプローチが案内されます。
- Resumable, or tus, after the open-source tus protocol
- Form-based, also known as POST
- Pull
tus を使うのが進捗状況の表示などもできていちばんオススメだが、工数的にはフォームで POST するのがラクとのこと。Pull はどこか別のサーバー上に動画がアップロードされている場合に使う。今回はメールでもオススメされているし、既存のUIで実装されている進捗表示のプログレスバーを引き続き生かしたいので、tus を採用することに。
そもそも tus 自体はじめて聞いたが、ファイルアップロードのためのプロトコルとのこと。アップロードが中断した時に、途中で失敗したところから再開できたり、進捗を表示することもできるなど。
実装準備
vimeo 上でアプリを作る
My Appsからアプリを作成し、Client identifier
access token
Client secrets
を取得する。access token
の生成時に「Authenticated (you)」を選んで「Private」にチェックを入れて、合わせて必要な権限にもチェックを付けておく必要あり。
Getting Started with the Vimeo API
ライブラリのインストール
comporser 経由でインストール。
composer require vimeo/vimeo-api
Getting Started with the Vimeo API
GitHubもある。 vimeo/vimeo.php: Official PHP library for the Vimeo API.
その他の言語のライブラリとかはこちら。 Vimeo API Libraries and SDKs
動画アップロード処理の実装
フロントエンド
document.addEventListener('DOMContentLoaded', () => {
const file_select = document.getElementById('file_input');
if( file_input ){
file_input.addEventListener('click', (evt) => {
evt.target.value = ''; // エラー等で再選択する時に同じファイルでもchangeイベントを発火させるための処理
});
file_input.addEventListener('change', () => {
const file = evt.target.files[0];
vimeo_upload(file);
}, false);
}
});
const vimeo_upload = (file) => {
let filedata = new FormData();
filedata.append('file', file);
filedata.append('action', 'vimeo_tus_upload');
filedata.append('nonce', nonce);
filedata.append('title', get_video_title());
jQuery.ajax({
type: 'POST',
dataType: 'JSON',
url: ajaxurl,
processData: false,
contentType: false,
cache: false,
data: filedata
}).done(function( ret ){
if( $ret[0] =- 'success' ){
// 成功時の処理
}else{
// エラー時の処理
}
}).fail(function( xhr, status, errorThrown ){
// 通信失敗時の処理
});
}
actionとかnonceとかやってるのはWordPress仕様。
PHP でアップロード
ライブラリに用意されたupload
メソッドでアップロードするパターン。サーバーサイドで完結するので、プログレスバーの実装はできない(はず)。
vimeo のドキュメントより、ライブラリのコードを直接読むか、ライブラリ内のexampleを読んだ方が分かりやすいかも。
require '{path_to_root_folder}/autoload.php';
use Vimeo\Vimeo;
use Vimeo\Exceptions\VimeoUploadException;
function get_vimeo_client(){
$client = new Vimeo("{client_id}", "{client_secret}", "{access_token}");
}
function vimeo_tus_upload(){
self::check_nonce( $_POST['nonce'] );// 省略
$client = self::get_vimeo_client();
$file = $_FILES['file']['tmp_name'];
if( empty($file) ){
$response = array( 'error', 'ファイルを読み込めませんでした' );
echo json_encode( $response );
die();
}
try{
$url = $client->upload(
$file,
array(
'name' => 'Vimeo API SDK test upload',
'description' => "This video was uploaded through the Vimeo API's PHP SDK.",
)
);
}catch( VimeoUploadException $e ){
$response = array( 'error', $e->getMessage() );
echo json_encode( $response );
die();
}
$url = end( explode( '/', $url ) );
$response = array( 'success', $url );
echo json_encode($response);
die();
}
なお、レスポンスはvideo/video_id
の形式で返ってくるが、https://vimeo.com/video/{video_id}
にアクセスしても404になってhttps://vimeo.com/{video_id}
だとアクセスできる。このへんのvimeoの仕様はもうちょっと深堀りした方がいいのかもしれない。
JavaScript でアップロード
サーバーサイドではアップロード先のURLだけ取得して、JSでアップロード処理を行う。プログレスバーが欲しい時はこれ。
tus クライアントをインストール
$ npm install --save tus-js-client
またはtus.min.jsをダウンロードして読み込む。
<script src="./tus.min.js"></script>
アップロード先のURLを取得(PHP)
function vimeo_upload_request(){
self::check_nonce( $_POST['nonce'] );
$client = self::get_vimeo_client();
try{
$params['upload']['approach'] = 'tus';
$params['upload']['size'] = $_POST['size'];
// 任意
$params['name'] = 'Vimeo API SDK test upload';
$params['description'] = "This video was uploaded through the Vimeo API's PHP SDK.";
$uri = '/me/videos?fields=uri,upload';
$attempt = $client->request($uri, $params, 'POST');
if ($attempt['status'] == 200) {
$url = end( explode( '/', $attempt['body']['uri'] ) );
$response = array( 'success', $url, $attempt['body']['upload']['upload_link'] );
echo json_encode($response);
}else{
$attempt_error = !empty($attempt['body']['error']) ? ' [' . $attempt['body']['error'] . ']' : '';
$response = array( 'error', $attempt_error );
echo json_encode($response);
}
}catch( VimeoUploadException $e ){
$response = array( 'error', $e->getMessage() );
echo json_encode($response);
}
die();
}
アップロード
vimeo のドキュメントには書いてないので JS クライアントのドキュメントを見る。「Example: Upload to Vimeo」というドンピシャの例があるので助かる。
const vimeo_upload = (file) => {
jQuery.ajax({
type: 'POST',
dataType: "JSON",
url: vimeo_ajax_object.ajaxurl,
data: {
'action': 'vimeo_upload_request',
'nonce' : vimeo_ajax_object.ajaxnonce,
'size' : file.size
}
}).done(function(ret){
if( ret[0] == 'success' ){
const url = ret[1];
const upload_url = ret[2];
vimeo_upload_tus( upload_url, url, file );
}else{
// リクエスト失敗時の処理
}
}).fail(function( xhr, status, errorThrown ){
// 通信失敗時の処理
});
}
const vimeo_upload_tus = ( upload_url, vimeo_id, file ) => {
const upload = new tus.Upload(file, {
uploadUrl: upload_url,
onError: function(error) {
// 失敗時の処理
},
onProgress: function( bytesUploaded, bytesTotal ) {
const percentage = (bytesUploaded / bytesTotal * 100).toFixed(0);
let progress = document.getElementById('progress');
progress.setAttribute('style', 'width:' + percentage + '%');
progress.innerHTML = ' ' + percentage + '%';
},
onSuccess: function() {
// 成功時の処理
}
});
upload.start();
}
privacy の設定
アップロードのリクエスト時、 metadata に privacy 設定を追加することができる。この際、アカウントがフリープランだと privacy 設定に対応していないためエラーになる。
This feature requires a paid plan on Vimeo.
Manage your video’s privacy settings – Help Center
エラー例
(
[invalid_parameters] => Array
(
[0] => Array
(
[field] => privacy.download
[error_code] => 2204
[error] => You have provided an invalid parameter. Please contact developer of this application.
[developer_message] => The parameters passed to this API endpoint didn't pass Vimeo's validation. Please check the invalid_parameters list for more information.
)
)
[error] => You have provided an invalid parameter. Please contact developer of this application.
[link] =>
[developer_message] => The parameters passed to this API endpoint didn't pass Vimeo's validation. Please check the invalid_parameters list for more information.
[error_code] => 2204
)
ユーザーのプラン情報を取得
ユーザーによってプランが混在するような環境ではこれを回避するため、ユーザー情報からプランを確認する。
try{
$uri ='/me';
$user = $client->request($uri, '', 'GET');
$account = $user['body']['account'];
}catch( VimeoRequestException $e ){
echo json_encode($e->getMessage());
die();
}
$params = array(
'upload' => array(
'approach' => 'tus',
'size' => $_POST['size'],
),
'name' => $_POST['title'],
);
if( $account != 'free' ){
$params['privacy']['download'] = false;
}
埋め込みプリセットの設定
ビューアーのデザインを設定し、プリセット( presets )として設定することができる。プリセットは以下より作成できる。プリセット設定画面URL末尾の数字がpreset_id
になる。
以下はアップロードした動画に特定のプリセットを設定する例。
try{
$uri ='/videos/' . video_id . '/presets/' . preset_id;
$response = $client->request($uri, '', 'PUT');
if( !empty($response['body']['error']) ){
// エラー処理
}
}catch( VimeoRequestException $e ){
// エラー処理
die();
}
なお、デフォルトのプリセットは 設定 > 動画 > アップロードのデフォルト > 動画に適用する埋め込みプリセットを選択。 で設定可能だが、プリセットを作成したあと一度リロードしないと選択肢に表示されない。
その他、各種処理は以下。
削除処理の実装
フロント省略。
function vimeo_delete(){
self::check_nonce( $_POST['nonce'] );
$client = self::get_vimeo_client();
$vimeo_id = $_POST['vimeo_id']; // 動画IDを指定する
try {
$uri = '/videos/' . $vimeo_id;
$response = $client->request($uri, [], 'DELETE');
} catch ( VimeoUploadException $e ) {
$response = array( 'error', $e->getMessage() );
echo json_encode($response);
die();
}
$response = array( 'success', $response['status'] );
echo json_encode($response);
die();
}
その他参考
アップロード時の各種パラメーターは以下を参照。
他の言語の記事もあって参考になった。感謝。