Add audio uploads (#11123)
* Add audio uploads Fix #4827 Accept uploads of OGG, WAV, FLAC, OPUS and MP3 files, and converts them to OGG. Media attachments get a new `audio` type. In the UI, audio uploads are displayed identically to video uploads. * Improve code style
This commit is contained in:
		@@ -24,14 +24,16 @@
 | 
			
		||||
class MediaAttachment < ApplicationRecord
 | 
			
		||||
  self.inheritance_column = nil
 | 
			
		||||
 | 
			
		||||
  enum type: [:image, :gifv, :video, :unknown]
 | 
			
		||||
  enum type: [:image, :gifv, :video, :unknown, :audio]
 | 
			
		||||
 | 
			
		||||
  IMAGE_FILE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.webp'].freeze
 | 
			
		||||
  VIDEO_FILE_EXTENSIONS = ['.webm', '.mp4', '.m4v', '.mov'].freeze
 | 
			
		||||
  AUDIO_FILE_EXTENSIONS = ['.ogg', '.oga', '.mp3', '.wav', '.flac', '.opus'].freeze
 | 
			
		||||
 | 
			
		||||
  IMAGE_MIME_TYPES             = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze
 | 
			
		||||
  VIDEO_MIME_TYPES             = ['video/webm', 'video/mp4', 'video/quicktime'].freeze
 | 
			
		||||
  VIDEO_CONVERTIBLE_MIME_TYPES = ['video/webm', 'video/quicktime'].freeze
 | 
			
		||||
  AUDIO_MIME_TYPES             = ['audio/wave', 'audio/wav', 'audio/x-wav', 'audio/x-pn-wave', 'audio/ogg', 'audio/mpeg', 'audio/webm', 'audio/flac'].freeze
 | 
			
		||||
 | 
			
		||||
  BLURHASH_OPTIONS = {
 | 
			
		||||
    x_comp: 4,
 | 
			
		||||
@@ -65,6 +67,13 @@ class MediaAttachment < ApplicationRecord
 | 
			
		||||
    },
 | 
			
		||||
  }.freeze
 | 
			
		||||
 | 
			
		||||
  AUDIO_STYLES = {
 | 
			
		||||
    original: {
 | 
			
		||||
      format: 'ogg',
 | 
			
		||||
      convert_options: {},
 | 
			
		||||
    },
 | 
			
		||||
  }.freeze
 | 
			
		||||
 | 
			
		||||
  VIDEO_FORMAT = {
 | 
			
		||||
    format: 'mp4',
 | 
			
		||||
    convert_options: {
 | 
			
		||||
@@ -83,6 +92,11 @@ class MediaAttachment < ApplicationRecord
 | 
			
		||||
    },
 | 
			
		||||
  }.freeze
 | 
			
		||||
 | 
			
		||||
  VIDEO_CONVERTED_STYLES = {
 | 
			
		||||
    small: VIDEO_STYLES[:small],
 | 
			
		||||
    original: VIDEO_FORMAT,
 | 
			
		||||
  }.freeze
 | 
			
		||||
 | 
			
		||||
  IMAGE_LIMIT = 8.megabytes
 | 
			
		||||
  VIDEO_LIMIT = 40.megabytes
 | 
			
		||||
 | 
			
		||||
@@ -95,9 +109,9 @@ class MediaAttachment < ApplicationRecord
 | 
			
		||||
                    processors: ->(f) { file_processors f },
 | 
			
		||||
                    convert_options: { all: '-quality 90 -strip' }
 | 
			
		||||
 | 
			
		||||
  validates_attachment_content_type :file, content_type: IMAGE_MIME_TYPES + VIDEO_MIME_TYPES
 | 
			
		||||
  validates_attachment_size :file, less_than: IMAGE_LIMIT, unless: :video_or_gifv?
 | 
			
		||||
  validates_attachment_size :file, less_than: VIDEO_LIMIT, if: :video_or_gifv?
 | 
			
		||||
  validates_attachment_content_type :file, content_type: IMAGE_MIME_TYPES + VIDEO_MIME_TYPES + AUDIO_MIME_TYPES
 | 
			
		||||
  validates_attachment_size :file, less_than: IMAGE_LIMIT, unless: :larger_media_format?
 | 
			
		||||
  validates_attachment_size :file, less_than: VIDEO_LIMIT, if: :larger_media_format?
 | 
			
		||||
  remotable_attachment :file, VIDEO_LIMIT
 | 
			
		||||
 | 
			
		||||
  include Attachmentable
 | 
			
		||||
