uploads: move thumbnail generation code to MediaFile.

* Move image thumbnail generation code to MediaFile::Image.
* Move video thumbnail generation code to MediaFile::Video.
* Move ugoira->webm conversion code to MediaFile::Ugoira.

This separates thumbnail generation from the upload process so that it's
possible to generate thumbnails outside of uploads.
This commit is contained in:
evazion
2020-05-18 00:31:12 -05:00
parent 24c53172db
commit 45064853de
15 changed files with 269 additions and 423 deletions

View File

@@ -1,36 +0,0 @@
module DanbooruImageResizer
module_function
# Taken from ArgyllCMS 2.0.0 (see also: https://ninedegreesbelow.com/photography/srgb-profile-comparison.html)
SRGB_PROFILE = "#{Rails.root}/config/sRGB.icm"
# http://jcupitt.github.io/libvips/API/current/libvips-resample.html#vips-thumbnail
if Vips.at_least_libvips?(8, 8)
THUMBNAIL_OPTIONS = { size: :down, linear: false, no_rotate: true, export_profile: SRGB_PROFILE, import_profile: SRGB_PROFILE }
CROP_OPTIONS = { linear: false, no_rotate: true, export_profile: SRGB_PROFILE, import_profile: SRGB_PROFILE, crop: :attention }
else
THUMBNAIL_OPTIONS = { size: :down, linear: false, auto_rotate: false, export_profile: SRGB_PROFILE, import_profile: SRGB_PROFILE }
CROP_OPTIONS = { linear: false, auto_rotate: false, export_profile: SRGB_PROFILE, import_profile: SRGB_PROFILE, crop: :attention }
end
# http://jcupitt.github.io/libvips/API/current/VipsForeignSave.html#vips-jpegsave
JPEG_OPTIONS = { background: 255, strip: true, interlace: true, optimize_coding: true }
# https://github.com/jcupitt/libvips/wiki/HOWTO----Image-shrinking
# http://jcupitt.github.io/libvips/API/current/Using-vipsthumbnail.md.html
def resize(file, width, height, resize_quality = 90)
output_file = Tempfile.new
resized_image = Vips::Image.thumbnail(file.path, width, height: height, **THUMBNAIL_OPTIONS)
resized_image.jpegsave(output_file.path, Q: resize_quality, **JPEG_OPTIONS)
output_file
end
def crop(file, width, height, resize_quality = 90)
output_file = Tempfile.new
resized_image = Vips::Image.thumbnail(file.path, width, height: height, **CROP_OPTIONS)
resized_image.jpegsave(output_file.path, Q: resize_quality, **JPEG_OPTIONS)
output_file
end
end

View File

@@ -5,20 +5,20 @@ class MediaFile
# delegate all File methods to `file`.
delegate *(File.instance_methods - MediaFile.instance_methods), to: :file
def self.open(file)
def self.open(file, **options)
file = Kernel.open(file, "r", binmode: true) unless file.respond_to?(:read)
case file_ext(file)
when :jpg, :gif, :png
MediaFile::Image.new(file)
MediaFile::Image.new(file, **options)
when :swf
MediaFile::Flash.new(file)
MediaFile::Flash.new(file, **options)
when :webm, :mp4
MediaFile::Video.new(file)
MediaFile::Video.new(file, **options)
when :zip
MediaFile::Ugoira.new(file)
MediaFile::Ugoira.new(file, **options)
else
MediaFile.new(file)
MediaFile.new(file, **options)
end
end
@@ -45,7 +45,7 @@ class MediaFile
end
end
def initialize(file)
def initialize(file, **options)
@file = file
end
@@ -73,5 +73,29 @@ class MediaFile
file.size
end
def is_image?
file_ext.in?([:jpg, :png, :gif])
end
def is_video?
file_ext.in?([:webm, :mp4])
end
def is_ugoira?
file_ext == :zip
end
def is_flash?
file_ext == :swf
end
def preview(width, height, **options)
nil
end
def crop(width, height, **options)
nil
end
memoize :dimensions, :file_ext, :file_size, :md5
end

View File

