Look ma, no backend - Uploading and encoding using Filepicker.io and Zencoder

How to go about uploading videos is one of the most common questions we get from new customers at Zencoder. As a developer, implementing file uploads is something you've probably done a few times, but it's always a pain.

Enter Filepicker.io

Filepicker.io makes file upload easy. Like, really easy. You're not just limited to just local files either; they support a wide range of sources, from Dropbox and Google to even recording a video directly from your webcam. The best part is, you can do all of this without ever leaving the front-end. Before we do anything else, you'll need to sign up for a Filepicker.io account. Once you've done so, create a new App in your dashboard if one doesn't exist. Take note of the API key you see, we'll be using that later. Filepicker.io is nice enough to provide an S3 bucket for getting started, but take a second to set up a destination S3 bucket for your uploads. Let's start on the same page with a basic HTML5 template. We're going to use jQuery to make things simple, so we'll include that with our boilerplate along with the Filepicker.io library.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>Zencoder Dropzone</title>

    <!-- jQuery Include -->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

    <!-- Filepicker.io Include -->
    <script type="text/javascript" src="//api.filepicker.io/v1/filepicker.js"></script>
</head>

<body>
    <div id="content">
        <h1>Upload all the things!</h1>
    </div>
</body>
</html>
Now we can use the Filepicker.io JavaScript API to allow our users to select a file and save it to our S3 bucket. We'll also need to associate this with a link in the body so the user has something to click. Add this below the Filepicker.io JavaScript include. First let's add the upload link. Since we already have a big, prominent h1 tag, let's just add the link to that.
<h1><a href="#" id="upload-link">Upload all the things!</a></h1>
Now we want to use that link to trigger filepicker.pickAndStore when clicked. This is where we'll use the API key you made note of earlier. Place this snippet below the Filepicker.io JavaScript include in the head of the page.
<script type="text/javascript">
    $(function() {
      filepicker.setKey('The_Key_From_Your_Dashboard');

      $('a').click(function(e) {
        e.preventDefault(); // This keeps the normal link behavior from happening

        filepicker.pickAndStore({},{location: 's3'},function(fpfiles){
            console.log(JSON.stringify(fpfiles));
        });
      });
    });
</script>
You'll need to use some sort of web server to serve up the HTML or else you won't be able to load the external JavaScript files. You can use something like http-server, but there's a basic Node application that will serve static files in the GitHub repository. Your page should look pretty unimpressive at this point. You should just see a big link and a lot of white space. Just the link If you click the link, though… Tadaa! Choose any file (might want to pick something relatively small) and upload it. Right now, a successful upload just logs the fpfiles object to the console, so after you upload a file take a look at the console. If everything went according to plan, you should have an object with some information about your newly uploaded file. fpfiles object Congratulations! You just uploaded a file from your computer with just 27 total lines of code, including simple HTML markup. Just uploading files and leaving them there isn't useful though, so let's make it so users can upload videos and encode them.

Adding some Zencoder to the mix

First, let's alter our uploader to only accept video files. Filepicker allows us to restrict by mimetype, so if you're like me you may be tempted to try {mimetype: 'video/*'}. This will work just fine in Chrome, but your Safari users will see a much smaller subset of files that they can upload. For video, it's much more reliable to restrict by extension, so let's take that route.
$('a').click(function(e) {
  e.preventDefault(); // This keeps the normal link behavior from happening
  var acceptedExtensions = ['3g2','3gp','3gp2','3gpp','3gpp2','aac','ac3','eac3','ec3','f4a','f4b','f4v','flv','highwinds','m4a','m4b','m4r','m4v','mkv','mov','mp3','mp4','oga','ogg','ogv','ogx','ts','webm','wma','wmv'];
  filepicker.pickAndStore({extensions: acceptedExtensions},{location: 's3'},function(fpfiles){
      console.log(JSON.stringify(fpfiles));
  });
});
You can restrict this set of accepted files or add more, but I took the easy way out and just used the list of valid output formats from the Zencoder format documentation. This includes some audio files, but since Zencoder supports audio-only encoding we can leave them in there. Now if you click the link and browse your local files, you should notice that you can only select files with an extension on the list. If you try to drag and drop an unnacceptable file, you'll get an error. Unacceptable file error Great! Now that we know we'll only be uploading files Zencoder can support, let's make it so a successful upload sends that file to Zencoder for encoding. Before we can do that, we'll need to set our Zencoder API key. You can just include this right below your Filepicker key.
filepicker.setKey('The_Key_From_Your_Dashboard');
var zenKey = 'Zencoder_API_Key';
Now we'll use jQuery's $.ajax to send our API request to Zencoder upon successful upload.
filepicker.pickAndStore({extensions: acceptedExtensions},{location: 's3'},function(fpfiles){
  // This is the simplest Zencoder API call you can make. This will output an h.264 mp4 with AAC audio and
  // save it to Zencoder's temporary storage on S3.
  var request = {
    "input": fpfiles[0].url
  }
  // Let's use $.ajax instead of $.post so we can specify custom headers.
  $.ajax({
      url: 'https://app.zencoder.com/api/v2/jobs',
      type: 'POST',
      data: JSON.stringify(request),
      headers: { "Zencoder-Api-Key": zenKey },
      dataType: 'json',
      success: function(data) {
        $('body').append('Job created! <a href="https://app.zencoder.com/jobs/'+ data.id +'">View Job</a>')
      },
      error: function(data) {
        console.log(data);
      }
  });
});
Now refresh your page and upload a video. If everything has gone according to plan you should see a success message with a link to your newly created job. job created There you go! 47 lines of code later you have a web page that will allow you to upload a video and send it off for encoding.

Notes and warnings

It is a BAD IDEA to put your Zencoder API key in plain text inside of JavaScript. Just to repeat that one more time, do not use this in code that other people could possibly access.

Nothing would stop people from taking your API key and encoding all the video they wanted.

A much better idea would be to use Filepicker.io as described, but actually make the Zencoder API call in your back end where your API key is safe from prying eyes.

Just to take things a step further…

drop zone I think drag and drop is really cool, so I wanted to make a whole page that uses Filepicker.io's makeDropPane. Users have to put their API key in before doing anything and it's not stored in the code, so the demo is safe to put online.

Aaand even further…

drop zone with history Just to officially take the demo too far, this version validates the API key, includes a history of your recent Zencoder jobs and allows you to modify the request template. All of these settings are saved in your browser's localStorage so you don't lose everything on a refresh. I tried to over-comment, so feel free to take a look through the source! I would love to hear what you think! You can find me on Twitter as @matt_mcclure if you have any questions or comments.