@@ -120,8 +134,12 @@ class MediaAttachment < ApplicationRecord
 | 
			
		||||
    file.blank? && remote_url.present?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def video_or_gifv?
 | 
			
		||||
    video? || gifv?
 | 
			
		||||
  def larger_media_format?
 | 
			
		||||
    video? || gifv? || audio?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def audio_or_video?
 | 
			
		||||
    audio? || video?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def to_param
 | 
			
		||||
@@ -156,28 +174,24 @@ class MediaAttachment < ApplicationRecord
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    def file_styles(f)
 | 
			
		||||
      if f.instance.file_content_type == 'image/gif'
 | 
			
		||||
        {
 | 
			
		||||
          small: IMAGE_STYLES[:small],
 | 
			
		||||
          original: VIDEO_FORMAT,
 | 
			
		||||
        }
 | 
			
		||||
      elsif IMAGE_MIME_TYPES.include? f.instance.file_content_type
 | 
			
		||||
      if f.instance.file_content_type == 'image/gif' || VIDEO_CONVERTIBLE_MIME_TYPES.include?(f.instance.file_content_type)
 | 
			
		||||
        VIDEO_CONVERTED_STYLES
 | 
			
		||||
      elsif IMAGE_MIME_TYPES.include?(f.instance.file_content_type)
 | 
			
		||||
        IMAGE_STYLES
 | 
			
		||||
      elsif VIDEO_CONVERTIBLE_MIME_TYPES.include?(f.instance.file_content_type)
 | 
			
		||||
        {
 | 
			
		||||
          small: VIDEO_STYLES[:small],
 | 
			
		||||
          original: VIDEO_FORMAT,
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
      elsif VIDEO_MIME_TYPES.include?(f.instance.file_content_type)
 | 
			
		||||
        VIDEO_STYLES
 | 
			
		||||
      else
 | 
			
		||||
        AUDIO_STYLES
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def file_processors(f)
 | 
			
		||||
      if f.file_content_type == 'image/gif'
 | 
			
		||||
        [:gif_transcoder, :blurhash_transcoder]
 | 
			
		||||
      elsif VIDEO_MIME_TYPES.include? f.file_content_type
 | 
			
		||||
      elsif VIDEO_MIME_TYPES.include?(f.file_content_type)
 | 
			
		||||
        [:video_transcoder, :blurhash_transcoder]
 | 
			
		||||
      elsif AUDIO_MIME_TYPES.include?(f.file_content_type)
 | 
			
		||||
        [:transcoder]
 | 
			
		||||
      else
 | 
			
		||||
        [:lazy_thumbnail, :blurhash_transcoder]
 | 
			
		||||
      end
 | 
			
		||||
@@ -202,7 +216,15 @@ class MediaAttachment < ApplicationRecord
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def set_type_and_extension
 | 
			
		||||
    self.type = VIDEO_MIME_TYPES.include?(file_content_type) ? :video : :image
 | 
			
		||||
    self.type = begin
 | 
			
		||||
      if VIDEO_MIME_TYPES.include?(file_content_type)
 | 
			
		||||
        :video
 | 
			
		||||
      elsif AUDIO_MIME_TYPES.include?(file_content_type)
 | 
			
		||||
        :audio
 | 
			
		||||
      else
 | 
			
		||||
        :image
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def set_meta
 | 
			
		||||
@@ -245,7 +267,7 @@ class MediaAttachment < ApplicationRecord
 | 
			
		||||
      frame_rate: movie.frame_rate,
 | 
			
		||||
      duration: movie.duration,
 | 
			
		||||
      bitrate: movie.bitrate,
 | 
			
		||||
    }
 | 
			
		||||
    }.compact
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def reset_parent_cache
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user