2024-05-03 03:04:43 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
class E621ThumbnailJob < ApplicationJob
|
|
|
|
queue_as :default
|
|
|
|
|
|
|
|
def perform(entry)
|
|
|
|
infile = Tempfile.new(%W[e621-thumbnail-#{entry.stripped_md5} .webm])
|
|
|
|
outfile = Tempfile.new(%W[e621-thumbnail-#{entry.stripped_md5} .#{entry.filetype}])
|
|
|
|
cutfile = Tempfile.new(%W[e621-thumbnail-#{entry.stripped_md5} .cut.webm])
|
|
|
|
palettefile = Tempfile.new(%W[e621-thumbnail-#{entry.stripped_md5} .palette.png])
|
2024-05-06 07:47:53 +00:00
|
|
|
Timeout.timeout(120) do
|
2024-05-03 03:04:43 +00:00
|
|
|
infile.binmode
|
2024-05-06 07:47:53 +00:00
|
|
|
io = FileDownload.new("https://static1.e621.net/data/#{entry.stripped_md5[0..1]}/#{entry.stripped_md5[2..3]}/#{entry.stripped_md5}.webm").download!
|
|
|
|
IO.copy_stream(io, infile)
|
2024-05-03 03:04:43 +00:00
|
|
|
duration = `ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 #{infile.path}`.to_f
|
|
|
|
offset = duration > 10 ? rand(0..(duration - 10)) : duration / 2
|
|
|
|
if entry.filetype == "gif"
|
|
|
|
`ffmpeg -y -i #{infile.path} -ss #{offset} -t 3 -c:v copy -an #{cutfile.path} 1>&2`
|
|
|
|
`ffmpeg -y -i #{cutfile.path} -filter_complex "[0:v] palettegen" #{palettefile.path} 1>&2`
|
|
|
|
`ffmpeg -y -i #{cutfile.path} -i #{palettefile.path} -filter_complex "[0:v][1:v] paletteuse" #{outfile.path} 1>&2`
|
|
|
|
else
|
|
|
|
`ffmpeg -y -i #{infile.path} -ss #{offset} -vframes 1 #{outfile.path} 1>&2`
|
|
|
|
end
|
|
|
|
ImageOptim.new.optimize_image!(outfile.path)
|
2024-05-06 07:47:53 +00:00
|
|
|
Websites.config.e621_thumbnails_storage.upload("/#{entry.stripped_md5}.#{entry.filetype}", outfile)
|
2024-06-29 07:13:04 +00:00
|
|
|
Websites.config.e621_thumbnails_backup_storage.put("/#{entry.stripped_md5}.#{entry.filetype}", outfile)
|
2024-05-03 03:04:43 +00:00
|
|
|
entry.update!(status: "complete")
|
|
|
|
execute_webhook(entry, title: "Thumbnail Generated (#{entry.filetype})")
|
|
|
|
end
|
|
|
|
rescue Timeout::Error
|
|
|
|
entry.update!(status: "timeout")
|
|
|
|
execute_webhook(entry, title: "Thumbnail Generation Timed Out (#{entry.filetype})", error: true)
|
|
|
|
rescue StandardError => e
|
|
|
|
code = Requests::Pastebin.default.create(title: "E621 Thumbnail Generation Error (#{entry.stripped_md5})", content: "#{e}\n#{e.backtrace&.join("\n") || ''}")
|
|
|
|
entry.update!(status: "error", error_code: code)
|
2024-05-12 01:02:35 +00:00
|
|
|
execute_webhook(entry, title: "Thumbnail Generation Errored (#{entry.filetype})", body: "Backtrace: https://pastebin.com/#{code}", error: true)
|
2024-05-03 03:04:43 +00:00
|
|
|
raise(e)
|
|
|
|
ensure
|
|
|
|
[infile, outfile, palettefile, cutfile].each do |file|
|
|
|
|
file&.close
|
|
|
|
file&.unlink
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def execute_webhook(entry, title:, body: "", error: false)
|
|
|
|
if error
|
|
|
|
entry.update(expires_at: 5.minutes.from_now)
|
|
|
|
E621ThumbnailErrorCleanupJob.set(wait: 5.minutes).perform_later(entry)
|
|
|
|
end
|
|
|
|
thumb = {}
|
|
|
|
if entry.complete?
|
|
|
|
thumb = {
|
|
|
|
thumbnail: {
|
|
|
|
url: entry.url,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
end
|
|
|
|
Websites.config.e621_thumbnails_webhook.execute({
|
|
|
|
embeds: [
|
|
|
|
{
|
|
|
|
title: title,
|
|
|
|
description: <<~DESC,
|
|
|
|
Key: ##{entry.api_key_id} (`#{entry.api_key.application_name}`)
|
|
|
|
Post: [##{entry.post_id}](https://e621.net/posts/#{entry.post_id})
|
|
|
|
#{body}
|
|
|
|
DESC
|
|
|
|
color: error ? 0xDC143C : 0x008000,
|
|
|
|
timestamp: Time.now.iso8601,
|
|
|
|
**thumb,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
})
|
|
|
|
end
|
|
|
|
end
|