1
0
Fork 1
forked from fedi/mastodon
mastodon/app/models/media_attachment.rb
Daniel Hunsaker cf7e840990 Update model annotations to use BIGINT for IDs (#5461)
All the migrations have been updated to use BIGINTs for ID fields in the DB, but ActiveRecord needs to be told to treat those values as BIGINT as well. This PR does that.
2017-11-12 16:18:50 +01:00

189 lines
5 KiB
Ruby

# frozen_string_literal: true
# == Schema Information
#
# Table name: media_attachments
#
# id :bigint not null, primary key
# status_id :bigint
# file_file_name :string
# file_content_type :string
# file_file_size :integer
# file_updated_at :datetime
# remote_url :string default(""), not null
# account_id :bigint
# created_at :datetime not null
# updated_at :datetime not null
# shortcode :string
# type :integer default("image"), not null
# file_meta :json
# description :text
#
require 'mime/types'
class MediaAttachment < ApplicationRecord
self.inheritance_column = nil
enum type: [:image, :gifv, :video, :unknown]
IMAGE_FILE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif'].freeze
VIDEO_FILE_EXTENSIONS = ['.webm', '.mp4', '.m4v'].freeze
IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif'].freeze
VIDEO_MIME_TYPES = ['video/webm', 'video/mp4'].freeze
IMAGE_STYLES = { original: '1280x1280>', small: '400x400>' }.freeze
VIDEO_STYLES = {
small: {
convert_options: {
output: {
vf: 'scale=\'min(400\, iw):min(400\, ih)\':force_original_aspect_ratio=decrease',
},
},
format: 'png',
time: 0,
},
}.freeze
belongs_to :account, inverse_of: :media_attachments
belongs_to :status, inverse_of: :media_attachments
has_attached_file :file,
styles: ->(f) { file_styles f },
processors: ->(f) { file_processors f },
convert_options: { all: '-quality 90 -strip' }
include Remotable
validates_attachment_content_type :file, content_type: IMAGE_MIME_TYPES + VIDEO_MIME_TYPES
validates_attachment_size :file, less_than: 8.megabytes
validates :account, presence: true
validates :description, length: { maximum: 420 }, if: :local?
scope :attached, -> { where.not(status_id: nil) }
scope :unattached, -> { where(status_id: nil) }
scope :local, -> { where(remote_url: '') }
scope :remote, -> { where.not(remote_url: '') }
default_scope { order(id: :asc) }
def local?
remote_url.blank?
end
def needs_redownload?
file.blank? && remote_url.present?
end
def to_param
shortcode
end
before_create :prepare_description, unless: :local?
before_create :set_shortcode
before_post_process :set_type_and_extension
before_save :set_meta
class << self
private
def file_styles(f)
if f.instance.file_content_type == 'image/gif'
{
small: IMAGE_STYLES[:small],
original: {
format: 'mp4',
convert_options: {
output: {
'movflags' => 'faststart',
'pix_fmt' => 'yuv420p',
'vf' => 'scale=\'trunc(iw/2)*2:trunc(ih/2)*2\'',
'vsync' => 'cfr',
'b:v' => '1300K',
'maxrate' => '500K',
'bufsize' => '1300K',
'crf' => 18,
},
},
},
}
elsif IMAGE_MIME_TYPES.include? f.instance.file_content_type
IMAGE_STYLES
else
VIDEO_STYLES
end
end
def file_processors(f)
if f.file_content_type == 'image/gif'
[:gif_transcoder]
elsif VIDEO_MIME_TYPES.include? f.file_content_type
[:video_transcoder]
else
[:thumbnail]
end
end
end
private
def set_shortcode
self.type = :unknown if file.blank? && !type_changed?
return unless local?
loop do
self.shortcode = SecureRandom.urlsafe_base64(14)
break if MediaAttachment.find_by(shortcode: shortcode).nil?
end
end
def prepare_description
self.description = description.strip[0...420] unless description.nil?
end
def set_type_and_extension
self.type = VIDEO_MIME_TYPES.include?(file_content_type) ? :video : :image
extension = appropriate_extension
basename = Paperclip::Interpolations.basename(file, :original)
file.instance_write :file_name, [basename, extension].delete_if(&:blank?).join('.')
end
def set_meta
meta = populate_meta
return if meta == {}
file.instance_write :meta, meta
end
def populate_meta
meta = {}
file.queued_for_write.each do |style, file|
begin
geo = Paperclip::Geometry.from_file file
meta[style] = {
width: geo.width.to_i,
height: geo.height.to_i,
size: "#{geo.width.to_i}x#{geo.height.to_i}",
aspect: geo.width.to_f / geo.height.to_f,
}
rescue Paperclip::Errors::NotIdentifiedByImageMagickError
meta[style] = {}
end
end
meta
end
def appropriate_extension
mime_type = MIME::Types[file.content_type]
extensions_for_mime_type = mime_type.empty? ? [] : mime_type.first.extensions
original_extension = Paperclip::Interpolations.extension(file, :original)
extensions_for_mime_type.include?(original_extension) ? original_extension : extensions_for_mime_type.first
end
end