Private Videos With Custom Players Session Retention
There are quite a few cases where you would want to include other assets in the session where you play your video. In example:
- Displaying a clickable thumbnail that redirects to your video
- Selection of multiple players with a fallback (hls to mp4 fallback)
- Using a custom built player
In these cases, you will have to make multiple requests to api.video assets. As it's a secured session we are using a Session Token in order to retrain the session and make sure it's continuous.
What is a Session Token?
In short a Session Token is api.video's way of retaining the session for every request you make to each asset. You can find the detailed article about session tokens here.
Example for incorrect usage of private videos
Let's take an example where you want to create a clickable thumbnail which will lead to the video. If we just write the following HTML it will not work, you will get a 404 error:
<html>
<head>
</head>
<body>
<a href=\"https://vod.api.video/vod/{video id}/token/{private token}/mp4/source.mp4\">
<img src=\"https://vod.api.video/vod/{video id}/token/{private token}/thumbnail.jpg\" height=\"30%\" width=\"30%\">
</a>
</body>
</html>
How to play private video in a custom built player?
In order to play your private video with a clickable thumbnail or in a custom made player, you will first have to call the session token. Assuming that you are passing an .mp4
video to the player, the flow will be as follows described in the Session Flow document.
Continuous requests while playing private videos on custom player
In some cases you would need to make further requests to get different assets for the video, for example other qualities or different assets (hls or mp4), while retaining the same session. We've made sure that this task is easy as possible for you by using the session token.
Examples
Let look at some cases where we can build an application that will use the Session Token when delivering a private video
Node.js example: Delivering the video with video.js and adding a thumbnail on the top
You can find the source for the example below on GitHub.
Check out an example of consuming private videos and thumbnail with video.js (Node) below.
We first build a wrapper that will make requests to the api.video API, while passing it a hardcoded API key in order to reuse that function in the future.
With the use of the wrapper we then make a request to the /videos endpoint to get the video by id. That function will return the mp4 url of the video from the response.
We need that url in order to extract the private token from it, the private token is needed in order make the request to the /session endpoint and get the session token.
With a regex function, we will extract the private token from the url in the response
Now that we have the private token, we make a request to the /session endpoint
GET https://vod.api.video/vod/{videoId}/token/{private token}/session
- We will get a response with the session token in JSON format.
{"session_token": "111-222-333"}
- We will use the session token and include it as a query string in the GET request to the next asset that we request from the API, in our case it's the thumbnail
GET https://vod.api.video/vod/viXXX/token/AAA-BBB-CCC/thumbnail.jpg?avh=111-222-333
- Finally, our server will generate an HTML response to the client.
You can find the complete code below:
const http = require('http');
const url = require('url');
const base64 = require('base-64');
const vodUrl = 'https://vod.api.video/vod/';
const wsUrl = 'https://ws.api.video/videos/';
//const sample video id = 'xxxxxxxxxxxxxxx';
const apiKey = 'Your API Key';
/************************************************************************
* This is an example of how you can handle private videos with the
* use of session tokens. In the example we will create an HTTP server
* that will handle incoming GET requests, with the video id in the
* query string. Then it will make a request to get the video id from
* the https://ws.api.video/videos/ endpoint, extract the private token
* , get the session token from the /session endpoint and finally consume
* the video and thumbnail.
* ***********************************************************************/
// 1 - First create a server that will accept GET requests, with id as query parameter
const server = http.createServer( async (req, res) => {
const videoIdFromReq = url.parse(req.url, true).query.id;
const videoDetails = await getVideoDetailsById(videoIdFromReq);
const privateToken = await videoDetails.extractPrivateTokenAssets();
const sessionToken = await videoDetails.getSessionToken(privateToken);
const html = await generateHTML(videoDetails.data, sessionToken);
res.write(html);
});
server.listen(3000);
console.log('Node.js web server at port 3000 is running..')
// 2 - Create a handler function for the requests to api.video endpoints with the basic auth
const apiVideoReq = async (url) => {
const headers = new Headers();
headers.append('Authorization', 'Basic' + base64.encode(apiKey + ":"));
const response = await fetch(url, {headers});
return {
httpRawResponse: response,
processHTTPresponse: async () => {
if(response.status === 200) {
const data = await response.json();
return data;
} else {
throw new Error(`unbale to prase JSON, got response status: ${response.status}`)
}
}
}
}
// 3 - Create a function to get the video by id reusing the above functions
const getVideoDetailsById = async (videoId) => {
const completeUrlWithVideoId = `${wsUrl}${videoId}`
const apiResponse = await apiVideoReq(completeUrlWithVideoId);
const videoDetails = await apiResponse.processHTTPresponse();
return {
data: videoDetails,
// 4 - extract the private token from the assets response
extractPrivateTokenAssets: async () => {
const regexBtwnTokenMp4 = /(?<=token\/)(.*?)(?=\/mp4)/;
const regexMatchResults = videoDetails.assets.mp4.match(regexBtwnTokenMp4);
if(regexMatchResults.length > 0) {
return regexMatchResults[0]
} else {
throw new Error(`Was not able to find the private token the asset url: ${assetUrl}`)
}
},
// 5 - get the session token while passing the private token
getSessionToken: async (privateToken) => {
const sessionUrlWithVideoIdAndToken = `${vodUrl}${videoId}/token/${privateToken}/session`
const res = await apiVideoReq(sessionUrlWithVideoIdAndToken);
const data = await res.processHTTPresponse(res);
return data.session_token;
}
}
}
// 6 - generate the HTML with video.js, the mp4 url and the thumbnail, while passing in the session token
const generateHTML = async (data, sessionToken) => {
if(data.assets && data.assets.mp4 && data.assets.thumbnail) {
const mp4Url = data.assets.mp4;
const thumbnailUrl = data.assets.thumbnail;
return `<html>
<head>
<div style="max-width: 150px" >
<img
style="max-width:100%;"
src="${thumbnailUrl}?avh=${sessionToken}">
</div>
</head>
<body><video
controls
preload="auto"
width="640"
height="264"
data-setup="{}"><source src="${mp4Url}?avh=${sessionToken}" type="video/mp4" /></body></html>`
}
}