VOD Upload

How do I offer my customers the ability to upload a video?

So, you’re ready to offer your end users the ability to upload their own videos to your service. Cool! How do you do this in practice? This guide shows you step-by-step how to integrate video upload services into your site using the Dacast APIs!

👍

Our PHP SDK and Node SDK make getting embed codes for your content very simple and provide wrapper functions to perform all of the necessary steps from start to finish, only requiring you to set your API key, and pass the ID of the video content to generate the embed code for. If you are using one of these platforms, it is highly recommended to download and integrate the SDK to facilitate integration of all our API services into your application.

To give your customers/end users the possibility to upload videos to your account, you should create an upload form on your website.

The minimal requirements for inputs are:

  • File selector box
  • Start upload button

You may wish to ask for information such as Video Name (to give the content a descriptive title once it’s uploaded), splashscreen image, and thumbnail image, but this is not essential at this stage.

When a user starts the upload, you will first need to generate a signature that allows you to push the file to Dacast’s S3 bucket.

If you are accessing our API directly, with your API key, you’re going to make a POST request to https://developer.dacast.com/v2/vod, for instance:

curl "https://developer.dacast.com/v2/vod" \
  -X POST \
  -d "{\"source\":\"yourFileNameHere.mp4\",\"upload_type\":\"ajax\",\"callback_url\":\"yourCallbackUrlHere\"}" \
  -H "X-Api-Key: insertYourApiKeyHere" \
  -H "X-Format: default"
const headers = new Headers();
headers.append('X-Api-Key', 'insertYourApiKeyHere');
headers.append('X-Format', 'default');

const body = `{"source":"yourFileNameHere.mp4","upload_type":"ajax","callback_url":"yourCallbackUrlHere"}`;

const init = {
  method: 'POST',
  headers,
  body
};

fetch('https://developer.dacast.com/v2/vod', init)
.then((response) => {
  return response.json(); // or .text() or .blob() ...
})
.then((text) => {
  // text is the response body
})
.catch((e) => {
  // error in e.message
});
const http = require('https');
const init = {
  host: 'developer.dacast.com',
  path: '/v2/vod',
  method: 'POST',
  headers: {
    'X-Api-Key': 'insertYourApiKeyHere',
    'X-Format': 'default'
  }
};
const callback = function(response) {
  let result = Buffer.alloc(0);
  response.on('data', function(chunk) {
    result = Buffer.concat([result, chunk]);
  });
  
  response.on('end', function() {
    // result has response body buffer
    console.log(result.toString());
  });
};

const req = http.request(init, callback);
const body = `{"source":"yourFileNameHere.mp4","upload_type":"ajax","callback_url":"yourCallbackUrlHere"}`;
req.write(body);
req.end();
import requests

url = 'https://developer.dacast.com/v2/vod'
headers = {'X-Api-Key': 'insertYourApiKeyHere','X-Format': 'default'}
body = """{"source":"yourFileNameHere.mp4","upload_type":"ajax","callback_url":"yourCallbackUrlHere"}"""

req = requests.post(url, headers=headers, data=body)

print(req.status_code)
print(req.headers)
print(req.text)
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://developer.dacast.com/v2/vod');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"source\":\"yourFileNameHere.mp4\",\"upload_type\":\"ajax\",\"callback_url\":\"yourCallbackUrlHere\"}");

$headers = array();
$headers[] = 'X-Api-Key: insertYourApiKeyHere';
$headers[] = 'X-Format: default';
$headers[] = 'Content-Type: application/json';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$result = curl_exec($ch);
if (curl_errno($ch)) {
    echo 'Error:' . curl_error($ch);
}
curl_close($ch);
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "{\"source\":\"yourFileNameHere.mp4\",\"upload_type\":\"ajax\",\"callback_url\":\"yourCallbackUrlHere\"}=");
Request request = new Request.Builder()
  .url("https://developer.dacast.com/v2/vod")
  .method("POST", body)
  .addHeader("X-Api-Key", "insertYourApiKeyHere")
  .addHeader("X-Format", "default")
  .build();
Response response = client.newCall(request).execute();

🚧

Note that it is very important to implement a callback script on your server to be notified when the upload and integration of the video is complete in the Dacast systems, since it is an asynchronous process. We’ll look at examples of how that callback looks towards the end of this article.

When you get the signature back, it will look something like:

{
  "acl":"private",
  "bucket":"upload.dacast.com",
  "key":"vod/b21c25ef-1d75-9789-6a92-d8ba13c53a86/none/9f5becc4-7db9-e49f-646a-14e198ddd748",
  "policy":"sfdlkfjwlkarhwoi4u57908237rujhwkeriuq23yr9q8ihe29834y42kbfew,btr12=32ewfak",
  "success_action_status":"201",
  "x-amz-algorithm":"AWS4-HMAC-SHA256",
  "x-amz-credential":"AKIAUERNWEFKSDFSKW/20211104/us-east-1/s3/aws4_request",
  "x-amz-date":"20211104T102930Z",
  "x-amz-signature":"ad538afca4718cd7591e109613631d9678729086b47e0f5ac8ee7171168d48a3"
}

