Websites/app/jobs/e621_thumbnail_job.rb
2024-05-02 22:04:43 -05:00

75 lines
3.1 KiB
Ruby

# 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])
Timeout.timeout(1000) do
infile.binmode
HTTParty.get("https://static1.e621.net/data/#{entry.stripped_md5[0..1]}/#{entry.stripped_md5[2..3]}/#{entry.stripped_md5}.webm", stream_body: true) do |fragment|
infile.write(fragment)
end
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)
StorageManager::E621Thumbnails.upload("#{entry.stripped_md5}.#{entry.filetype}", outfile.read)
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)
execute_webhook(entry, title: "Thumbnail Generation Errored (#{entry.filetype})", body: "Backtrace: https://passtebin.com/#{code}", error: true)
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