@@ -1,7 +1,7 @@
# Adapted from https://github.com/dim/ruby-imagespec/blob/f2f3ce8bb5b1b411f8658e66a891a095261d94c0/lib/image_spec/parser/swf.rb
# License: https://github.com/dim/ruby-imagespec/blob/master/LICENSE
class MediaFile::Flash < MediaFile::Image
class MediaFile::Flash < MediaFile
def dimensions
# Read the entire stream into memory because the
# dimensions aren't stored in a standard location

View File

@@ -1,9 +1,46 @@
class MediaFile::Image < MediaFile
def dimensions
image.size
# Taken from ArgyllCMS 2.0.0 (see also: https://ninedegreesbelow.com/photography/srgb-profile-comparison.html)
SRGB_PROFILE = "#{Rails.root}/config/sRGB.icm"
# http://jcupitt.github.io/libvips/API/current/VipsForeignSave.html#vips-jpegsave
JPEG_OPTIONS = { Q: 90, background: 255, strip: true, interlace: true, optimize_coding: true }
# http://jcupitt.github.io/libvips/API/current/libvips-resample.html#vips-thumbnail
if Vips.at_least_libvips?(8, 8)
THUMBNAIL_OPTIONS = { size: :down, linear: false, no_rotate: true, export_profile: SRGB_PROFILE, import_profile: SRGB_PROFILE }
CROP_OPTIONS = { crop: :attention, linear: false, no_rotate: true, export_profile: SRGB_PROFILE, import_profile: SRGB_PROFILE }
else
THUMBNAIL_OPTIONS = { size: :down, linear: false, auto_rotate: false, export_profile: SRGB_PROFILE, import_profile: SRGB_PROFILE }
CROP_OPTIONS = { crop: :attention, linear: false, auto_rotate: false, export_profile: SRGB_PROFILE, import_profile: SRGB_PROFILE }
end
def dimensions
image.size
rescue Vips::Error
[0, 0]
end
# https://github.com/jcupitt/libvips/wiki/HOWTO----Image-shrinking
# http://jcupitt.github.io/libvips/API/current/Using-vipsthumbnail.md.html
def preview(width, height)
output_file = Tempfile.new(["image-preview", ".jpg"])
resized_image = image.thumbnail_image(width, height: height, **THUMBNAIL_OPTIONS)
resized_image.jpegsave(output_file.path, **JPEG_OPTIONS)
MediaFile::Image.new(output_file)
end
def crop(width, height)
output_file = Tempfile.new(["image-crop", ".jpg"])
resized_image = image.thumbnail_image(width, height: height, **CROP_OPTIONS)
resized_image.jpegsave(output_file.path, **JPEG_OPTIONS)
MediaFile::Image.new(output_file)
end
private
def image
@image ||= Vips::Image.new_from_file(file.path)
@image ||= Vips::Image.new_from_file(file.path, fail: true)
end
end

View File

