fixes #3960
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
module DanbooruImageResizer
|
module DanbooruImageResizer
|
||||||
|
extend self
|
||||||
|
|
||||||
# Taken from ArgyllCMS 2.0.0 (see also: https://ninedegreesbelow.com/photography/srgb-profile-comparison.html)
|
# Taken from ArgyllCMS 2.0.0 (see also: https://ninedegreesbelow.com/photography/srgb-profile-comparison.html)
|
||||||
SRGB_PROFILE = "#{Rails.root}/config/sRGB.icm"
|
SRGB_PROFILE = "#{Rails.root}/config/sRGB.icm"
|
||||||
# http://jcupitt.github.io/libvips/API/current/libvips-resample.html#vips-thumbnail
|
# http://jcupitt.github.io/libvips/API/current/libvips-resample.html#vips-thumbnail
|
||||||
@@ -9,7 +11,7 @@ module DanbooruImageResizer
|
|||||||
|
|
||||||
# XXX libvips-8.4 on Debian doesn't support the `Vips::Image.thumbnail` method.
|
# XXX libvips-8.4 on Debian doesn't support the `Vips::Image.thumbnail` method.
|
||||||
# On 8.4 we have to shell out to vipsthumbnail instead. Remove when Debian supports 8.5.
|
# On 8.4 we have to shell out to vipsthumbnail instead. Remove when Debian supports 8.5.
|
||||||
def self.resize(file, width, height, quality = 90)
|
def resize(file, width, height, quality = 90)
|
||||||
if Vips.at_least_libvips?(8, 5)
|
if Vips.at_least_libvips?(8, 5)
|
||||||
resize_ruby(file, width, height, quality)
|
resize_ruby(file, width, height, quality)
|
||||||
else
|
else
|
||||||
@@ -17,13 +19,13 @@ module DanbooruImageResizer
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.crop(file, width, height, quality = 90)
|
def crop(file, width, height, quality = 90)
|
||||||
crop_shell(file, width, height, quality)
|
crop_shell(file, width, height, quality)
|
||||||
end
|
end
|
||||||
|
|
||||||
# https://github.com/jcupitt/libvips/wiki/HOWTO----Image-shrinking
|
# https://github.com/jcupitt/libvips/wiki/HOWTO----Image-shrinking
|
||||||
# http://jcupitt.github.io/libvips/API/current/Using-vipsthumbnail.md.html
|
# http://jcupitt.github.io/libvips/API/current/Using-vipsthumbnail.md.html
|
||||||
def self.resize_ruby(file, width, height, resize_quality)
|
def resize_ruby(file, width, height, resize_quality)
|
||||||
output_file = Tempfile.new
|
output_file = Tempfile.new
|
||||||
resized_image = Vips::Image.thumbnail(file.path, width, height: height, **THUMBNAIL_OPTIONS)
|
resized_image = Vips::Image.thumbnail(file.path, width, height: height, **THUMBNAIL_OPTIONS)
|
||||||
resized_image.jpegsave(output_file.path, Q: resize_quality, **JPEG_OPTIONS)
|
resized_image.jpegsave(output_file.path, Q: resize_quality, **JPEG_OPTIONS)
|
||||||
@@ -31,7 +33,7 @@ module DanbooruImageResizer
|
|||||||
output_file
|
output_file
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.crop_ruby(file, width, height, resize_quality)
|
def crop_ruby(file, width, height, resize_quality)
|
||||||
return nil unless Danbooru.config.enable_image_cropping
|
return nil unless Danbooru.config.enable_image_cropping
|
||||||
|
|
||||||
output_file = Tempfile.new
|
output_file = Tempfile.new
|
||||||
@@ -41,7 +43,7 @@ module DanbooruImageResizer
|
|||||||
output_file
|
output_file
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.resize_shell(file, width, height, quality)
|
def resize_shell(file, width, height, quality)
|
||||||
output_file = Tempfile.new(["resize", ".jpg"])
|
output_file = Tempfile.new(["resize", ".jpg"])
|
||||||
|
|
||||||
# --size=WxH will upscale if the image is smaller than the target size.
|
# --size=WxH will upscale if the image is smaller than the target size.
|
||||||
@@ -63,7 +65,7 @@ module DanbooruImageResizer
|
|||||||
output_file
|
output_file
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.crop_shell(file, width, height, quality)
|
def crop_shell(file, width, height, quality)
|
||||||
return nil unless Danbooru.config.enable_image_cropping
|
return nil unless Danbooru.config.enable_image_cropping
|
||||||
|
|
||||||
output_file = Tempfile.new(["crop", ".jpg"])
|
output_file = Tempfile.new(["crop", ".jpg"])
|
||||||
@@ -85,4 +87,20 @@ module DanbooruImageResizer
|
|||||||
|
|
||||||
output_file
|
output_file
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validate_shell(file)
|
||||||
|
temp = Tempfile.new("validate")
|
||||||
|
output, status = Open3.capture2e("vips stats #{file.path} #{temp.path}.v")
|
||||||
|
|
||||||
|
# png | jpeg | gif
|
||||||
|
if output =~ /Read Error|Premature end of JPEG file|Failed to read from given file/m
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
ensure
|
||||||
|
temp.close
|
||||||
|
temp.unlink
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
class UploadService
|
class UploadService
|
||||||
module Utils
|
module Utils
|
||||||
extend self
|
extend self
|
||||||
|
class CorruptFileError < RuntimeError; end
|
||||||
|
|
||||||
def file_header_to_file_ext(file)
|
def file_header_to_file_ext(file)
|
||||||
case File.read(file.path, 16)
|
case File.read(file.path, 16)
|
||||||
@@ -25,7 +26,7 @@ class UploadService
|
|||||||
|
|
||||||
def delete_file(md5, file_ext, upload_id = nil)
|
def delete_file(md5, file_ext, upload_id = nil)
|
||||||
if Post.where(md5: md5).exists?
|
if Post.where(md5: md5).exists?
|
||||||
if upload_id
|
if upload_id.present? && Upload.where(id: upload_id).exists?
|
||||||
CurrentUser.as_system do
|
CurrentUser.as_system do
|
||||||
Upload.find(upload_id).update(status: "completed")
|
Upload.find(upload_id).update(status: "completed")
|
||||||
end
|
end
|
||||||
@@ -34,7 +35,7 @@ class UploadService
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if upload_id && Upload.where(id: upload_id).exists?
|
if upload_id.present? && Upload.where(id: upload_id).exists?
|
||||||
CurrentUser.as_system do
|
CurrentUser.as_system do
|
||||||
Upload.find(upload_id).update(status: "preprocessed + deleted")
|
Upload.find(upload_id).update(status: "preprocessed + deleted")
|
||||||
end
|
end
|
||||||
@@ -206,8 +207,24 @@ class UploadService
|
|||||||
end
|
end
|
||||||
|
|
||||||
def download_for_upload(upload)
|
def download_for_upload(upload)
|
||||||
download = Downloads::File.new(upload.source, upload.referer_url)
|
attempts = 0
|
||||||
file, strategy = download.download!
|
|
||||||
|
begin
|
||||||
|
download = Downloads::File.new(upload.source, upload.referer_url)
|
||||||
|
file, strategy = download.download!
|
||||||
|
|
||||||
|
if !DanbooruImageResizer.validate_shell(file)
|
||||||
|
raise CorruptFileError.new("File is corrupted")
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue
|
||||||
|
if attempts == 3
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
|
||||||
|
attempts += 1
|
||||||
|
retry
|
||||||
|
end
|
||||||
|
|
||||||
if download.data[:ugoira_frame_data]
|
if download.data[:ugoira_frame_data]
|
||||||
upload.context = {
|
upload.context = {
|
||||||
|
|||||||
BIN
test/files/test-corrupt.jpg
Normal file
BIN
test/files/test-corrupt.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
@@ -42,6 +42,28 @@ class UploadServiceTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "for a corrupt jpeg" do
|
||||||
|
setup do
|
||||||
|
@source = "https://raikou1.donmai.us/93/f4/93f4dd66ef1eb11a89e56d31f9adc8d0.jpg"
|
||||||
|
@mock_upload = mock("upload")
|
||||||
|
@mock_upload.stubs(:source).returns(@source)
|
||||||
|
@mock_upload.stubs(:referer_url).returns(nil)
|
||||||
|
@bad_file = File.open("#{Rails.root}/test/files/test-corrupt.jpg", "rb")
|
||||||
|
Downloads::File.any_instance.stubs(:download!).returns([@bad_file, nil])
|
||||||
|
end
|
||||||
|
|
||||||
|
teardown do
|
||||||
|
@bad_file.close
|
||||||
|
end
|
||||||
|
|
||||||
|
should "retry three times" do
|
||||||
|
DanbooruImageResizer.expects(:validate_shell).times(4).returns(false)
|
||||||
|
assert_raise(UploadService::Utils::CorruptFileError) do
|
||||||
|
subject.download_for_upload(@mock_upload)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "for a pixiv" do
|
context "for a pixiv" do
|
||||||
setup do
|
setup do
|
||||||
@source = "http://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350"
|
@source = "http://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350"
|
||||||
@@ -849,7 +871,8 @@ class UploadServiceTest < ActiveSupport::TestCase
|
|||||||
context "a post that is replaced to another file then replaced back to the original file" do
|
context "a post that is replaced to another file then replaced back to the original file" do
|
||||||
should "not delete the original files" do
|
should "not delete the original files" do
|
||||||
begin
|
begin
|
||||||
FileUtils.expects(:rm_f).never
|
# this is called thrice to delete the file for 62247364
|
||||||
|
FileUtils.expects(:rm_f).times(3)
|
||||||
|
|
||||||
as_user do
|
as_user do
|
||||||
@post.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350")
|
@post.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350")
|
||||||
|
|||||||
Reference in New Issue
Block a user