Add a model for storing image and video metadata for uploaded files. Metadata is extracted using ExifTool. You will need to install ExifTool after this commit. ExifTool 12.22 is the minimum required version because we use the `--binary` option, which was added in this release. The MediaMetadata model is separate from the MediaAsset model because some files contain tons of metadata, and most of it is non-essential. The MediaAsset model represents an uploaded file and contains essential metadata, like the file's size and type, while the MediaMetadata model represents all the other non-essential metadata associated with a file. Metadata is stored as a JSON column in the database. ExifTool returns all the file's metadata, not just the EXIF metadata. EXIF is one of several types of image metadata, hence why we call it MediaMetadata instead of EXIFMetadata.
99 lines
3.4 KiB
Ruby
99 lines
3.4 KiB
Ruby
class UploadService
|
|
module Utils
|
|
module_function
|
|
|
|
def distribute_files(file, record, type, original_post_id: nil)
|
|
# need to do this for hybrid storage manager
|
|
post = Post.new
|
|
post.id = original_post_id if original_post_id.present?
|
|
post.md5 = record.md5
|
|
post.file_ext = record.file_ext
|
|
[Danbooru.config.storage_manager, Danbooru.config.backup_storage_manager].each do |sm|
|
|
sm.store_file(file, post, type)
|
|
end
|
|
end
|
|
|
|
def is_downloadable?(source)
|
|
source =~ %r{\Ahttps?://}
|
|
end
|
|
|
|
def generate_resizes(media_file)
|
|
preview_file = media_file.preview(Danbooru.config.small_image_width, Danbooru.config.small_image_width)
|
|
crop_file = media_file.crop(Danbooru.config.small_image_width, Danbooru.config.small_image_width)
|
|
|
|
if media_file.is_ugoira?
|
|
sample_file = media_file.convert
|
|
elsif media_file.is_image? && media_file.width > Danbooru.config.large_image_width
|
|
sample_file = media_file.preview(Danbooru.config.large_image_width, media_file.height)
|
|
else
|
|
sample_file = nil
|
|
end
|
|
|
|
[preview_file, crop_file, sample_file]
|
|
end
|
|
|
|
def process_resizes(upload, file, original_post_id, media_file: nil)
|
|
media_file ||= upload.media_file
|
|
preview_file, crop_file, sample_file = Utils.generate_resizes(media_file)
|
|
|
|
begin
|
|
Utils.distribute_files(file, upload, :original, original_post_id: original_post_id) if file.present?
|
|
Utils.distribute_files(sample_file, upload, :large, original_post_id: original_post_id) if sample_file.present?
|
|
Utils.distribute_files(preview_file, upload, :preview, original_post_id: original_post_id) if preview_file.present?
|
|
Utils.distribute_files(crop_file, upload, :crop, original_post_id: original_post_id) if crop_file.present?
|
|
ensure
|
|
preview_file.try(:close!)
|
|
crop_file.try(:close!)
|
|
sample_file.try(:close!)
|
|
end
|
|
end
|
|
|
|
def process_file(upload, file, original_post_id: nil)
|
|
upload.file = file
|
|
media_file = upload.media_file
|
|
|
|
upload.file_ext = media_file.file_ext.to_s
|
|
upload.file_size = media_file.file_size
|
|
upload.md5 = media_file.md5
|
|
upload.image_width = media_file.width
|
|
upload.image_height = media_file.height
|
|
|
|
upload.validate!(:file)
|
|
upload.tag_string = "#{upload.tag_string} #{Utils.automatic_tags(media_file)}"
|
|
|
|
process_resizes(upload, file, original_post_id)
|
|
|
|
MediaAsset.create_from_media_file!(media_file)
|
|
end
|
|
|
|
def automatic_tags(media_file)
|
|
tags = []
|
|
tags << "sound" if media_file.has_audio?
|
|
tags << "animated_gif" if media_file.file_ext == :gif && media_file.is_animated?
|
|
tags << "animated_png" if media_file.file_ext == :png && media_file.is_animated?
|
|
tags.join(" ")
|
|
end
|
|
|
|
def get_file_for_upload(upload, file: nil)
|
|
return file if file.present?
|
|
raise "No file or source URL provided" if upload.source_url.blank?
|
|
|
|
strategy = Sources::Strategies.find(upload.source_url, upload.referer_url)
|
|
raise NotImplementedError, "No login credentials configured for #{strategy.site_name}." unless strategy.class.enabled?
|
|
|
|
file = strategy.download_file!
|
|
|
|
if strategy.data[:ugoira_frame_data].present?
|
|
upload.context = {
|
|
"ugoira" => {
|
|
"frame_data" => strategy.data[:ugoira_frame_data],
|
|
"content_type" => "image/jpeg"
|
|
}
|
|
}
|
|
end
|
|
|
|
file
|
|
end
|
|
end
|
|
end
|