
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
Comprehensive Ooyala Backlot API wrapper for Node.js
Ooyala SDK for handling all video, label, and thumbnail related data. Easy-to-use
methods for video asset uploading and retry logic, as well as improved error handling /
interpreting from Ooyala API responses.
This library was built with love and hate through trial and error in working with the Backlot API for years in production. It also aims to vastly reduce the logic in complex upload workflows as well as try to make sense and normalize the multitude of error types and responses from Ooyala.
All methods in this SDK are promise based, and strictly validated. If any method
is called with missing or invalid parameter types, it will be rejected with the
ValidationError described below. The aim is to prevent any type of bad or
unrecoverable state within Backlot, as it often requires human intervention to continue.
All responses and data types are generally a pass-through of what comes from the Ooyala
API, no object properties are modified other than sanitization on video title and
description. Typically, the normalization is to keep consistent data responses.
From this { items: [{}, {}, {}] } to this [{}, {}, {}]
With npm
npm install ooyala
var Ooyala = require('ooyala')
var api = new Ooyala({
secret: 'so secret'
, key: 'such key'
// defaults
, endpoint: 'https://api.ooyala.com'
, chunkSize: 10485760
, expires: 200
})
var fs = require('fs')
fs.readFile('/tmp/asset.mp4', function(err, buffer) {
// Setup our new video asset. This example can be used as an `update/replacement`
// for existing videos if an `embed_code` property is added.
var myVideo = {
name: 'awesome thing i did'
, description: 'mom get the camera!!'
, file_name: 'my_asset.mp4' // Ooyala tracks these names as unique keys
, file_size: buffer.length // Ooyala needs this to generate upload URLs
, metadata: {
made_by: 'me!'
, internal_id: 124109
}
, labels: [
'Summer 2016'
, 'Foods/Popcorn'
]
}
api
// Create or update the asset, set the metadata, then sync the given labels.
.syncVideoAsset(myVideo)
// Here you can check any kind of video status, or save the remote data before
// continuing. It is recommended to capture state here in case of upload failure.
.then(function(remoteVideo) {
// Check if something else is uploading it, we could also check for `duplicate`
// or `error` status, as Ooyala will respond with an error if attempted.
if (remoteVideo.status === 'uploading') {
return Promise.reject(new Error('ooyala will error if we try'))
}
// The `embed_code` property is the primary video ID
var videoId = remoteVideo.embed_code
// Allow the SDK to handle the multi-step upload workflow, with retry logic
return api.uploadFullVideoAsset(videoId, buffer)
})
.then(function() {
// All done!
})
// Error handling
.catch(Ooyala.ProcessingVideoError, function(err) {
// The video is still transcoding, check for updates from Ooyala before trying again
})
.catch(Ooyala.DuplicateVideoError, function(err) {
// The video `file_name` used is in use by another video asset
})
.catch(Ooyala.Error, function(err) {
// Something else went wrong within the Ooyala API or this SDK
})
.catch(function(err) {
// Default error catcher, should always be used with Promises
})
})
Here is an example of how to check for video updates in Ooyala Backlot. The following
code will check for all video updates since yesterday, including human changes through
the UI, as well as video status changes, (uploading, transcoding, live, ...)
then use the last known ooyala update time as the next starting point for the search.
// Starting search date
var start = new Date(Date.now() - (24 * 60 * 60 * 1000))
// Sleep / delay time before next fetch iteration
var sleep = 5 * 60 * 1000
// API polling method
function fetch(search, sleep) {
api
.searchVideos({
where: `update_at>'${search.toISOString()}'`
})
.then(function(videos) {
// Find all `update_at` timestrings from ooyala
var updates = videos.map(function(x) {
return +new Date(x.updated_at)
})
// Update the search date to the last known update
search = Math.max.apply(null, updates.concat(search))
/*!
* Do something with the results, such as saving to an internal database,
* sending an outbound HTTP request, or adding to a message queue for processing
*/
// Sleep a while then do it again
setTimeout(search, sleep)
})
.catch(function(err) {
console.error('Oh bother', err)
process.exit(1)
})
}
// Start the endless polling loop
fetch(start, delay)
Create a new Neulion API wrapper
config - Object - api options
endpoint - String - Ooyala HTTP endpoint (optional, default https://api.ooyala.com)key - String - API Keysecret - String - API SecretchunkSize - Number - File upload chunk size (default 10485760)expires - Number - API query expiration in ms (optional, default 2000)retryLimit - Number - Upload asset retry limitvar api = new Ooyala(config)
Ooyala API request wrapper, adds all necessary key and signature data, as well as custom error handling for invalid responses.
options - Object
method - String - HTTP method (GET, POST, PUT, PATCH, DELETE)route - String - Ooyala API routeparams - Object - querystring parametersoptions - Object - any request optionsapi
.request({
method: 'GET'
, route: '/v2/assets'
, params: {
orderby: 'created_at ascending'
}
, options: {}
)
.then(function(response) {
// yay we did it!
})
.catch(function(err) {
// oh noooes...
})
Request Shortcuts:
api.get(options)
api.post(options)
api.put(options)
api.patch(options)
api.delete(options)
Generate the request signature for API access. Generally for internal use.
options - Object
method - String - http methodroute - String - api routeparams - String - querystring paramsbody - String|Buffer - request bodyvar signature = api.sign({
method: 'GET'
, route: '/v2/assets'
, params: {}
})
The following methods correspond to the top level label assets stored in Backlot.
Fetch all video labels from ooyala. This can become slow if there are many labels to retrieve.
api.getLabels().then(function(labels) {})
Create a new label with the given name.
name - String - label nameapi.createLabel('/Awesome/Sauce').then(function(labelDetails) {})
Fetch the full label details from ooyala
name - String - label nameapi.getLabelDetails('/Awesome/Sauce').then(function(labelDetails) {})
Delete a label from ooyala, this method is slightly different as it requires the
primary label id, rather than the name.
id - String - label idapi.deleteLabel('/Awesome/Sauce').then(function(ooyalaResponse) {})
Convenience method for finding details on all existing labels, as well as creating any labels that do not yet exist. Returns an array of label details. This method is recommended for use above the others, as it provides consistent results with minimal app logic.
The caveat in this method is that it uses the getLabels method described above,
if this proves to be a performance issue, then the logic here will be optimized.
labels - Array - list of label namesvar labels = [
'Categories/Food'
, 'Categories/Drinks'
]
api.syncLabels(labels).then(function(labelArray) {})
The following methods correspond to the linking of Labels and Videos within Backlot. Any label used here must exist before it can be used.
Find all labels associated with a given video
videoId - String - video id / embed codeapi.getVideoLabels('asest_id').then(function(labels) {})
Add a list of labels to a given video
videoId - String - video id / embed codelabelIds - Array - list of video idsvar labels = ['Foo', 'Bar', 'Baz']
api
.syncLabels(labels)
.then(function(labelList) {
var labelIds = labelList.map(function(x) { return x.id })
return api.addVideoLabels('asest_id', labelIds)
})
Remove a given label from the video
videoId - String - video id / embed codelabelId - String - label idapi.removeVideoLabel('asset_id', 'label_id').then(function() {})
Convenience method for removing multiple labels from a video, which is currently
not supported via Ooyala API. This will map to removeVideoLabel above.
videoId - String - video id / embed codelabelIds - Array - list of video idsapi.removeVideoLabels('asset_id', labelIdList).then(function() {})
Remove all associated labels with the video
videoId - String - video id / embed codeOoyala provided shortcut for removing all labels and adding the given label ids. This will remove any existing label data.
videoId - String - video id / embed codelabelIds - Array - list of video idsConvenience method for syncing the given label names in ooyala, then replacing all video labels with the IDs returned from ooyala. If given an empty list, this will effectively remove all label associations.
videoId - String - video id / embed codelabelNames - Array - list of video namesapi.syncVideoLabels('asset_id', [
'Topics/HTML'
, 'Topics/JS'
, 'Category/Recent'
])
The following methods correspond to top level video objects in Backlot.
Create a new video object in ooyala.
data - Object - video id / embed codeapi
.createVideoAsset({
name: 'my video'
, description: 'so awesome'
, file_name: 'video.mp4'
, file_size: 309232
})
Delete a video
videoId - String - video id / embed codeGet the top level details of a video
videoId - String - video id / embed codeGet associated video metadata
videoId - String - video id / embed codeSet the video metadata
videoId - String - video id / embed codemetadata - Object - metadataGet the video player information
videoId - String - video id / embed codeGet all video source information
videoId - String - video id / embed codeGet all video streams
videoId - String - video id / embed codeShortcut for getting all related video data from Ooyala, includes the following
related content: metadata, labels, player, source_file_info,
primary_preview_image, and streams.
videoId - String - video id / embed codeapi
.getFullVideoDetails(id)
.then(function(video) {
// video.status (`uploading`, `transcoding`, `live`)
})
.catch(function(err) {
// ...
})
Search the Ooyala API for videos. Please see the official documentation below for how to use the method, as it is not the easiest thing to figure out.
params - Object - api search parameters
order_by - Stringlimit - Numberinclude - Stringwhere - Stringvar date = new Date(Date.now() - 600000).toISOString()
api
.searchVideos({
where: `updated_at>${date}`
, orderby: 'updated_at ascending'
, include: 'labels,metadata'
, limit: 10
})
.then(function(videos) {
// ...
})
Workflow for creating a full video asset in Ooyala using the following steps:
videoData - Object - full video objectbuffer - Buffer|Uint8Array - raw asset datafs.readFile('video.mp4', function(err, buffer) {
var video = {
name: 'amaze video'
, description: 'such quality, many likes'
, file_name: 'the-video-name-1.mp4'
, file_size: buffer.length
, hosted_at: 'http://some-site.wow'
, metadata: { created_by: 'doge' }
, labels: ['Wow', 'Such', 'Footage']
}
api.createFullVideoAsset(video, buffer)
})
Get a list of generated preview images for a given video
videoId - String - video idSet the video to use the manually uploaded thumbnail image
videoId - String - video idSet the video to use an auto generated preview image at an optional given time.
See the time property on the response from the getVideoThumbnails method.
videoId - String - video idtime - Number - pre-generated thumbnail time (optional)Upload a given raw image asset, it will still need to be manually set for usage
using the setVideoToUploadedThumbnail method.
videoId - String - video idimageBuffer - Buffer|Uint8Array - raw image dataUpload a closed captions file buffer for a video
videoId - String - video idccFileBuffer - Buffer|Uint8Array - closed caption file bufferThe following methods are used for uploading the actual video file asset to ooyala. It is highly recommended to use the convenience methods below rather than walk through each step manually yourself. If you do need to use custom upload logic, all methods are exposed, however, please create an issue so that this process may be improved for all who use it over time.
With that out of the way, asset upload and replacement in Ooyala Backlot is generally a four to five step process, in which error handling often requires data from all steps in the process, for either reporting or retry purposes.
Fetch the pre-signed ooyala provided upload URL(s) for each file chunk needed. If you are not using the convenience methods of this SDK for uploading, you will need the URL array from this method for subsequent chunk upload and retry logic.
videoId - String - video idHalf-convenience method for uploading an asset, primary used internally, but can be called directly if doing custom upload logic.
videoId - String - video iduploadUrls - Array - upload urls from the getVideoUploadUrl methodassetBuffer - Buffer|Uint8Array - raw asset dataUpload the designated file chunk to the designated ooyala provided upload url.
This is part of what makes uploading tricky. The chunks are based on what you set
the chunkSize to when initializing the SDK. So, given a 5mb file, with a chunkSize
of 2mb, it would take 3 upload urls, and 3 2mb whole or partial chunks to fully
upload the asset.
uploadUrl - String - ooyala provided upload urlbufferChunk - Buffer|Uint8Array - partial video buffer chunkOnce finished uploading all data chunks to all upload URLs, you must (for whatever reason) tell the Ooyala API that you have finished uploading.
videoId - String - video idSame as above but for replacement workflow
videoId - String - video idUpdate an existing video's data in ooyala.
videoId - String - video idvideoData - Object - video dataDESCRIPTION
DESCRIPTION
DESCRIPTION
DESCRIPTION
DESCRIPTION
DESCRIPTION
The following error classes are dynamically created based on the HTTP response of any given API call to ooyala. It is currently unclear which routes can produce which of the following errors. As this SDK is large, I have yet to associate these with each method correctly, so for now, assume any method in this SDK can return any of these errors. Some should stand out as obvious based on what you are doing.
Top level generic error class, all of the following error classes are derived from this.
Alias: OoyalaError
Internal validation error, all methods validate before sending any requests to prevent corrupted state or wasted API calls to ooyala.
Top level generic request error, either this or the generic Error class should
always be handled, as it is not guaranteed that there is a detailed class representing
all error states from Backlot. All following classes are derived from this.
Given that a request happened, all RequestError classes should have the following:
response - request module JSON responsemessage - string decoded ooyala responsemessageData - object decoded ooyala responseThe string data should always exist, some error responses from Ooyala contain JSON
data, or are themselves, JSON data, and some are simply string responses. So,
brace yourself, there be dragons here. The messageData may not exist, or always
be empty, and the message may be a stringified object. Because it is unknown,
both are provided.
An action was attempted against an already processing video
This asset (filename) already exists in Backlot. A filename change can bypass this, however, it should not be needed as a workaround.
The video is either currently uploaded, or is stuck in an aborted upload state. If the former, then the current action can likely be tried again once the upload finishes, however, if it is the latter, then the asset must be manually deleted from Backlot as there is no way to continue, either via a new upload or asset replacement.
The video asset upload is missing chunks / data, this error is actually recoverable, as Ooyala is attempting to let you know to try again. The logic in the shortcut / convenience methods will handle this for you.
An asset or thumbnail change to the current video is too soon since the last upload
or replacement. The timing here is unknown, error was discovered while running tests,
I would guess this is roughly 30 seconds.
General 404 response from Ooyala, for any data type.
Either asking for an asset that should 404 on your account, but exists somewhere
in Backlot, or you have invalid credentials. It is probably invalid credentials.
This really shouldn't happen with this SDK, in the wild this happens frequently as the requirements for the API signature are not exactly clear, meaning that the signature code here is a really good guess. If you encounter this error, please report it and how you did it.
This is Ooyala's general 'ValidationError' response, this SDK attempts to prevent this type of error from happening beforehand, as it is generally representative of a malformed request, or missing parameters. If encountered, please report.
This may only apply to thumbnails, the image you are trying to upload is over the max
limit from Ooyala. It is unclear what that exact limit is, but seems to definitely be
under 10mb.
For any text given to Ooyala, there cannot be any hidden characters, generally this is seen for video descriptions, as its a pretty free-form text field. This SDK should take care of this issue for you. If encountered, please report.
FAQs
Ooyala API
We found that ooyala demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.