Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setting content-type for mp4 files on s3

I am adding user uploaded videos to my RoRs site with the help of the paperclip gem and s3 storage. For some reason that I can't figure out, whenever a user uploads an mp4 file, s3 sets content-type for that file as application/mp4 instead of video/mp4.

Note that I have registered mp4 mime type in an initializer file:

Mime::Type.lookup_by_extension('mp4').to_s => "video/mp4"

Here is the relevant part of my Post model:

  has_attached_file :video, 
                :storage => :s3,
                :s3_credentials => "#{Rails.root.to_s}/config/s3.yml",
                :path => "/video/:id/:filename"

  validates_attachment_content_type :video,
     :content_type => ['video/mp4'],
     :message => "Sorry, this site currently only supports MP4 video"

What am I missing in my paperclip and/or s3 set-up.

####Update#####

For some reason that is beyond my knowledge of Rails, my default mime types for mp4 contained files is the following:

    MIME::Types.type_for("my_video.mp4").to_s
 => "[application/mp4, audio/mp4, video/mp4, video/vnd.objectvideo]" 

So, when paperclip send an mp4 file to s3, it seems to identify the file's mime type as the first default, "application/mp4". That is why s3 identifies the file as having a content-type of "application/mp4". Because I want to enable streaming of these mp4 files, I need paperclip to identify the file as having a mime type of "video/mp4".

Is there a way to modify paperclip (maybe in a before_post_process filter) to allow for this, or is there a way to modify rails through an init file to identify mp4 files as being "video/mp4". If I could do either, which way is best.

Thanks for your help

like image 397
chuck w Avatar asked Jul 23 '12 23:07

chuck w


People also ask

How do I change the format of a S3 bucket?

You cannot. The default content-type is "application/octet-stream". The only option you have is setting the content-type at the time of upload or updating it once the upload is complete.

What file formats does S3 support?

Supported file formats JSON (newline-delimited) Avro. Parquet. ORC.

Can we store videos in S3?

Step 1: Create an S3 bucket Create a bucket to store the original video that you plan to stream. Sign in to the AWS Management Console and open the Amazon S3 console at https://console.aws.amazon.com/s3/ . In the left navigation pane, choose Buckets. Choose Create bucket.

What is content type in AWS S3?

When you upload content to AWS S3, the object can be assigned a MIME type that describes the format of the contents. The transfer service automatically applies content types to objects as they are uploaded, with content types assigned from the following list: 3dm. x-world/x-3dmf.


2 Answers

Turns out that I needed to set a default s3 header content_type in the model. This isn't the best solution for me because at some point I might start allowing video containers other than mp4. But it gets me moving on to the next problem.

  has_attached_file :video, 
                :storage => :s3,
                :s3_credentials => "#{Rails.root.to_s}/config/s3.yml",
                :path => "/video/:id/:filename",
                :s3_headers =>  { "Content-Type" => "video/mp4" }
like image 130
chuck w Avatar answered Oct 05 '22 17:10

chuck w


I did the following:

...
MIN_VIDEO_SIZE = 0.megabytes
MAX_VIDEO_SIZE = 2048.megabytes
VALID_VIDEO_CONTENT_TYPES = ["video/mp4", /\Avideo/] # Note: The regular expression /\Avideo/ will match anything that starts with "video"

has_attached_file :video, {
  url: BASE_URL,
  path: "video/:id_partition/:filename"
}

validates_attachment :video,
    size: { in: MIN_VIDEO_SIZE..MAX_VIDEO_SIZE }, 
    content_type: { content_type: VALID_VIDEO_CONTENT_TYPES }

before_validation :validate_video_content_type, on: :create

before_post_process :validate_video_content_type

def validate_video_content_type
  if video_content_type == "application/octet-stream"
    # Finds the first match and returns it. 
    # Alternatively you could use the ".select" method instead which would find all mime types that match any of the VALID_VIDEO_CONTENT_TYPES
    mime_type = MIME::Types.type_for(video_file_name).find do |type| 
      type.to_s.match Regexp.union(VALID_VIDEO_CONTENT_TYPES)
    end

    self.video_content_type = mime_type.to_s unless mime_type.blank?   
  end
end
...
like image 40
Mark Murphy Avatar answered Oct 05 '22 18:10

Mark Murphy