Einleitung
In diesem Dokument wird erläutert, wie Sie den Status von Jobs verfolgen können, indem Sie entweder Statusanforderungen an die senden CMS API oder mit Dynamic Ingest API Benachrichtigungen. Wir bieten auch eine Beispiel-Dashboard-App, die den Prozess automatisiert.
Beachten Sie, dass der Status von Aufnahmejobs nur für Jobs verfügbar ist, die in den letzten 7 Tagen gesendet wurden.
Status anfordern
Sie erhalten den Status von dynamischen Aufnahmeaufträgen (Aufnehmen, Ersetzen oder erneutes Transcodieren) mithilfe von diese CMS API Endpunkte - Beachten Sie, dass diese Endpunkte für funktionieren Nur Dynamic Delivery-Jobs::
Status für alle Jobs abrufen
https://cms.api.brightcove.com/v1/accounts/{account_id}/videos/{video_id}/ingest_jobs
Die Antwort wird ungefähr so aussehen:
[
{
"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"
}
]
Status für einen bestimmten Job abrufen
https://cms.api.brightcove.com/v1/accounts/{account_id}/videos/{video_id}/ingest_jobs/{job_id}
Die Antwort wird ungefähr so aussehen:
{
"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"
}
Die möglichen Werte für state
sind:
processing
: Verarbeitung, Video ist noch nicht abspielbarpublishing
: Mindestens eine abspielbare Wiedergabeversion wurde erstellt und das Video wird für die Wiedergabe vorbereitetpublished
: Mindestens eine Wiedergabe ist für die Wiedergabe verfügbarfinished
: Mindestens eine Audio-/Videowiedergabe wurde verarbeitetfailed
: Verarbeitung fehlgeschlagen; Wenn Sie nicht herausfinden können, was schief gelaufen ist, wenden Sie sich an den Support
Benachrichtigungen erhalten
Die oben beschriebene Methode für den Anforderungsstatus funktioniert zwar, aber wenn Sie auf einen bestimmten Status warten (published
oder finished
). Wir werden uns nun ansehen, wie Sie eine App zum Umgang mit Benachrichtigungen erstellen können.
Die Dynamic Ingest-Benachrichtigungen geben Ihnen alle Informationen, die Sie benötigen, um zu wissen, wann Ihr Video bereit ist — Sie müssen nur wissen, wonach Sie suchen müssen... und definieren, was „bereit“ für Ihre Systeme bedeutet. Dieses Diagramm fasst den Arbeitsablauf zusammen:
Dynamische Aufnahmebenachrichtigungen
Der Dynamic Ingest-Benachrichtigungsdienst sendet Ihnen Benachrichtigungen für verschiedene Arten von Ereignissen. Die beiden am nützlichsten, um herauszufinden, wann das Video "bereit" ist, sind diejenigen, die anzeigen, dass bestimmte Wiedergabeversionen erstellt wurden, und diejenige, die anzeigt, dass die gesamte Verarbeitung abgeschlossen ist. Hier sind jeweils Beispiele:
Benachrichtigung über dynamische Wiedergabe erstellt
Beachten Sie in diesem Beispiel:
- Die
videoId
value gibt an, für welches Video die Wiedergabe bestimmt ist (falls mehrere Ingest-Jobs ausgeführt werden) - Die
entity
value ist der erstellte dynamische Wiedergabetyp - wenn die
status
Wert ist "SUCCESS", die Wiedergabe wurde erfolgreich erstellt
Bearbeitung der vollständigen Benachrichtigung
Beachten Sie in diesem Beispiel:
- Die
videoId
undjobId
Werte geben an, für welches Video dies gedacht ist (falls mehrere Aufnahmejobs ausgeführt werden) - Wenn die
status
Wert ist "SUCCESS", das Video wurde erfolgreich verarbeitet
Um Benachrichtigungen zu erhalten, müssen Sie ein Feld "Rückrufe" in sich aufnehmen Dynamic Ingest API Anfragen, die auf eine oder mehrere Rückrufadressen verweisen:
{
"master": {
"url": "https://s3.amazonaws.com/bucket/mysourcevideo.mp4"
}, "profile": "multi-platform-extended-static",
"callbacks": ["https://host1/path1”, “https://host2/path2”]
}
Beispiel-Dashboard
In diesem Abschnitt wird erläutert, wie Benachrichtigungen zusammengestellt werden können, um ein einfaches Dashboard für die Dynamic Ingest API zu erstellen. Der Handler für Benachrichtigungen analysiert Benachrichtigungen aus dem Dynamic Ingest API um die Verarbeitung vollständiger Benachrichtigungen zu identifizieren. Anschließend werden die Videobenachrichtigungen für jedes Video in einer JSON-Datei einem Array von Objekten hinzugefügt. Das Dashboard selbst ist eine HTML-Seite, die die JSON-Datei importiert, um die Benachrichtigungsdaten abzurufen. Es verwendet die IDs, um eine Anfrage an die CMS-API zu stellen, um die Video-Metadaten abzurufen.
Hier ist die High-Level-Architektur der App:
Die App-Teile
Der Handler für Benachrichtigungen ist in PHP integriert - er sucht nach der Verarbeitung vollständiger Benachrichtigungen und fügt die Video-ID zu einem Array in einer separaten JavaScript-Datei hinzu:
<? php
// POST funktioniert nicht für JSON-Daten
$ problem = "Keine Fehler";
versuche {
$ json = file_get_contents ('php: // input');
$ decoded = json_decode ($ json, true);
} catch (Ausnahme $ e) {
$ problem = $ e-> getMessage ();
echo $ problem;
}
// vollständige Benachrichtigung
$ notification = json_encode ($ decodiert, JSON_PRETTY_PRINT);
// Beginnen Sie mit dem Extrahieren der nützlichen Teile der Benachrichtigung
// Suchen Sie für Dynamic Delivery nach 'videoId'.
if (isset ($ decoded ["videoId"])) {
$ videoId = $ decodiert ["videoId"];
} elseif (isset ($ decoded ["entity"])) {
$ videoId = $ decodiert ["Entität"];
} sonst {
$ videoId = null;
}
if (isset ($ decoded ["entityType"])) {
$ entityType = $ decoded ["entityType"];
} sonst {
$ entityType = null;
}
if (isset ($ decodiert ["Status"])) {
$ status = $ decodiert ["Status"];
} sonst {
$ status = null;
}
if (isset ($ decoded ["action"])) {
$ action = $ decodiert ["Aktion"];
} sonst {
$ action = null;
}
// Wenn die Benachrichtigung für den abgeschlossenen Titel ist, handeln Sie
if (($ entityType == 'TITLE') && ($ action == 'CREATE')) {
if (($ status == 'SUCCESS') || ($ status == 'FAILED')) {
$ newLine = "\\ nvideoIdArray.unshift (". $ videoId. ");";
// Sag PHP, wo es die Protokolldatei finden kann und sag PHP, dass es sie öffnen soll
// und füge den zuvor erstellten String hinzu.
$ logFileLocation = "video-ids.js";
$ fileHandle = fopen ($ logFileLocation, 'a') oder die ("- 1");
chmod ($ logFileLocation, 0777);
fwrite ($ fileHandle, $ newLine);
fclose ($ fileHandle);
}
}
// Vollständige Benachrichtigung für Audit Trail speichern
$ logEntry = $ Benachrichtigung. ", \\ n";
$ logFileLocation = "full-log.txt";
$ fileHandle = fopen ($ logFileLocation, 'a') oder die ("- 1");
chmod ($ logFileLocation, 0777);
fwrite ($ fileHandle, $ logEntry);
fclose ($ fileHandle);
echo "Dynamic Ingest Callback App läuft";
? >
JSON-Datei:
Die JSON-Datei ist zunächst ein leeres Array ( []
) — Daten werden vom Benachrichtigungshandler hinzugefügt.
Armaturenbrett
Das Dashboard enthält HTML und JavaScript zum Abrufen der Benachrichtigungsdaten und zusätzlicher Videodaten aus dem CMS API und schreiben Sie die Ergebnisse in eine Tabelle:
<!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>
Proxy
<? php
/ **
* brightcove-learning-proxy.php - Proxy für Brightcove RESTful-APIs
* erhält ein Zugriffstoken, stellt die Anfrage und gibt die Antwort zurück
* Zugriff auf:
* URL: https://solutions.brightcove.com/bcls/bcls-proxy/bcsl-proxy.php
* (Beachten Sie, dass Sie * immer * über HTTPS auf den Proxy zugreifen sollten)
* Methode: BEITRAG
*
* @post {string} url - die URL für die API-Anfrage
* @post {string} [requestType = GET] - HTTP-Methode für die Anforderung
* @post {string} [requestBody = null] - JSON-Daten, die mit Schreibanforderungen gesendet werden sollen
*
* @returns {string} $ response - Von der API empfangene JSON-Antwort
* /
// CORS-Aktivierung
header („Access-Control-Allow-Origin: *“);
// Anfrage für Zugriffstoken einrichten
$ data = array ();
// //
// ändere die folgenden Werte, um diesen Proxy mit einem anderen Konto zu verwenden
// //
$ 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, array (
CURLOPT_POST => TRUE,
CURLOPT_RETURNTRANSFER => WAHR,
CURLOPT_SSL_VERIFYPEER => FALSCH,
CURLOPT_USERPWD => $ auth_string,
CURLOPT_HTTPHEADER => Array (
'Inhaltstyp: application / x-www-form-urlencoded',
),
CURLOPT_POSTFIELDS => $ data
));
$ response = curl_exec ($ ch);
curl_close ($ ch);
// Auf Fehler prüfen
if ($ response === FALSE) {
die (curl_error ($ ch));
}
// Dekodiere die Antwort
$ responseData = json_decode ($ response, TRUE);
$ access_token = $ responseData ["access_token"];
// API-Aufruf einrichten
// Daten bekommen
if ($ _POST ["requestBody"]) {
$ data = json_decode ($ _ POST ["requestBody"]);
} sonst {
$ data = array ();
}
// Anforderungstyp abrufen oder standardmäßig GET
if ($ _POST ["requestType"]) {
$ method = $ _POST ["requestType"];
} sonst {
$ method = "GET";
}
// URL und Autorisierungsinformationen aus den Formulardaten abrufen
$ request = $ _POST ["url"];
// Sende die http Anfrage
$ ch = curl_init ($ request);
curl_setopt_array ($ ch, array (
CURLOPT_CUSTOMREQUEST => $ method,
CURLOPT_RETURNTRANSFER => WAHR,
CURLOPT_SSL_VERIFYPEER => FALSCH,
CURLOPT_HTTPHEADER => Array (
'Inhaltstyp: application / json',
"Genehmigung: Inhaber {$ access_token} ",
),
CURLOPT_POSTFIELDS => json_encode ($ data)
));
$ response = curl_exec ($ ch);
curl_close ($ ch);
// Auf Fehler prüfen
if ($ response === FALSE) {
echo „Fehler: „+$response;
die (curl_error ($ ch));
}
// Dekodiere die Antwort
// $ responseData = json_decode ($ response, TRUE);
// Rückgabe der Antwort an den AJAX-Aufrufer
echo $ response;
? >
Löschen Sie das Protokoll
Diese einfache PHP-App stellt einfach die JavaScript-Datei in ihren ursprünglichen Zustand zurück und löscht die alten Video-IDs:
<? php
$ logFileLocation = "di.json";
$ freshContent = array ();
$ encodedContent = json_encode ($ freshContent);
file_put_contents ($ logFileLocation, $ encodedContent);
echo 'Protokolldatei gelöscht - <a href="di-log.html"> zurück zum Dashboard </a>';
? >