はじめに
このドキュメントでは、にステータスリクエストを送信することで、ジョブのステータスを追跡する方法について説明します。CMS APIまたはを使用してDynamic Ingest API通知。プロセスを自動化するサンプルダッシュボードアプリも提供します
取り込みジョブのステータスは、過去7日間に送信されたジョブでのみ利用可能であることに注意してください。
ステータスのリクエスト
を使用して、動的取り込みジョブ(取り込み、置換、または再トランスコード)のステータスを取得します。これらCMS APIエンドポイント -これらのエンドポイントは動的配信ジョブのみ:
すべてのジョブのステータスを取得する
https://cms.api.brightcove.com/v1/accounts/{account_id}/videos/{video_id}/ingest_jobs
応答は次のようになります。
[
{
"id": "ac49b1db-e6e1-477f-a2c1-70b9cd3107cb",
"state": "finished",
"account_id": "57838016001",
"video_id": "5636411346001",
"error_code": null,
"error_message": null,
"updated_at": "2017-11-07T13:56:51.505Z",
"started_at": "2017-11-07T13:56:12.510Z",
"priority": "normal",
"submitted_at": "2017-11-07T13:56:12.435Z"
},
{
"id": "10605652-8b6f-4f22-b190-01bd1938677b",
"state": "processing",
"account_id": "57838016001",
"video_id": "5636411346001",
"error_code": null,
"error_message": null,
"updated_at": null,
"started_at": null,
"priority": "low",
"submitted_at": "2017-11-07T14:06:35.000Z"
}
]
特定のジョブのステータスを取得する
https://cms.api.brightcove.com/v1/accounts/{account_id}/videos/{video_id}/ingest_jobs/{job_id}
応答は次のようになります。
{
"id": "ac49b1db-e6e1-477f-a2c1-70b9cd3107cb",
"state": "finished",
"account_id": "57838016001",
"video_id": "5636411346001",
"error_code": null,
"error_message": null,
"updated_at": "2017-11-07T13:56:51.505Z",
"started_at": "2017-11-07T13:56:12.510Z",
"priority": "normal",
"submitted_at": "2017-11-07T13:56:12.435Z"
}
の可能な値state
は:
processing
:処理中、ビデオはまだ再生できませんpublishing
:少なくとも1つの再生可能なレンディションが作成され、ビデオを再生する準備ができていますpublished
:少なくとも1つのレンディションが再生可能ですfinished
:少なくとも1つのオーディオ/ビデオレンディションが処理されましたfailed
:処理に失敗しました。何が悪かったのかわからない場合は、サポートに連絡してください
通知を受け取る
上記のリクエストステータスメソッドは機能しますが、特定の状態を待機している場合(published
またはfinished
)、探している答えが得られるまでステータスを尋ね続けるよりも、これらのイベントが発生したときにBrightcoveに通知させる方がよいでしょう。次に、通知の処理を中心にアプリを構築する方法を見ていきます。
動的取り込み通知は、動画の準備ができたときに知っておく必要があるすべての情報を提供します。必要な情報を把握し、システムの「準備完了」の意味を定義する必要があります。次の図に、ワークフローの概要を示します。
動的取り込み通知
動的取り込み通知サービスは、いくつかの種類のイベントについて通知を送信します。ビデオが「準備完了」であるかどうかを判断するのに最も役立つ2つは、特定のレンディションが作成されたことを示すものと、すべての処理が完了したことを示すものです。それぞれの例を次に示します。
動的レンディション作成通知
{
"entity": "default/video3800",
"entityType": "DYNAMIC_RENDITION",
"version": "1",
"action": "CREATE",
"jobId": "d3ef8751-2b88-4141-95d5-83f0393aca07",
"videoId": "5660367449001",
"dynamicRenditionId": "default\/video3800",
"bitrate": 3804,
"width": 1920,
"height": 1080,
"accountId": "57838016001",
"status": "SUCCESS"
}
この例では、次の点に注意してください。
videoId
この値により、レンディションがどのビデオ用であるかを知ることができます (複数のインジェストジョブを実行している場合)- ザ・
entity
値は、作成された動的レンディションタイプです - の場合
status
値は「SUCCESS」で、レンディションは正常に作成されました
完全な通知を処理しています
{
"entity": "5660367449001",
"entityType": "TITLE",
"version": "1",
"action": "CREATE",
"jobId": "d3ef8751-2b88-4141-95d5-83f0393aca07",
"videoId": "5660367449001",
"accountId": "57838016001",
"status": "SUCCESS"
}
この例では、次の点に注意してください。
- ザ・
videoId
そしてjobId
値は、これがどのビデオ用であるかを知らせます(複数の取り込みジョブが実行されている場合) - の場合
status
値は「SUCCESS」で、ビデオは正常に処理されました
通知を受け取るには、Dynamic Ingest APIリクエストに「コールバック」フィールドを含めて、1つ以上のコールバックアドレスを指す必要があります。
{
"master": {
"url": "https://s3.amazonaws.com/bucket/mysourcevideo.mp4"
}, "profile": "multi-platform-extended-static",
"callbacks": ["http://host1/path1”, “http://host2/path2”]
}
サンプルダッシュボード
このセクションでは、通知をまとめてDynamic IngestAPIのシンプルなダッシュボードを構築する方法について説明します。通知のハンドラは、Dynamic Ingest APIからの通知を解析して、処理が完了した通知を識別します。次に、JSON ファイルの各動画のオブジェクトの配列にビデオ通知を追加します。ダッシュボード自体は、JSON ファイルをインポートして通知データを取得する HTML ページです。この ID を使用して CMS API にリクエストを行い、ビデオのメタデータを取得します。
アプリの高レベルのアーキテクチャは次のとおりです。
アプリのパーツ
通知のハンドラは、PHPに組み込まれています-それは完全な通知を処理し、別のJavaScriptファイル内の配列にビデオIDを追加します。
<?php
//POST は JSON データでは機能しません
$problem = "No errors";
try {
$json = file_get_contents('php://input');
$decoded = json_decode($json, true);
} キャッチ(例外 $e){
$problem = $e->getMessage();
エコー$問題;
}
//完全な通知
$notification = json_encode($decoded, JSON_PRETTY_PRINT);
//通知の有用な部分を抽出することから始めます
//動的配信の場合は、「videoId」を探します
//レガシー取り込みシステムの場合、ビデオIDは「エンティティ」です
if(isset($ decode ["videoId"])){
$ videoId = $ decode ["videoId"];
} elseif(isset($ decode ["entity"])){
$ videoId = $ decode ["entity"];
} else {
$ videoId = null;
}
(isset ($デコード ["entityType"])) {
$entityType = $decoded["entityType"];
} else {
$ entityType = null;
}
if(isset($ decode ["status"])){
$ status = $ decode ["status"];
} else {
$ status = null;
}
if(isset($ decode ["action"])){
$ action = $ decode ["action"];
} else {
$ action = null;
}
//完了したタイトルに関する通知の場合は、行動します
if(($ entityType == 'TITLE')&&($ action == 'CREATE')){
if(($ status == 'SUCCESS')||($ status == 'FAILED')){
$ newLine = "\\ nvideoIdArray.unshift("。$ videoId。 ");";
//PHPにログファイルがある場所を指示し、PHPにそれを開くように指示する
//先ほど作成した文字列をそれに追加します。
$ logFileLocation = "video-ids.js";
$fileHandle = fopen($logFileLocation, 'a') or die("-1");
chmod ($logfileLocation, 0777);
fwrite($ fileHandle、$ newLine);
fclose ($fileHandle);
}
}
//監査証跡の完全な通知を保存します
$ logEntry = $ notification。 "、\\ n";
$ logFileLocation = "full-log.txt";
$fileHandle = fopen($logFileLocation, 'a') or die("-1");
chmod ($logfileLocation, 0777);
fwrite ($fileHandle, $logEntry);
fclose ($fileHandle);
echo「動的取り込みコールバックアプリが実行されています」;
?>
JSON ファイル:
JSONファイルは最初は空の配列です([]
)-データは通知ハンドラーによって追加されます。
ダッシュボード
ダッシュボードには、から通知データと追加のビデオデータを取得し、結果をテーブルに書き込むための HTML CMS APIと JavaScript が含まれています。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Dynamic Ingest Log</title>
<style>
body {
font-family: sans-serif;
margin: 5em;
}
.hide {
display: none;
}
.show {
display: block;
}
table {
border-collapse: collapse;
border: 1px #999999 solid;
}
th {
background-color: #666666;
color: #f5f5f5;
padding: .5em;
font-size: .7em;
}
td {
border: 1px #999999 solid;
font-size: .7em;
padding: .5em
}
.hidden {
display: none;
}
</style>
</head>
<body>
<h1>Dynamic Ingest Log</h1>
<h2>Account: Brightcove Learning (57838016001)</h2>
<p style="width:70%">
Videos are listed in order of processing completion time, newest to oldest. The reference id (generated by the <a href="./di-tester.html">Dynamic Ingest tester</a>) is a combination of the date/time that the Dynamic Ingest job was initiated and the ingest profile that was used. You can add additional videos using the <a href="./di-tester.html">Dynamic Ingest tester</a>. New videos will appear in this log after processing is complete.
</p>
<p>
<button id="clearLogBtn">Clear the log</button>
</p>
<div id="videoLogBlock">
<table>
<thead>
<tr>
<th>Video ID</th>
<th>Name</th>
<th>Reference ID</th>
<th>Renditions Created</th>
<th>Processing Complete</th>
</tr>
</thead>
<tbody id="logBody"></tbody>
</table>
<h4 id="loadingMessage">Loading data, please wait...</h4>
</div>
<script>
var BCLS = ( function (window, document) {
// to use another account, set the account_id value appropriately
// the client_id and client_secret will also need to be changed in the proxy
var my_account_id = 57838016001,
account_id = my_account_id,
logBody = document.getElementById('logBody'),
loadingMessage = document.getElementById('loadingMessage'),
clearLogBtn = document.getElementById('clearLogBtn'),
i = 0,
iMax,
// set the proxyURL to the location of the proxy app that makes Brightcove API requests
proxyURL = './brightcove-learning-proxy.php',
dataFileURL = './di.json',
videoDataArray = [],
requestOptions = {},
currentVideo,
currentIndex = 0;
/**
* tests for all the ways a variable might be undefined or not have a value
* @param {*} x the variable to test
* @return {Boolean} true if variable is defined and has a value
*/
function isDefined(x) {
if ( x === '' || x === null || x === undefined || x === NaN) {
return false;
}
return true;
}
/**
* find index of an object in array of objects
* based on some property value
*
* @param {array} targetArray - array to search
* @param {string} objProperty - object property to search
* @param {string|number} value - value of the property to search for
* @return {integer} index of first instance if found, otherwise returns null
*/
function findObjectInArray(targetArray, objProperty, value) {
var i, totalItems = targetArray.length, objFound = false;
for (i = 0; i < totalItems; i++) {
if (targetArray[i][objProperty] === value) {
objFound = true;
return i;
}
}
if (objFound === false) {
return null;
}
}
/**
* factory for new video objects
* @param {String} videoId the video id
* @return {object} the new object
*/
function makeVideoDataObject(videoId) {
var obj = {};
obj.id = videoId;
obj.name = '';
obj.reference_id = '';
obj.renditions = 0;
obj.complete = 'no';
return obj;
}
/**
* processes notification objects
* creates a new object in the videoDataArray if it doesn't exist
* and updates the videoDataArray object based on the notification
* @param {Object} notificationObj the raw notification object
*/
function processNotification(notificationObj) {
var objIndex, videoObj;
// if notification object contains a video id, find the corresponding
// object in the videoDataArray or create it if it's not there
if (isDefined(notificationObj) && isDefined(notificationObj.videoId)) {
objIndex = findObjectInArray(videoDataArray, 'id', notificationObj.videoId);
// if not found, create one
if (!isDefined(objIndex)) {
videoObj = makeVideoDataObject(notificationObj.videoId);
videoDataArray.push(videoObj);
objIndex = videoDataArray.length - 1;
}
// now update properties based on what's in the notification
if (notificationObj.entityType === 'DYNAMIC_RENDITION') {
// increment the renditions account
videoDataArray[objIndex].renditions++;
}
} else if (notificationObj.entityType === 'TITLE') {
// overall processing notification - checked for SUCCESS / FAILED
if (notificationObj.status === 'SUCCESS') {
// mark complete
videoDataArray[objIndex].complete = 'yes';
} else if (notificationObj.status === 'FAILED') {
// mark failed
videoDataArray[objIndex].complete = 'failed';
}
}
return;
}
/**
* creates the dashboard table body
*/
function writeReport() {
var j,
jMax = videoDataArray.length,
item,
t;
loadingMessage.textContent = 'This page will refresh in 1 minute...';
for (j = 0; j < jMax; j++) {
item = videoDataArray[j];
if (item.id !== undefined) {
logBody.innerHTML += '<tr><td>' + item.id + '</td><td>' + item.name + '</td><td>' + item.reference_id + '</td><td>' + item.renditions + '</td><td>' + item.complete + '</td></tr>';
}
}
// set timeout for refresh
t = window.setTimeout(init, 60000);
};
// function to set up the notification data request
function setJSONRequestOptions() {
submitRequest(null, dataFileURL, 'notificationData');
}
// function to set up video data request
function setVideoRequestOptions() {
requestOptions = {};
requestOptions.url = 'https://cms.api.brightcove.com/v1/accounts/' + account_id + '/videos/' + currentVideo.id;
submitRequest(requestOptions, proxyURL, 'video');
}
/**
* initiates the CMS API requests
*/
function getVideoInfo() {
iMax = videoDataArray.length;
if (currentIndex < iMax) {
currentVideo = videoDataArray[currentIndex];
setVideoRequestOptions();
} else {
loadingMessage.innerHTML = 'No videos have been ingested - you can add some using the <a href="./di-tester.html">Dynamic Ingest tester</a>';
}
}
/**
* make the CMS API requests
* @param {Object} options request options
* @param (String) url URL to send request to
* @param (String) type the request type
*/
function submitRequest(options, url, type) {
var httpRequest = new XMLHttpRequest(),
requestData,
responseData,
videoDataObject,
parsedData,
getResponse = function () {
try {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
responseData = httpRequest.responseText;
switch (type) {
case 'notificationData':
var k, kMax, dataArray;
dataArray = JSON.parse(responseData);
// process the notifications
kMax = dataArray.length;
for (k = 0; k < kMax; k++) {
processNotification(dataArray[k]);
}
getVideoInfo();
break;
case 'video':
parsedData = JSON.parse(responseData);
videoDataArray[currentIndex].reference_id = parsedData.reference_id;
videoDataArray[currentIndex].name = parsedData.name;
currentIndex++;
if (currentIndex < iMax) {
currentVideo = videoDataArray[currentIndex];
setVideoRequestOptions();
} else {
writeReport();
}
break;
}
} else {
console.log('There was a problem with the request. Request returned '', httpRequest.status);
if (type === 'video') {
setVideoRequestOptions();
} else {
setSourcesRequestOptions();
}
}
}
}
catch(e) {
console.log('Caught Exception: ', e);
}
};
// notifications data is a special case
if (type === 'notificationData') {
// set response handler
httpRequest.onreadystatechange = getResponse;
// open the request
httpRequest.open("GET", url);
// set headers
httpRequest.setRequestHeader("Content-Type", "application/json");
// open and send request
httpRequest.send();
} else {
// requests via proxy
// set up request data
requestData = "url=" + encodeURIComponent(options.url) + "&requestType=GET";
// set response handler
httpRequest.onreadystatechange = getResponse;
// open the request
httpRequest.open("POST", url);
// set headers
httpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
// open and send request
httpRequest.send(requestData);
}
};
// event handlers
clearLogBtn.addEventListener('click', function () {
if (window.confirm('Are you sure? This action cannot be undone!')) {
// if your clear-log app resides in another location, change the URL
window.location.href = 'clear-log.php';
}
});
// get things started
function init() {
// clear table and the video data array
logBody.innerHTML = "";
videoDataArray = [];
setJSONRequestOptions();
}
// kick off the app
init();
})(window, document);
</script>
</body>
</html>
プロキシ
<?php
/**
* brightcove-learning-proxy.php-Brightcove ブ RESTful API 用プロキシ
* アクセストークンを取得し、リクエストを行い、レスポンスを返す
* アクセス:
* URL: https://solutions.brightcove.com/bcls/bcls-proxy/bcsl-proxy.php
*(HTTPS経由でプロキシにアクセスする必要があることに注意してください)
* 方法:役職
*
* @post {文字列} url-APIリクエストのURL
* @post {文字列} [requestType=Get]-リクエストのHTTPメソッド
* @post {文字列} [requestBody=Null]-書き込みリクエストで送信されるJSONデータ
*
* @returns {文字列} $response-APIから受け取ったJSONレスポンス
*/
// CORSエンタブラチュア
ヘッダー (「アクセス制御許可オリジン:*」);
//アクセストークンのリクエストを設定する
$data = array();
//
//別のアカウントでこのプロキシを使用するには、以下の値を変更します
//
$client_id = "YOUR_CLIENT_ID_HERE";
$client_secret = "YOUR_CLIENT_SECRET_HERE";
$auth_string = "{$client_id}:{$client_secret}";
$request = "https://oauth.brightcove.com/v4/access_token?grant_type=client_credentials";
$ch = curl_init($request);
curl_setopt_array ($ch, 配列 (
CURLOPT_POST = > 真、
CURLOPT_RETURNTRANSFER = > 真、
CURLOPT_SSL_VERIFYPEER = > 偽、
CURLOPT_USERPWD = > $auth_string、
CURLOPT_HTTPHEADER = > 配列 (
'コンテンツタイプ:アプリケーション/X-www-form-urlencoded',
)、
CURLOPT_POSTFIELDS = > $データ
)));
$response = curl_exec($ch);
curl_close ($ch);
//エラーをチェックする
($応答=== 偽) {
死ぬ (curl_error ($ch));
}
//レスポンスをデコードする
$responseData = json_decode($response, TRUE);
$access_token = $responseData["access_token"];
//API 呼び出しを設定する
//データを取得する
($_POST ["requestBody"]) {
$data = json_decode($_POST["requestBody"]);
} else {
$data = array();
}
//リクエストタイプを取得するか、デフォルトで GET
($_POST ["requestType"]) {
$method = $_POST["requestType"];
} else {
$method = "GET";
}
//フォームデータから URL と認証情報を取得
$request = $_POST["url"];
//httpリクエストを送る
$ch = curl_init($request);
curl_setopt_array ($ch, 配列 (
CURLOPT_CUSTOMREQUEST = > $メソッド、
CURLOPT_RETURNTRANSFER = > 真、
CURLOPT_SSL_VERIFYPEER = > 偽、
CURLOPT_HTTPHEADER = > 配列 (
'コンテンツタイプ:アプリケーション/JSON ',
「認証:ベアラー {$access_token}」,
)、
>CURLOPT_POSTFIELDS = json_encode ($データ)
)));
$response = curl_exec($ch);
curl_close ($ch);
//エラーをチェックする
($応答=== 偽) {
エコー「エラー:「+$応答;
死ぬ (curl_error ($ch));
}
//レスポンスをデコードする
//$responseData = json_decode ($レスポンス、真);
//AJAX 呼び出し元にレスポンスを返す
エコー$レスポンス;
?>
ログをクリアする
この単純なPHPアプリは、JavaScriptファイルを元の状態に復元し、古い動画IDをクリアするだけです:
<?php
$logFileLocation = "di.json";
$freshContent = array ();
$encodedContent = json_encode($freshContent);
ファイル_put_contents ($logfileLocation, $encodedContent);
エコー 'ログファイルがクリアされました-< href=」di-log.html「> ダッシュボードに戻る < /a > ';
?>