@@ -1,13 +1,93 @@
class MediaFile::Ugoira < MediaFile
def dimensions
tempfile = Tempfile.new
folder = Zip::File.new(file.path)
folder.first.extract(tempfile.path) { true }
extend Memoist
class Error < StandardError; end
attr_reader :frame_data
image_file = MediaFile.open(tempfile)
image_file.dimensions
ensure
image_file.close
tempfile.close!
def self.conversion_enabled?
system("ffmpeg -version > /dev/null") && system("mkvmerge --version > /dev/null")
end
def initialize(file, frame_data: {}, **options)
super(file, **options)
@frame_data = frame_data
end
def close
file.close
zipfile.close
preview_frame.close
end
def dimensions
preview_frame.dimensions
end
def preview(width, height)
preview_frame.preview(width, height)
end
def crop(width, height)
preview_frame.crop(width, height)
end
# XXX should take width and height and resize image
def convert
raise NotImplementedError, "can't convert ugoira to webm: ffmpeg or mkvmerge not installed" unless self.class.conversion_enabled?
Dir.mktmpdir("ugoira-#{md5}") do |tmpdir|
output_file = Tempfile.new(["ugoira-conversion", ".webm"], binmode: true)
FileUtils.mkdir_p("#{tmpdir}/images")
zipfile.each do |entry|
path = File.join(tmpdir, "images", entry.name)
entry.extract(path)
end
# Duplicate last frame to avoid it being displayed only for a very short amount of time.
last_file_name = zipfile.entries.last.name
last_file_name =~ /\A(\d{6})(\.\w{,4})\Z/
new_last_index = $1.to_i + 1
file_ext = $2
new_last_filename = ("%06d" % new_last_index) + file_ext
path_from = File.join(tmpdir, "images", last_file_name)
path_to = File.join(tmpdir, "images", new_last_filename)
FileUtils.cp(path_from, path_to)
delay_sum = 0
timecodes_path = File.join(tmpdir, "timecodes.tc")
File.open(timecodes_path, "w+") do |f|
f.write("# timecode format v2\n")
frame_data.each do |img|
f.write("#{delay_sum}\n")
delay_sum += (img["delay"] || img["delay_msec"])
end
f.write("#{delay_sum}\n")
f.write("#{delay_sum}\n")
end
ext = zipfile.first.name.match(/\.(\w{,4})$/)[1]
ffmpeg_out, status = Open3.capture2e("ffmpeg -i #{tmpdir}/images/%06d.#{ext} -codec:v libvpx -crf 4 -b:v 5000k -an #{tmpdir}/tmp.webm")
raise Error, "ffmpeg failed: #{ffmpeg_out}" unless status.success?
mkvmerge_out, status = Open3.capture2e("mkvmerge -o #{output_file.path} --webm --timecodes 0:#{tmpdir}/timecodes.tc #{tmpdir}/tmp.webm")
raise Error, "mkvmerge failed: #{mkvmerge_out}" unless status.success?
MediaFile.open(output_file)
end
end
private
def zipfile
Zip::File.new(file.path)
end
def preview_frame
tempfile = Tempfile.new("ugoira-preview", binmode: true)
zipfile.entries.first.extract(tempfile.path) { true } # 'true' means overwrite the existing tempfile.
MediaFile.open(tempfile)
end
memoize :zipfile, :preview_frame
end

View File

@@ -1,9 +1,29 @@
class MediaFile::Video < MediaFile
extend Memoist
def dimensions
[video.width, video.height]
end
def video
@video ||= FFMPEG::Movie.new(file.path)
def preview(max_width, max_height)
preview_frame.preview(max_width, max_height)
end
def crop(max_width, max_height)
preview_frame.crop(max_width, max_height)
end
private
def video
FFMPEG::Movie.new(file.path)
end
def preview_frame
vp = Tempfile.new(["video-preview", ".jpg"], binmode: true)
video.screenshot(vp.path, seek_time: 0)
MediaFile.open(vp.path)
end
memoize :video, :preview_frame
end

View File

