Fix #5363: Inconsistent order of files from zip uploads.

Upload files in natural order rather than archive order when uploading archive files.

Before files were listed in the same order they appeared in the zip file. This could be in
non-alphabetical order, or even with files from different directories interleaved between each
other. Now files are uploaded in natural order, which is alphabetical order but with numbers sorted
properly, so that `file-9.jpg` appears before `file-10.jpg`.
This commit is contained in:
evazion
2022-12-02 17:57:52 -06:00
parent c19fc16885
commit d7d3427488
5 changed files with 48 additions and 1 deletions

32
app/logical/danbooru.rb Normal file
View File

@@ -0,0 +1,32 @@
# frozen_string_literal: true
# The Danbooru module contains miscellaneous global helper functions.
module Danbooru
module EnumerableMethods
extend self
# Sort a list of strings in natural order, e.g. with "file-2.txt" before "file-10.txt".
#
# @see https://en.wikipedia.org/wiki/Natural_sort_order
# @see https://stackoverflow.com/a/15170063
#
# @param list [Enumerable<String>] The list to sort.
# @return [Array] The sorted list.
def natural_sort(list)
natural_sort_by(list, &:to_s)
end
# Sort a list of objects in natural order. The block should return a sort key, which is compared in natural order.
#
# @param list [Enumerable<Object>] The list to sort.
# @return [Array] The sorted list.
def natural_sort_by(list, &block)
list.sort_by do |element|
# "file-2022-10-01.txt" => ["file-", 2022, "-", 10, "-", 1, ".txt"]
yield(element).to_s.split(/(\d+)/).map { |str| str.match?(/\A\d+\z/) ? str.to_i : str }
end
end
end
extend EnumerableMethods
end

View File

@@ -206,7 +206,7 @@ class Upload < ApplicationRecord
tmpdir, filenames = file.extract!
tmpdirs << tmpdir
filenames.map do |filename|
Danbooru.natural_sort(filenames).map do |filename|
name = "file://#{original_filename}/#{Pathname.new(filename).relative_path_from(tmpdir)}" # "file://foo.zip/foo/1.jpg"
UploadMediaAsset.new(upload: self, file: filename, source_url: name)
end

View File

@@ -1,5 +1,7 @@
# frozen_string_literal: true
require "danbooru"
module Danbooru
module Extensions
module String

Binary file not shown.

View File

@@ -445,6 +445,19 @@ class UploadsControllerTest < ActionDispatch::IntegrationTest
assert_equal(5, upload.upload_media_assets.size)
assert_equal("file://ugoira.zip/000000.jpg", upload.upload_media_assets[0].source_url)
end
should "upload the files in filename order" do
upload = assert_successful_upload("test/files/archive/out-of-order.zip", user: @user)
assert_equal(6, upload.media_asset_count)
assert_equal(6, upload.upload_media_assets.size)
assert_equal("file://out-of-order.zip/9/9.gif", upload.upload_media_assets[0].source_url)
assert_equal("file://out-of-order.zip/9/10.gif", upload.upload_media_assets[1].source_url)
assert_equal("file://out-of-order.zip/9/11.gif", upload.upload_media_assets[2].source_url)
assert_equal("file://out-of-order.zip/10/9.gif", upload.upload_media_assets[3].source_url)
assert_equal("file://out-of-order.zip/10/10.gif", upload.upload_media_assets[4].source_url)
assert_equal("file://out-of-order.zip/10/11.gif", upload.upload_media_assets[5].source_url)
end
end
context "uploading a .rar file from your computer" do