このコミットが含まれているのは:
@@ -11,25 +11,30 @@ class MaterialThumbnailGenerator
|
||||
class << self
|
||||
def generate! material
|
||||
new(material).generate!
|
||||
rescue ActiveStorage::FileNotFoundError, ArgumentError, MiniMagick::Error => e
|
||||
Rails.logger.warn("Material thumbnail generation skipped: #{ e.class }: #{ e.message }")
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def initialize material
|
||||
@material = material
|
||||
@ffmpeg_stderr = []
|
||||
end
|
||||
|
||||
def generate!
|
||||
@material.thumbnail.purge if @material.thumbnail.attached?
|
||||
return unless @material.file.attached?
|
||||
return unless image? || video?
|
||||
return log_result(:no_file) unless @material.file.attached?
|
||||
return log_result(:unsupported_content_type) unless image? || video?
|
||||
|
||||
@material.file.blob.open do |file|
|
||||
thumbnail = image? ? image_thumbnail(file.path) : video_thumbnail(file.path)
|
||||
attach_thumbnail(thumbnail) if thumbnail
|
||||
return log_result(:generation_failed) unless thumbnail
|
||||
|
||||
return attach_thumbnail(thumbnail)
|
||||
end
|
||||
rescue ActiveStorage::FileNotFoundError => e
|
||||
log_result(:file_not_found, error: e)
|
||||
rescue MiniMagick::Error => e
|
||||
log_result(:mini_magick_error, error: e)
|
||||
rescue ArgumentError, StandardError => e
|
||||
log_result(:generation_failed, error: e)
|
||||
end
|
||||
|
||||
private
|
||||
@@ -38,7 +43,11 @@ class MaterialThumbnailGenerator
|
||||
|
||||
def video? = content_type.start_with?('video/')
|
||||
|
||||
def content_type = @material.file.blob.content_type.to_s
|
||||
def content_type
|
||||
return nil unless @material.file.attached?
|
||||
|
||||
@material.file.blob.content_type.to_s
|
||||
end
|
||||
|
||||
def image_thumbnail path
|
||||
image = MiniMagick::Image.open(path)
|
||||
@@ -71,16 +80,47 @@ class MaterialThumbnailGenerator
|
||||
'-frames:v', '1',
|
||||
'-f', 'image2',
|
||||
output_path)
|
||||
Rails.logger.warn("ffmpeg thumbnail failed: #{ stderr }") unless status.success?
|
||||
@ffmpeg_stderr << stderr if stderr.present?
|
||||
status.success?
|
||||
rescue Errno::ENOENT => e
|
||||
Rails.logger.warn("ffmpeg unavailable for material thumbnail: #{ e.message }")
|
||||
@ffmpeg_stderr << "ffmpeg unavailable: #{ e.message }"
|
||||
false
|
||||
end
|
||||
|
||||
def attach_thumbnail image
|
||||
@material.thumbnail.attach(io: File.open(image.path),
|
||||
filename: 'material-thumbnail.jpg',
|
||||
content_type: 'image/jpeg')
|
||||
blob = nil
|
||||
File.open(image.path) do |io|
|
||||
blob = ActiveStorage::Blob.create_and_upload!(
|
||||
io:,
|
||||
filename: 'material-thumbnail.jpg',
|
||||
content_type: 'image/jpeg')
|
||||
end
|
||||
@material.thumbnail.attach(blob)
|
||||
log_result(:attached)
|
||||
rescue StandardError => e
|
||||
blob&.purge_later
|
||||
log_result(:attach_failed, error: e)
|
||||
end
|
||||
|
||||
def log_result result, error: nil
|
||||
log_payload = { material_id: @material.id,
|
||||
file_blob_id: file_blob_id,
|
||||
content_type:,
|
||||
result:,
|
||||
error_class: error&.class&.name,
|
||||
error_message: error&.message,
|
||||
ffmpeg_stderr: @ffmpeg_stderr.join("\n").presence }
|
||||
if [:attached, :no_file, :unsupported_content_type].include?(result)
|
||||
Rails.logger.info("Material thumbnail generation: #{ log_payload.to_json }")
|
||||
else
|
||||
Rails.logger.warn("Material thumbnail generation: #{ log_payload.to_json }")
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def file_blob_id
|
||||
return nil unless @material.file.attached?
|
||||
|
||||
@material.file.blob.id
|
||||
end
|
||||
end
|
||||
|
||||
新しい課題から参照
ユーザをブロックする