You now take this response body and use it to prepare a new POST request to the Dacast S3 server at upload.dacast.com.

This request will have a multipart/form-data body that contains all of the keys and values in the previous response in the same order as they are given in the response, as well as a final key “file” with the video file that you want to upload as the content of that key.

curl -X POST https://upload.dacast.com \
  --form acl=private \
  --form bucket=upload.dacast.com \
  --form key=vod/b21c25ef-1d75-9789-6a92-d8ba13c53a86/none/9f5becc4-7db9-e49f-646a-14e198ddd748 \
  --form policy=sfdlkfjwlkarhwoi4u57908237rujhwkeriuq23yr9q8ihe29834y42kbfew,btr12=32ewfak \
  --form success_action_status=201 \
  --form x-amz-algorithm=AWS4-HMAC-SHA256 \
  --form x-amz-credential=AKIAUERNWEFKSDFSKW/20211104/us-east-1/s3/aws4_request \ 
  --form x-amz-date=20211104T102930Z \
  --form x-amz-signature=ad538afca4718cd7591e109613631d9678729086b47e0f5ac8ee7171168d48a3 \
  --form file=@localfilename
var formdata = new FormData();
formdata.append("acl", "private");
formdata.append("bucket", "upload.dacast.com");
formdata.append("key", "vod/b21c25ef-1d75-9789-6a92-d8ba13c53a86/none/9f5becc4-7db9-e49f-646a-14e198ddd748");
formdata.append("policy", "sfdlkfjwlkarhwoi4u57908237rujhwkeriuq23yr9q8ihe29834y42kbfew,btr12=32ewfak");
formdata.append("success_action_status", "201");
formdata.append("x-amz-credential", "AKIAUERNWEFKSDFSKW/20211104/us-east-1/s3/aws4_request");
formdata.append("x-amz-date", "20211104T102930Z");
formdata.append("x-amz-signature", "ad538afca4718cd7591e109613631d9678729086b47e0f5ac8ee7171168d48a3");
formdata.append("file", fileInput.files[0], "[PROXY]");

var requestOptions = {
  method: 'POST',
  body: formdata,
  redirect: 'follow'
};

fetch("https://upload.dacast.com", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));
var request = require('request');
var fs = require('fs');
var options = {
  'method': 'POST',
  'url': 'https://upload.dacast.com',
  'headers': {
  },
  formData: {
    'acl': 'private',
    'bucket': 'upload.dacast.com',
    'key': 'vod/b21c25ef-1d75-9789-6a92-d8ba13c53a86/none/9f5becc4-7db9-e49f-646a-14e198ddd748',
    'policy': 'sfdlkfjwlkarhwoi4u57908237rujhwkeriuq23yr9q8ihe29834y42kbfew,btr12=32ewfak',
    'success_action_status': '201',
    'x-amz-credential': 'AKIAUERNWEFKSDFSKW/20211104/us-east-1/s3/aws4_request',
    'x-amz-date': '20211104T102930Z',
    'x-amz-signature': 'ad538afca4718cd7591e109613631d9678729086b47e0f5ac8ee7171168d48a3',
    'file': {
      'value': fs.createReadStream('pathToFile'),
      'options': {
        'filename': 'fileName',
        'contentType': 'application/octet-stream'
      }
    }
  }
};
request(options, function (error, response) {
  if (error) throw new Error(error);
  console.log(response.body);
});
import requests

url = "https://upload.dacast.com"

payload={'acl': 'private',
'bucket': 'upload.dacast.com',
'key': 'vod/b21c25ef-1d75-9789-6a92-d8ba13c53a86/none/9f5becc4-7db9-e49f-646a-14e198ddd748',
'policy': 'sfdlkfjwlkarhwoi4u57908237rujhwkeriuq23yr9q8ihe29834y42kbfew,btr12=32ewfak',
'success_action_status': '201',
'x-amz-credential': 'AKIAUERNWEFKSDFSKW/20211104/us-east-1/s3/aws4_request',
'x-amz-date': '20211104T102930Z',
'x-amz-signature': 'ad538afca4718cd7591e109613631d9678729086b47e0f5ac8ee7171168d48a3'}
files=[
  ('file',('fileName',open('pathToLocalFile','rb'),'application/octet-stream'))
]
headers = {}

response = requests.request("POST", url, headers=headers, data=payload, files=files)

