# frozen_string_literal: true # == Schema Information # # Table name: post_images # # id :integer not null, primary key # aspect_ratio :float # compressed :boolean default(FALSE), not null # duration :float default(0.0) # file :string # file_name_cache :string # format :string # height :integer # is_animated :boolean not null # mime_type :string # name :string # orig_sha512_hash :text # sha512_hash :text # size :integer # sw_intensity :float # thumbnails_generated :boolean default(FALSE), not null # width :integer # created_at :datetime not null # updated_at :datetime not null # post_id :integer not null # # Indexes # # index_post_images_on_created_at (created_at) # index_post_images_on_orig_sha512_hash (orig_sha512_hash) UNIQUE # index_post_images_on_post_id (post_id) # index_post_images_on_sha512_hash (sha512_hash) UNIQUE # index_post_images_on_updated_at (updated_at) # # Foreign Keys # # fk_rails_... (post_id => posts.id) # class Post::Image < ApplicationRecord include ActiveModel::Dirty define_attribute_method :mime_type MIME_TYPE_TAGS = { 'image/png' => 'png', 'image/jpeg' => 'jpeg', 'image/gif' => 'gif', 'video/mp4' => 'mp4', 'video/webm' => 'webm', 'image/svg' => 'svg', 'image/svg+xml' => 'svg' }.freeze AUTOMATICALLY_CURATED_TAGS = MIME_TYPE_TAGS.values.uniq.freeze belongs_to :post, inverse_of: :image has_one :intensity, class_name: 'Post::Image::Intensity' has_many :processing_logs mount_uploader :file, ImageUploader delegate :pretty_url, :url, to: :file validates :file, presence: { unless: ->(image) { image.post&.destroyed_content? } } validates_with ImageHashDuplicationValidator, on: :create after_commit do |image| next if image.post.disable_processing if image.file.previously_changed? if image.file.video? # process videos in a separate queue ProcessVideoJob.set(wait: 10.seconds).perform_later(post.id) else ProcessImageJob.set(wait: 10.seconds).perform_later(post.id) end end end def auto_curated_tags [MIME_TYPE_TAGS[self.mime_type]] end def file_type format&.upcase end def file_name(truncated = false) return post.id.to_s if truncated return file_name_cache if file_name_cache # Not set? Let's build. # Trunate filename to 150 characters, making room for the path + filename on Windows - https://stackoverflow.com/questions/265769/maximum-filename-length-in-ntfs-windows-xp-and-windows-vista fn = "#{post.id}__#{Tag.where(id: post.tag_ids).display_order.pluck(:slug).join('_')}".gsub('%2F', '').delete('/')[0..150].sub(/%\h?\z/, '') rescue id.to_s update_columns(file_name_cache: fn) fn end def detect_duplicates(dist = 0.20, aspect_dist = 0.05) PostQuery.duplicates(intensity, dist) .where('aspect_ratio BETWEEN ? AND ?', aspect_ratio - aspect_dist, aspect_ratio + aspect_dist) .where.not(id: id) .where("posts.duplication_checked = 'f'") end def as_indexed_json(*) { width: width, height: height, aspect_ratio: aspect_ratio, duration: duration, mime_type: mime_type, file_name: file_name, sha512_hash: sha512_hash, orig_sha512_hash: orig_sha512_hash, # original_format: original_format, file: self[:file] } end end