@@ -1,90 +0,0 @@
class PixivUgoiraConverter
def self.enabled?
system("ffmpeg -version > /dev/null") && system("mkvmerge --version > /dev/null")
end
def self.generate_webm(ugoira_file, frame_data)
raise NotImplementedError, "can't convert ugoira to webm: ffmpeg or mkvmerge not installed" unless enabled?
folder = Zip::File.new(ugoira_file.path)
output_file = Tempfile.new(binmode: true)
write_path = output_file.path
Dir.mktmpdir do |tmpdir|
FileUtils.mkdir_p("#{tmpdir}/images")
folder.each_with_index do |file, i|
path = File.join(tmpdir, "images", file.name)
file.extract(path)
end
# Duplicate last frame to avoid it being displayed only for a very short amount of time.
last_file_name = folder.to_a.last.name
last_file_name =~ /\A(\d{6})(\.\w{,4})\Z/
new_last_index = $1.to_i + 1
file_ext = $2
new_last_filename = ("%06d" % new_last_index) + file_ext
path_from = File.join(tmpdir, "images", last_file_name)
path_to = File.join(tmpdir, "images", new_last_filename)
FileUtils.cp(path_from, path_to)
delay_sum = 0
timecodes_path = File.join(tmpdir, "timecodes.tc")
File.open(timecodes_path, "w+") do |f|
f.write("# timecode format v2\n")
frame_data.each do |img|
f.write("#{delay_sum}\n")
delay_sum += (img["delay"] || img["delay_msec"])
end
f.write("#{delay_sum}\n")
f.write("#{delay_sum}\n")
end
ext = folder.first.name.match(/\.(\w{,4})$/)[1]
ffmpeg_out, status = Open3.capture2e("ffmpeg -i #{tmpdir}/images/%06d.#{ext} -codec:v libvpx -crf 4 -b:v 5000k -an #{tmpdir}/tmp.webm")
if !status.success?
Rails.logger.error "[write_webm] ******************************"
Rails.logger.error "[write_webm] failed write_path=#{write_path}"
Rails.logger.error "[write_webm] ffmepg output:"
ffmpeg_out.split(/\n/).each do |line|
Rails.logger.error "[write_webm][ffmpeg] #{line}"
end
Rails.logger.error "[write_webm] ******************************"
end
mkvmerge_out, status = Open3.capture2e("mkvmerge -o #{write_path} --webm --timecodes 0:#{tmpdir}/timecodes.tc #{tmpdir}/tmp.webm")
if !status.success?
Rails.logger.error "[write_webm] ******************************"
Rails.logger.error "[write_webm] failed write_path=#{write_path}"
Rails.logger.error "[write_webm] mkvmerge output:"
mkvmerge_out.split(/\n/).each do |line|
Rails.logger.error "[write_webm][mkvmerge] #{line}"
end
Rails.logger.error "[write_webm] ******************************"
end
end
output_file
end
def self.generate_crop(ugoira_file)
file = Tempfile.new(["ugoira-crop", ".zip"], binmode: true)
zipfile = Zip::File.new(ugoira_file.path)
zipfile.entries.first.extract(file.path) { true } # 'true' means overwrite the existing tempfile.
DanbooruImageResizer.crop(file, Danbooru.config.small_image_width, Danbooru.config.small_image_width, 85)
ensure
file&.close!
end
def self.generate_preview(ugoira_file)
file = Tempfile.new(["ugoira-preview", ".zip"], binmode: true)
zipfile = Zip::File.new(ugoira_file.path)
zipfile.entries.first.extract(file.path) { true } # 'true' means overwrite the existing tempfile.
DanbooruImageResizer.resize(file, Danbooru.config.small_image_width, Danbooru.config.small_image_width, 85)
ensure
file.close!
end
end

View File

@@ -25,53 +25,25 @@ class UploadService
source =~ /^https?:\/\//
end
def generate_resizes(file, upload)
if upload.is_video?
video = FFMPEG::Movie.new(file.path)
crop_file = generate_video_crop_for(video, Danbooru.config.small_image_width)
preview_file = generate_video_preview_for(video, Danbooru.config.small_image_width, Danbooru.config.small_image_width)
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)
elsif upload.is_ugoira?
preview_file = PixivUgoiraConverter.generate_preview(file)
crop_file = PixivUgoiraConverter.generate_crop(file)
sample_file = PixivUgoiraConverter.generate_webm(file, upload.context["ugoira"]["frame_data"])
elsif upload.is_image?
preview_file = DanbooruImageResizer.resize(file, Danbooru.config.small_image_width, Danbooru.config.small_image_width, 85)
crop_file = DanbooruImageResizer.crop(file, Danbooru.config.small_image_width, Danbooru.config.small_image_width, 85)
if upload.image_width > Danbooru.config.large_image_width
sample_file = DanbooruImageResizer.resize(file, Danbooru.config.large_image_width, upload.image_height, 90)
end
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, nil)
else
sample_file = nil
end
[preview_file, crop_file, sample_file]
end
def generate_video_crop_for(video, width)
vp = Tempfile.new(["video-preview", ".jpg"], binmode: true)
video.screenshot(vp.path, :seek_time => 0, :resolution => "#{video.width}x#{video.height}")
crop = DanbooruImageResizer.crop(vp, width, width, 85)
vp.close
return crop
end
def generate_video_preview_for(video, width, height)
dimension_ratio = video.width.to_f / video.height
if dimension_ratio > 1
height = (width / dimension_ratio).to_i
else
width = (height * dimension_ratio).to_i
end
output_file = Tempfile.new(["video-preview", ".jpg"], binmode: true)
video.screenshot(output_file.path, :seek_time => 0, :resolution => "#{width}x#{height}")
output_file
end
def process_file(upload, file, original_post_id: nil)
media_file = MediaFile.open(file)
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
@@ -81,7 +53,7 @@ class UploadService
upload.validate!(:file)
upload.tag_string = "#{upload.tag_string} #{Utils.automatic_tags(upload, file)}"
preview_file, crop_file, sample_file = Utils.generate_resizes(file, upload)
preview_file, crop_file, sample_file = Utils.generate_resizes(media_file)
begin
Utils.distribute_files(file, upload, :original, original_post_id: original_post_id)