print(response.text)
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://upload.dacast.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
$post = array(
    'acl' => 'private',
    'bucket' => 'upload.dacast.com',
    'key' => 'vod/b21c25ef-1d75-9789-6a92-d8ba13c53a86/none/9f5becc4-7db9-e49f-646a-14e198ddd748',
    'policy' => 'sfdlkfjwlkarhwoi4u57908237rujhwkeriuq23yr9q8ihe29834y42kbfew,btr12=32ewfak',
    'success_action_status' => '201',
    'x-amz-algorithm' => 'AWS4-HMAC-SHA256',
    'x-amz-credential' => 'AKIAUERNWEFKSDFSKW/20211104/us-east-1/s3/aws4_request',
    'x-amz-date' => '20211104T102930Z',
    'x-amz-signature' => 'ad538afca4718cd7591e109613631d9678729086b47e0f5ac8ee7171168d48a3',
    'file'=> new CURLFILE('pathToLocalFile')
);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);

$result = curl_exec($ch);
if (curl_errno($ch)) {
    echo 'Error:' . curl_error($ch);
}
curl_close($ch);
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
  .addFormDataPart("acl","private")
  .addFormDataPart("bucket","upload.dacast.com")
  .addFormDataPart("key","vod/b21c25ef-1d75-9789-6a92-d8ba13c53a86/none/9f5becc4-7db9-e49f-646a-14e198ddd748")
  .addFormDataPart("policy","sfdlkfjwlkarhwoi4u57908237rujhwkeriuq23yr9q8ihe29834y42kbfew,btr12=32ewfak")
  .addFormDataPart("success_action_status","201")
  .addFormDataPart("x-amz-credential","AKIAUERNWEFKSDFSKW/20211104/us-east-1/s3/aws4_request")
  .addFormDataPart("x-amz-date","20211104T102930Z")
  .addFormDataPart("x-amz-signature","ad538afca4718cd7591e109613631d9678729086b47e0f5ac8ee7171168d48a3")
  .addFormDataPart("file","",
    RequestBody.create(MediaType.parse("application/octet-stream"),
    new File("3BQyVDgbR/bbb_sunflower_2160p_30fps_normal.mp4")))
  .build();
Request request = new Request.Builder()
  .url("https://upload.dacast.com")
  .method("POST", body)
  .build();
Response response = client.newCall(request).execute();

This sends the file to the Dacast AWS bucket, ready for processing (encoding) and integration into your account.

As mentioned, this process is asynchronous, so once the file is uploaded, it will take some time before the file becomes available. This is where building a callback script and passing the URL to that script in the initial signature request is essential.

The callback returns a response like the below:

BODY:
--ddcd74e4f86a467b2cb963034dba510493aafca8b0275382ba0603a28d71 
Content-Disposition: form-data; name="file_id" 12cf941b-6e6e-40f4-5e2f-00c4034e8123 
--ddcd74e4f86a467b2cb963034dba510493aafca8b0275382ba0603a28d71 
Content-Disposition: form-data; name="title" Big_Buck_Bunny_360_10s_1MB.mp4 
--ddcd74e4f86a467b2cb963034dba510493aafca8b0275382ba0603a28d71--
HEADERS
Content-Type multipart/form-data; boundary=ddcd74e4f86a467b2cb963034dba510493aafca8b0275382ba0603a28d71
User-Agent Go-http-client/1.1
Accept-Encoding gzip
Content-Length 362
Host api.webhookinbox.com

As you can see, the response body contains form data that includes the file_id and title as registered in the system.

📘

You will need to parse the response to get the ID.

In Python, for instance, you can parse it using the requests-toolbelt library like so:

$ pip install requests - toolbelt

After installing it, you can import the module and directly use it to parse the request:

from requests_toolbelt.multipart
import decoder

response = requests.post(...)
multipart_data = decoder.MultipartDecoder.from_response(response)

for part in multipart_data.parts:
   print(part.content) // change this to code to extract the video ID from the response

In other languages, you will need to use a library similarly to the above Python example.

Store that ID in your database for future reference - it is the unique identifier to the content in our system!

If you are operating on a private upload system, for instance a content management or learning management system, you should additionally store your end user’s user ID against each video ID so that you can show only the videos that belong to that user to them in the future.

You can then use this ID to perform further operations, like:

  • Updating Video Metadata - if you asked for the Video Title in the upload form, you can now set that title using this method.
  • Uploading a Splashscreen and Thumbnail - we auto-generate these images, but if you want to set your own, or allow your end users to change these, use these methods.
  • List Content That Belongs to a User - so you can offer drop down selection of content to embed in a CMS, for instance.
  • Looking Up Video Metadata - so you can grab thumbnails and titles for content, and display your end users' videos on your website, in a gallery, for instance.
  • Getting Your Embed Code - this is crucial so you can embed the player on your website and show the end users' video content
  • Adding Your Content to a Playlist - so you can embed series of videos, for instance a lecture series, in one video player on your site