This is a javascript client library for interacting with the Vbrick Rev API. It should work in node.js 14+, evergreen browsers (i.e. not IE), and deno.
This library is intended for use with VBrick Rev.
The compiled library is at dist/rev-client.js
.
npm install @vbrick/rev-client
- Browser - This library is in ESM module format - it assumes use of an evergreen browser that has
fetch
,AbortController
, etc. - node.js - Node.js 14 or above required. It will work with commonjs (
require
) or ES Module (import
) projects. - deno - Should be compatible, though testing is limited. You'll need
--allow-net
permissions at minimum.
By default CORS (Cross Origin Resource Sharing) is disabled for Rev Cloud tenants. This means this library will not work out of the box in the browser. You should open a ticket with Vbrick Support if this feature isn't yet configured.
To verify if CORS is enabled for your account check the headers response from https://YOUR_REV_TENANT_URL/api/v2/accounts/branding-settings
- it doesn't require authentication.
On-Prem note: this library targets the latest version of Rev. Some API endpoints may not be available or work as expected in older versions of Rev On-Prem.
import {RevClient} from '/path/to/rev-client.js';
// create client object
const rev = new RevClient({
url: 'https://my.rev.url',
apiKey: 'my.user.apikey',
secret: 'my.user.secret',
// or can login via username + password
// username: 'my.username',
// password: 'my.password',
logEnabled: true, // turn on debug logging
keepAlive: true // automatically extend session
});
(async () => {
// call login api and start session. will throw error if invalid login
await rev.connect();
// create a category
const {categoryId} = await rev.category.create({ name: 'Created Via API' });
// get details about this category
const categoryDetails = await rev.category.details(categoryId);
console.log('category details: ', categoryDetails);
// get the account media contributor role
const mediaContributorRole = await rev.admin.getRoleByName('Media Contributor');
// create a new user, with the media contributor role
const userId = await rev.user.create({
username: 'new.user',
firstname: 'new',
lastname: 'user',
roleIds: [mediaContributorRole.id]
});
// upload a video, and assign 'new.user' as the owner of that video, and add to the category created above
// if browser instead of node.js - pass in a File object instead of the filepath
const videoId = await rev.upload.video("/path/to/local/video.mp4", {
uploader: 'new.user',
title: 'video uploaded via the API',
categories: [categoryDetails.name], // ['Created Via API']
unlisted: true,
isActive: true
/// ...any additional metadata
});
console.log('Video uploaded!', videoId);
await rev.disconnect();
})();
NOTE Unless otherwise noted all methods of RevClient
are async (they return a Promise
)
url
: REQUIRED - URL of Rev instance (exhttps://company.rev.vbrick.com
)keepAlive
:true
/false
(Default:true
) - If true then automatically extend the Rev session at regular intervals (untilrev.disconnect()
is called). If false then you must manually callextendSession()
to maintain a valid token.logEnabled
:true
/false
(Default:false
) - Enable/disable debug logginglog
:(logLevel, ...args) => void
- Custom log function. Default is to log to console
And one of following login options (apiKey
+secret
, username
+password
or oauthConfig
):
-
User API Key:
apiKey
: User API Key of Rev Usersecret
: User Secret of Rev User
-
Username/Password login:
username
: Username of Rev user.password
: Password of Rev user.
-
OAuth session (NOTE: This is for OAuth 2.0 browser-redirect flow to create sessions, it's not intended for server-side only login)
oauthConfig
: OAuth configuration objectoauthConfig.oauthApiKey
: API key from Rev Admin -> Security. This is a DIFFERENT value from the User Token used for API login/extend sessionoauthConfig.oauthSecret
: API secret from Rev Admin -> Security. This is a DIFFERENT value from a user'ssecret
oauthConfig.redirectUri
: The local URL Rev should redirect user to after logging in. This must match EXACTLY what's specified in Rev Admin -> Security for the specified API key
You can pass in an existing sessionState
to the constructor to reuse a session token
(assuming it isn't expired). When you include sessionState
the password
, secret
or authCode
values aren't necessary, however if not included you won't be able to re-login, just extend the session.
const initialRev = new RevClient({ url, apiKey, secret });
await initialRev.connect();
// store state for use elasewhere (like /tmp/ storage in a serverless environment)
// has { token, expiration }
let savedState = rev.sessionState;
// ... time passes ...
const revWithReusedSession = new RevClient({ url, apiKey, sessionState: savedState })
// or set after initial configuration
revWithReusedSession.sessionState = savedState
isConnected
- Boolean value that indicates if connect()
has been called and the session isn't expired
Make a request to a specific API endpoint. get
,post
,put
,patch
and delete
are helpers to set the method
value of the main request call
method
- HTTP Verb to useendpoint
- Path for call to make. This will be relative to theurl
set inRevClient
data
- Query parameters forget/delete
requests, Body forput/post/patch
requests.options
- Additional request parameters to pass tofetch
.options.responseType
-json|text|blob|stream
- specify how to decode the response. Default is to autodetect based on the response.stream
means pass through without decoding.
statusCode
- HTTP Status Codeheaders
- Headers objectbody
- Response payload, already decoded based onoptions.responseType
response
- rawfetch
Response object
Custom Error with the following additional properties:
status
- HTTP Status Codeurl
- Request URLcode?
- Rev-specific error codedetail?
- Rev-specific detail message;
rev = new RevClient({ url: "https://my.rev.url", ...credentials });
await rev.request('get', '/api/v2/users/my.username', { type: 'username' });
// HTTP GET https://my.rev.url/api/v2/users/my.username?type=username
Make HTTP requests with the specified verb (get/post/patch/etc). Unlike request()
these calls return the body directly.
endpoint
- Path for call to make. This will be relative to theurl
set inRevClient
data
- Query parameters forget/delete
requests, Body forput/post/patch
requests.options
- Additional request parameters to pass tofetch
.options.responseType
-json|text|blob|stream
- specify how to decode the response. Default is to autodetect based on the response.stream
means pass through without decoding.
The Response payload, already decoded based on options.responseType
RevClient
also wraps API functionality into separate namespaces. They mostly follow the API Documentation categorization.
admin.getRoleByName(name)
- Get a specific Role { id: string, name: string }
based on the Role's name (i.e. 'Media Viewer')
auth.buildOAuthAuthenticateURL(config, state?)
- returns Promise<string>
. Sign and format an OAuth Authorization URL (for browser login flow)
auth.parseOAuthRedirectResponse(url)
- Synchronous, returns { isSuccess, authCode, state, error}
based on returned information
All upload functions take in a file
argument and an options
argument.
file
:string
,stream.Readable
orBlob
if using node.js.File
if browser. Ifstring
(and using node.js) then treat as a file path and load the file from disk.options
:- Any
fetch
options (most importantlysignal
for passing in anAbortSignal
) filename?
:string
- the filename used in theContent-Disposition
field header.contentType?
:string
- the content type of the filecontentLength?
:number
- the known content length of the file. This is rarely needed, but can be used if passing along a HTTP StreamuseChunkedTransfer?
:boolean
- tell upload to not calculate a content length automatically, and just send asTransfer-Encoding: chunked
- Any
Note: Rev expects the file extension and content-type to agree. This library will attempt to automatically fix the filename/content-type as needed.
videoId
: string, videoId of the video in questionchapters
: array of Chapter objects. At least one oftitle
orimageFile
must be specifiedtime
: (required)string
title
:string
imageFile
:string
,stream.Readable
orBlob
if using node.js.File
if browser. Seefile
in the Shared Options section above.
action
: One of two string values (default:replace
):"append"
: Update Video Chapters)"replace"
: Upload Video Chapters
options
: Additionalfetch
options
file
:string
,stream.Readable
orBlob
if using node.js.File
if browser. Seefile
in the Shared Options section above.metadata
: Video metadata - see API docs. Note that at minimumuploader
MUST be included.options
: See Shared Options section above.
The ID of the video
upload.transcription(videoId, file, language?, options?)
- Upload a transcription / close captions file
query
: See API Docs for available search optionsoptions
: Optional, Additional options for requestoptions.maxResults
: number, set the maximum number of results to return.options.onProgress
:(items: <array>, current, total) => void
- callback for each time a page is queried from Rev.options.onScrollExpired
:(err: ScrollError) => void
- Search results use a scrollID cursor that expires after 1-5 minutes from first request. If the scrollID expires then onScrollExpired will be called with a ScrollError. Default behavior is to throw the error.
This method returns a SearchRequest
object, that includes the following methods:
.exec()
- Get all results as an array.nextPage()
-{ current, total, items, done }
- Get the search results one page at a time[async iterator]
- The class also implementsAsyncIterator
, so can be used as aStream
or usingfor await
// get the 10 most recent videos that match 'puppy' in the tags/keywords field
const request = rev.video.search({ q: 'puppies', searchField: 'tags', sortField: 'whenUploaded', sortDirection: 'desc' }, { maxResults: 10 });
const results = await request.exec();
// get ALL videos in the account and report their title, reporting progress and ignoring errors
const request = rev.video.search(undefined, {
onProgress(items, current, total) {
console.log(`PROGRESS: ${current}-${current + items.length} of ${total}`);
},
onScrollExpired(err) {
console.warn('Error while getting video results, ignoring: ', err);
}
});
for await (let video of request) {
console.log(`Video ${video.id}: ${video.title} | duration: ${video.duration}`);
}
The library exposes some additional utilities:
The Rev API includes rate limiting for some API endpoints. If you exceed the limit then you'll receive a 429
error response. This function can help to automatically avoid that threshold.
See the API Documentation on Rate Limiting for current limits.
fn
: function to be rate-limitedoptions
:fn
: function to be rate-limited (if not set as first argument)perSecond
: set limit toX
executions per secondperMinute
: set limit toX
executions per minuteperHour
: set limit toX
executions per hourlimit
: allowlimit
executions perinterval
millisecondsinterval
: allowlimit
executions perinterval
millisecondssignal
:AbortSignal
to cancel all pending executions.
Wrapped function with same arguments as passed in fn
, with added:
.abort()
- cancel all pending executions
import { RevClient, rateLimit } from '@vbrick/rev-client';
const rev = new RevClient(options);
// assumes this tool is only tool in the account using API uploads
const throttledUpload = rateLimit({
fn: (...args) => rev.upload.video(...args),
perMinute: 30
});
const numberOfVideos = 100;
for (let i = 0; i < numberOfVideos; i++) {
// same arguments as rev.upload.video
const videoId = await throttledUpload(file, {title: `video ${i}`, uploader: `my.username` });
}
Get the expected extension for a mime-type supported by Rev for upload. If none found it will return the defaultExtension
(or .mp4
if none specified)
Get the expected mime-type for the specified extension (.ext
). If none found it will return the defaultType
(or video/mp4
if none specified)
Custom error returned for error status code responses
status
:number
- http status codeurl
:string
- original URL of requestcode
:string
- Rev-specified error string, for exampleMalformedRequest
,RequiredFieldMissing
orInvalidFileType
detail
:string
- Additional details about error (if passed).
Custom error returned if a paged search request has expired (usually because more than 1 minute has passed between requests for more pages of data)
This code is distributed "as is", with no warranty expressed or implied, and no guarantee for accuracy or applicability to your purpose.