View File

@@ -100,6 +100,10 @@ class Upload < ApplicationRecord
end
module FileMethods
def media_file
@media_file ||= MediaFile.open(file, frame_data: context.to_h.dig("ugoira", "frame_data"))
end
def is_image?
%w(jpg gif png).include?(file_ext)
end

View File

@@ -17,7 +17,7 @@ FactoryBot.define do
factory(:ugoira_upload) do
file do
f = Tempfile.new
IO.copy_stream("#{Rails.root}/test/fixtures/ugoira.zip", f.path)
IO.copy_stream("#{Rails.root}/test/files/ugoira.zip", f.path)
ActionDispatch::Http::UploadedFile.new(tempfile: f, filename: "ugoira.zip")
end
end

7
test/files/ugoira.json Normal file
View File

@@ -0,0 +1,7 @@
[
{"file": "000000.jpg", "delay": 200},
{"file": "000001.jpg", "delay": 200},
{"file": "000002.jpg", "delay": 200},
{"file": "000003.jpg", "delay": 200},
{"file": "000004.jpg", "delay": 250}
]

View File

@@ -82,4 +82,47 @@ class MediaFileTest < ActiveSupport::TestCase
should "determine the correct filesize for a jpeg file" do
assert_equal(28086, MediaFile.open("test/files/test.jpg").file_size)
end
context "#preview" do
should "generate a preview image" do
assert_equal([150, 101], MediaFile.open("test/files/test.jpg").preview(150, 150).dimensions)
assert_equal([113, 150], MediaFile.open("test/files/test.png").preview(150, 150).dimensions)
assert_equal([150, 150], MediaFile.open("test/files/test.gif").preview(150, 150).dimensions)
assert_equal([150, 150], MediaFile.open("test/files/test-512x512.webm").preview(150, 150).dimensions)
assert_equal([150, 150], MediaFile.open("test/files/test-300x300.mp4").preview(150, 150).dimensions)
end
should "be able to fit to width only" do
assert_equal([400, 268], MediaFile.open("test/files/test.jpg").preview(400, nil).dimensions)
end
end
context "#crop" do
should "generate a cropped preview image" do
assert_equal([150, 150], MediaFile.open("test/files/test.jpg").crop(150, 150).dimensions)
assert_equal([150, 150], MediaFile.open("test/files/test.png").crop(150, 150).dimensions)
assert_equal([150, 150], MediaFile.open("test/files/test.gif").crop(150, 150).dimensions)
assert_equal([150, 150], MediaFile.open("test/files/test-512x512.webm").crop(150, 150).dimensions)
assert_equal([150, 150], MediaFile.open("test/files/test-300x300.mp4").crop(150, 150).dimensions)
end
end
context "for a ugoira" do
setup do
skip unless MediaFile::Ugoira.conversion_enabled?
frame_data = JSON.parse(File.read("test/files/ugoira.json"))
@ugoira = MediaFile.open("test/files/ugoira.zip", frame_data: frame_data)
end
should "generate a preview" do
assert_equal([60, 60], @ugoira.preview(150, 150).dimensions)
assert_equal([150, 150], @ugoira.crop(150, 150).dimensions)
end
should "convert to a webm" do
webm = @ugoira.convert
assert_equal(:webm, webm.file_ext)
assert_equal([60, 60], webm.dimensions)
end
end
end

View File

