Private Video – Not As Simple As You Think!



Private Video – Not As Simple As You Think!

0 1


s3-to-sproutvideo-presentation


On Github osahyoun / s3-to-sproutvideo-presentation

Private Video

Not As Simple As You Think!

Spec

Getting Video on to Spoutvideo

Amazon S3 - CORS

Prepare Your Bucket

<corsconfiguration>
 <corsrule>
   <allowedorigin>http://entry.quipper.com</allowedorigin>
   <allowedmethod>POST</allowedmethod>
 </corsrule>
</corsconfiguration>

Secure Uploading

  = hidden_field_tag 'key', ""
  = hidden_field_tag 'AWSAccessKeyId', VideoManager.s3_key
  = hidden_field_tag 'acl', 'private'
  = hidden_field_tag 'success_action_redirect', ""
  = hidden_field_tag 'policy', @form.policy
  = hidden_field_tag 'signature', @form.signature
  = hidden_field_tag 'Content-Type', ''

  # VideoManager::FormData
  def document
    { expiration: expiration_date,
      conditions: [
        { bucket: VideoManager.bucket},
        ["starts-with", "$key", ""],
        { acl: :private },
        { success_action_redirect: "" },
        ["starts-with", "$Content-Type", ""],
        ["content-length-range", 0, CONTENT_LENGTH]
      ]
    }
  end

Update Key before Posting

  key = () ->
    stamp = +new Date()
    return "#{$form.data('organization-id')}-#{stamp}-#{filename()}"

Keep Backend in the Know

  xhr.onload = createVideoObject

  //

  createVideoObject = () ->
    jQuery.post "/beta/organizations/#{$form.data('organization-id')}/media/videos",
      'key': $form.find("#key").val(),
      'state': 'pending',
      'title': unescape(FILENAME.replace(/.\w+$/, ''))
      (data) ->
        addRecordToTable(data)

Phew!

Video is now on Amazon S3

The upload was non-blocking

The user has a 'pending' video record

So, now what?

S3 to Sproutvideo

POST https://api.sproutvideo.com/v1/videos

Body must be multipart/form-data

s3fs

FUSE-based file system backed by Amazon S3

https://code.google.com/p/s3fs

s3fs

mkdir /quipper-videos

s3fs bucketname /quipper-videos

s3fs

mkdir /quipper-videos

s3fs bucketname /quipper-videos

  # RUNNER
  def VideoProcessor.main
    while true
      Dir[DRIVE].each do |path|
        process(path)
      end
      sleep SLEEP_TIME
    end
  end

  # PROCESSOR
  def VideoProcessor.process(path)
    unless exists?(path)
      redis.sadd(LOG_KEY, path)
      Video.new(path).send_to_sproutvideo
    end
  end

Sending to Sproutvideo

POST video file to Sproutvideo, passing notification URL and the title.

  def send_to_sproutvideo
    begin
      resp = Sproutvideo::Video.create(path, notification_url: notification_url, title: parser.title, requires_signed_embeds: true)
      if resp.success?
        update_video(resp.body)
      else
        update_video({error: resp.body[:error], state: 'error'})
      end
    rescue => e
      VideoProcessor.redis.hset(VideoProcessor::ERRORS_KEY, path, e.to_s)
      update_video({error: e.to_s})
    ensure
      # Delete file, even if Sproutvideo is unable to process file.
      File.delete(path)
    end
  end
end

Notification

Sproutvideo POSTs to passed notification URL when video has been processed.

  def notification_url
    "#{ENV['SPROUTVIDEO_NOTIFICATION_DOMAIN']}/beta/organizations/#{parser.organization_id}/media/video_processed?key=#{filename}"
  end

  {
    "created_at": "2012-12-20T00:07:54-05:00",
    "updated_at": "2012-12-20T00:07:54-05:00",
    "height": null,
    "width": null,
    "description": "An new video",
    "id": "a098d2bbd33e1c328",
    "sd_video_file_size": 0,
    "plays": 0,
    "title": "new upload.mov",
    "source_video_file_size": 0,
    "hd_video_file_size": 0,
    "embed_code": "<iframe class="sproutvideo-player" type="text/html" src="http://videos.sproutvideo.com/embed/a098d2bbd33e1c328/7ca00d6d622a8e8d?type=sd" width="630" height="354" frameborder="0"></iframe>",
    "state": "inspecting",
    "security_token": "7ca00d6d622a8e8d",
    "progress": 0,
    "tags": [],
    "duration": null,
    "password": null,
    "privacy": 2,
    "requires_signed_embeds": false,
    "assets": {
      "videos": {
        "hd_video_url": null,
        "sd_video_url": null,
        "source_video_url": null
      },
      "thumbnails": [],
      "poster_frames": []

Overview

THE END