The video upload marks the spot.

It’s about time I write on this thing since it has been months since my last post. I was sifting through some old code I’d written last year and I tell you what, sometimes I’m actually shocked at the things I’ve written that I have forgotten about. For instance, I had a client who wanted not only the ability to upload videos, but also link to videos through YouTube. Sounds easy right? Okay but make the videos play in the same player, and make them look like there is no difference. Not so easy. It took a lot of scrounging since this was last year, prior to the YouTube API, however it became a very fun little project involving ffmpeg and rvideo.

Basically what happens is if a video has a YouTube ID, then go get the thumbnail image and the original MPEG file from YouTube and convert it to flv before saving. If the user uploads a video, use ffmpeg to grab a still of the first frame to use as the thumbnail, then convert it to flv and save it.

I present thee Video model. (Unfortunately this was so long ago, I was using attachment_fu… maybe Paperclip would have helped a bit.)

class Video < ActiveRecord::Base
  include AASM

  aasm_column :state
  aasm_initial_state :pending
  aasm_state :pending
  aasm_state :converting
  aasm_state :converted, :enter => :set_new_filename
  aasm_state :error

  aasm_event :convert do
    transitions :from => :pending, :to => :converting
  end

  aasm_event :converted do
    transitions :from => :converting, :to => :converted
  end

  aasm_event :failure do
    transitions :from => :converting, :to => :error
  end

  def get_yt_video_data
    uri = URI.parse("http://www.youtube.com/get_video_info")
    post_args = { 'video_id' => self.url }
    res, data = Net::HTTP.post_form uri, post_args
    b = res.body
    CGI::parse(b) ## return a hash of k=>v pairs
  end

  def get_yt_video_thumb
    get_yt_video_data["thumbnail_url"].first
  end

  def get_yt_video_duration
    seconds = get_yt_video_data["length_seconds"].first.to_i ## format this better... seconds/60 = mins/60 = hours ... hh:mm:ss
    total_minutes = seconds / 1.minutes
    seconds_in_last_minute = seconds - total_minutes.minutes.seconds
    "#{total_minutes}:#{seconds_in_last_minute}"
  end

  def get_yt_embed_url
    return CGI::escape("#{public_filename}") unless self.url.present?
    data = get_yt_video_data
    fmt = '';
    fmt_map = data["fmt_map"]
    a = fmt_map[0..2]
    if a == '18/'
      fmt = '18'
    elsif a == '22/'
      fmt = '22'
      break
    end
    token = data["token"]
    uri2 = URI.parse("http://www.youtube.com")
    args2 = {:video_id => url, :t => token, :fmt => fmt }
    qstr = "video_id=#{url}&t=#{token}&fmt=18"
    res = ""
    Net::HTTP.start(uri2.host, uri2.port) {|http|
      res = http.head("/get_video?#{qstr}")
    }
    CGI::escape("#{res.header['Location']}")
  end

  protected

  def after_create
    return true if url.present?
    convert
  end

  def convert
    self.convert!
      spawn do
        success = system("ffmpeg -i #{full_filename} -ar 22050 -s 480x320 -f flv -y #{full_filename}.flv")
        if success && $?.exitstatus == 0
          self.converted!
        else
          self.failure!
        end
     end
  end

  def create_thumbnail
    system "ffmpeg -i #{full_filename}.flv -s 120x90 -vframes 1 -f image2 -an #{full_filename}.jpg"
  end

  def set_new_filename
    create_thumbnail
    update_attribute(:filename, "#{filename}.flv")
    update_attribute(:content_type, "application/x-flash-video")
    update_attribute(:width, "480")
    update_attribute(:height, "320")
  end

end

No related posts.

Related posts brought to you by Yet Another Related Posts Plugin.

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>