@@ -1,24 +0,0 @@
require "test_helper"
class PixivUgoiraConverterTest < ActiveSupport::TestCase
context "An ugoira converter" do
setup do
@zipfile = upload_file("test/fixtures/ugoira.zip").tempfile
@frame_data = [
{"file" => "000000.jpg", "delay" => 200},
{"file" => "000001.jpg", "delay" => 200},
{"file" => "000002.jpg", "delay" => 200},
{"file" => "000003.jpg", "delay" => 200},
{"file" => "000004.jpg", "delay" => 250}
]
end
should "output to webm" do
skip "ffmpeg is not installed" unless PixivUgoiraConverter.enabled?
sample_file = PixivUgoiraConverter.generate_webm(@zipfile, @frame_data)
preview_file = PixivUgoiraConverter.generate_preview(@zipfile)
assert_operator(sample_file.size, :>, 1_000)
assert_operator(preview_file.size, :>, 0)
end
end
end

View File

@@ -15,8 +15,6 @@ class UploadServiceTest < ActiveSupport::TestCase
}
context "::Utils" do
subject { UploadService::Utils }
context "#get_file_for_upload" do
context "for a non-source site" do
setup do
@@ -26,10 +24,8 @@ class UploadServiceTest < ActiveSupport::TestCase
end
should "work on a jpeg" do
file = subject.get_file_for_upload(@upload)
file = UploadService::Utils.get_file_for_upload(@upload)
assert_operator(File.size(file.path), :>, 0)
file.close
end
end
@@ -43,13 +39,9 @@ class UploadServiceTest < ActiveSupport::TestCase
should "work on an ugoira url" do
begin
file = subject.get_file_for_upload(@upload)
file = UploadService::Utils.get_file_for_upload(@upload)
assert_operator(File.size(file.path), :>, 0)
file.close
rescue Net::OpenTimeout
skip "network problems"
end
end
end
@@ -64,15 +56,12 @@ class UploadServiceTest < ActiveSupport::TestCase
end
should "work on an ugoira url" do
skip unless PixivUgoiraConverter.enabled?
file = subject.get_file_for_upload(@upload)
file = UploadService::Utils.get_file_for_upload(@upload)
assert_not_nil(@upload.context["ugoira"])
assert_operator(File.size(file.path), :>, 0)
file.close
rescue Net::OpenTimeout
skip "network failure"
end
end
end
@@ -84,14 +73,14 @@ class UploadServiceTest < ActiveSupport::TestCase
context "with an original_post_id" do
should "run" do
subject.expects(:distribute_files).times(3)
subject.process_file(@upload, @upload.file.tempfile, original_post_id: 12345)
UploadService::Utils.expects(:distribute_files).times(3)
UploadService::Utils.process_file(@upload, @upload.file.tempfile, original_post_id: 12345)
end
end
should "run" do
subject.expects(:distribute_files).times(3)
subject.process_file(@upload, @upload.file.tempfile)
UploadService::Utils.expects(:distribute_files).times(3)
UploadService::Utils.process_file(@upload, @upload.file.tempfile)
assert_equal("jpg", @upload.file_ext)
assert_equal(28086, @upload.file_size)
assert_equal("ecef68c44edb8a0d6a3070b5f8e8ee76", @upload.md5)
@@ -99,184 +88,6 @@ class UploadServiceTest < ActiveSupport::TestCase
assert_equal(500, @upload.image_width)
end
end
context ".generate_resizes" do
context "for an ugoira" do
setup do
context = UGOIRA_CONTEXT
@file = upload_file("test/fixtures/ugoira.zip")
@upload = mock
@upload.stubs(:is_video?).returns(false)
@upload.stubs(:is_ugoira?).returns(true)
@upload.stubs(:context).returns(context)
end
should "generate a preview and a video" do
skip unless PixivUgoiraConverter.enabled?
preview, crop, sample = subject.generate_resizes(@file, @upload)
assert_operator(File.size(preview.path), :>, 0)
assert_operator(File.size(crop.path), :>, 0)
assert_operator(File.size(sample.path), :>, 0)
assert_equal(60, MediaFile.open(preview).width)
assert_equal(60, MediaFile.open(preview).height)
assert_equal(150, MediaFile.open(crop).width)
assert_equal(150, MediaFile.open(crop).height)
preview.close
preview.unlink
sample.close
sample.unlink
end
end
context "for a video" do
teardown do
@file.close
end
context "for an mp4" do
setup do
@file = upload_file("test/files/test-300x300.mp4")
@upload = mock
@upload.stubs(:is_video?).returns(true)
@upload.stubs(:is_ugoira?).returns(false)
end
should "generate a video" do
preview, crop, sample = subject.generate_resizes(@file, @upload)
assert_operator(File.size(preview.path), :>, 0)
assert_operator(File.size(crop.path), :>, 0)
assert_equal(150, MediaFile.open(preview).width)
assert_equal(150, MediaFile.open(preview).height)
assert_equal(150, MediaFile.open(crop).width)
assert_equal(150, MediaFile.open(crop).height)
preview.close
preview.unlink
crop.close
crop.unlink
end
end
context "for a webm" do
setup do
@file = upload_file("test/files/test-512x512.webm")
@upload = mock
@upload.stubs(:is_video?).returns(true)
@upload.stubs(:is_ugoira?).returns(false)
end
should "generate a video" do
preview, crop, sample = subject.generate_resizes(@file, @upload)
assert_operator(File.size(preview.path), :>, 0)
assert_operator(File.size(crop.path), :>, 0)
assert_equal(150, MediaFile.open(preview).width)
assert_equal(150, MediaFile.open(preview).height)
assert_equal(150, MediaFile.open(crop).width)
assert_equal(150, MediaFile.open(crop).height)
preview.close
preview.unlink
crop.close
crop.unlink
end
end
end
context "for an image" do
teardown do
@file.close
end
setup do
@upload = mock
@upload.stubs(:is_video?).returns(false)
@upload.stubs(:is_ugoira?).returns(false)
@upload.stubs(:is_image?).returns(true)
@upload.stubs(:image_width).returns(1200)
@upload.stubs(:image_height).returns(200)
end
context "for a jpeg" do
setup do
@file = upload_file("test/files/test.jpg")
end
should "generate a preview" do
preview, crop, sample = subject.generate_resizes(@file, @upload)
assert_operator(File.size(preview.path), :>, 0)
assert_operator(File.size(crop.path), :>, 0)
assert_operator(File.size(sample.path), :>, 0)
preview.close
preview.unlink
sample.close
sample.unlink
end
end
context "for a png" do
setup do
@file = upload_file("test/files/test.png")
end
should "generate a preview" do
preview, crop, sample = subject.generate_resizes(@file, @upload)
assert_operator(File.size(preview.path), :>, 0)
assert_operator(File.size(crop.path), :>, 0)
assert_operator(File.size(sample.path), :>, 0)
preview.close
preview.unlink
sample.close
sample.unlink
end
end
context "for a gif" do
setup do
@file = upload_file("test/files/test.png")
end
should "generate a preview" do
preview, crop, sample = subject.generate_resizes(@file, @upload)
assert_operator(File.size(preview.path), :>, 0)
assert_operator(File.size(crop.path), :>, 0)
assert_operator(File.size(sample.path), :>, 0)
preview.close
preview.unlink
sample.close
sample.unlink
end
end
end
end
context ".generate_video_preview_for" do
context "for an mp4" do
setup do
@path = "test/files/test-300x300.mp4"
@video = FFMPEG::Movie.new(@path)
end
should "generate a video" do
sample = subject.generate_video_preview_for(@video, 100, 100)
assert_operator(File.size(sample.path), :>, 0)
sample.close
sample.unlink
end
end
context "for a webm" do
setup do
@path = "test/files/test-512x512.webm"
@video = FFMPEG::Movie.new(@path)
end
should "generate a video" do
sample = subject.generate_video_preview_for(@video, 100, 100)
assert_operator(File.size(sample.path), :>, 0)
sample.close
sample.unlink
end
end
end
end
context "::Preprocessor" do
@@ -302,7 +113,7 @@ class UploadServiceTest < ActiveSupport::TestCase
end
should "download the file" do
@service = subject.new(source: @source, referer_url: @ref)
@service = UploadService::Preprocessor.new(source: @source, referer_url: @ref)
@upload = @service.start!
assert_equal("preprocessed", @upload.status)
assert_equal(9800, @upload.file_size)
@@ -321,7 +132,7 @@ class UploadServiceTest < ActiveSupport::TestCase
should "download the file" do
begin
@service = subject.new(source: @source, referer_url: @ref)
@service = UploadService::Preprocessor.new(source: @source, referer_url: @ref)
@upload = @service.start!
rescue Net::OpenTimeout
skip "network failure"
@@ -341,9 +152,9 @@ class UploadServiceTest < ActiveSupport::TestCase
end
should "download the file" do
skip unless PixivUgoiraConverter.enabled?
skip unless MediaFile::Ugoira.conversion_enabled?
@service = subject.new(source: @source)
@service = UploadService::Preprocessor.new(source: @source)
begin
@upload = @service.start!
rescue Net::OpenTimeout
@@ -364,7 +175,7 @@ class UploadServiceTest < ActiveSupport::TestCase
end
should "download the file" do
@service = subject.new(source: @source)
@service = UploadService::Preprocessor.new(source: @source)
begin
@upload = @service.start!
rescue Net::OpenTimeout
@@ -386,7 +197,7 @@ class UploadServiceTest < ActiveSupport::TestCase
end
should "work for a video" do
@service = subject.new(source: @source)
@service = UploadService::Preprocessor.new(source: @source)
@upload = @service.start!
assert_equal("preprocessed", @upload.status)
assert_not_nil(@upload.md5)
@@ -405,7 +216,7 @@ class UploadServiceTest < ActiveSupport::TestCase
end
should "leave the upload in an error state" do
@service = subject.new(source: @source)
@service = UploadService::Preprocessor.new(source: @source)
@upload = @service.start!
assert_match(/error:/, @upload.status)
end
@@ -413,7 +224,7 @@ class UploadServiceTest < ActiveSupport::TestCase
context "for an invalid content type" do
should "fail" do
upload = subject.new(source: "http://www.example.com").start!
upload = UploadService::Preprocessor.new(source: "http://www.example.com").start!
assert_match(/\Aerror:.*File ext is invalid/, upload.status)
end
end
@@ -429,7 +240,7 @@ class UploadServiceTest < ActiveSupport::TestCase
end
should "overwrite the attributes" do
@service = subject.new(source: @source, rating: 'e')
@service = UploadService::Preprocessor.new(source: @source, rating: 'e')
@upload = @service.start!
@service.finish!
@upload.reload
@@ -737,7 +548,7 @@ class UploadServiceTest < ActiveSupport::TestCase
context "a post that is replaced by a ugoira" do
should "save the frame data" do
skip "ffmpeg not installed" unless PixivUgoiraConverter.enabled?
skip unless MediaFile::Ugoira.conversion_enabled?
begin
as_user { @post.replace!(replacement_url: "http://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247364") }
@post.reload
@@ -751,8 +562,6 @@ class UploadServiceTest < ActiveSupport::TestCase
assert_equal("https://i.pximg.net/img-zip-ugoira/img/2017/04/04/08/57/38/62247364_ugoira1920x1080.zip", @post.source)
assert_equal([{"delay" => 125, "file" => "000000.jpg"}, {"delay" => 125, "file" => "000001.jpg"}], @post.pixiv_ugoira_frame_data.data)
rescue Net::OpenTimeout
skip "Remote connection to Pixiv failed"
end
end
end
@@ -760,7 +569,7 @@ class UploadServiceTest < ActiveSupport::TestCase
context "a post that is replaced to another file then replaced back to the original file" do
should "not delete the original files" do
begin
skip unless PixivUgoiraConverter.enabled?
skip unless MediaFile::Ugoira.conversion_enabled?
@post.unstub(:queue_delete_files)
# this is called thrice to delete the file for 62247364
@@ -802,7 +611,7 @@ class UploadServiceTest < ActiveSupport::TestCase
# swap the images between @post1 and @post2.
begin
as_user do
skip unless PixivUgoiraConverter.enabled?
skip unless MediaFile::Ugoira.conversion_enabled?
@post1.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247350")
@post2.replace!(replacement_url: "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62247364")