Split files

This commit is contained in:
Leeingnyo 2022-05-20 14:21:08 +09:00
parent 1f5aed64f7
commit 238539c27d
3 changed files with 258 additions and 253 deletions

View File

@ -0,0 +1,114 @@
require "yaml"
require "./entry"
class ArchiveEntry < Entry
include YAML::Serializable
getter zip_path : String
def initialize(@zip_path, @book)
storage = Storage.default
@encoded_path = URI.encode @zip_path
@title = File.basename @zip_path, File.extname @zip_path
@encoded_title = URI.encode @title
@size = (File.size @zip_path).humanize_bytes
id = storage.get_entry_id @zip_path, File.signature(@zip_path)
if id.nil?
id = random_str
storage.insert_entry_id({
path: @zip_path,
id: id,
signature: File.signature(@zip_path).to_s,
})
end
@id = id
@mtime = File.info(@zip_path).modification_time
unless File.readable? @zip_path
@err_msg = "File #{@zip_path} is not readable."
Logger.warn "#{@err_msg} Please make sure the " \
"file permission is configured correctly."
return
end
archive_exception = validate_archive @zip_path
unless archive_exception.nil?
@err_msg = "Archive error: #{archive_exception}"
Logger.warn "Unable to extract archive #{@zip_path}. " \
"Ignoring it. #{@err_msg}"
return
end
file = ArchiveFile.new @zip_path
@pages = file.entries.count do |e|
SUPPORTED_IMG_TYPES.includes? \
MIME.from_filename? e.filename
end
file.close
end
def path : String
@zip_path
end
def createtime : Time
ctime @zip_path
end
private def sorted_archive_entries
ArchiveFile.open @zip_path do |file|
entries = file.entries
.select { |e|
SUPPORTED_IMG_TYPES.includes? \
MIME.from_filename? e.filename
}
.sort! { |a, b|
compare_numerically a.filename, b.filename
}
yield file, entries
end
end
def read_page(page_num)
raise "Unreadble archive. #{@err_msg}" if @err_msg
img = nil
begin
sorted_archive_entries do |file, entries|
page = entries[page_num - 1]
data = file.read_entry page
if data
img = Image.new data, MIME.from_filename(page.filename),
page.filename, data.size
end
end
rescue e
Logger.warn "Unable to read page #{page_num} of #{@zip_path}. Error: #{e}"
end
img
end
def page_dimensions
sizes = [] of Hash(String, Int32)
sorted_archive_entries do |file, entries|
entries.each_with_index do |e, i|
begin
data = file.read_entry(e).not_nil!
size = ImageSize.get data
sizes << {
"width" => size.width,
"height" => size.height,
}
rescue e
Logger.warn "Failed to read page #{i} of entry #{zip_path}. #{e}"
sizes << {"width" => 1000_i32, "height" => 1000_i32}
end
end
end
sizes
end
def examine : Bool
File.exists? @zip_path
end
end

144
src/library/dir_entry.cr Normal file
View File

@ -0,0 +1,144 @@
require "yaml"
require "./entry"
class DirEntry < Entry
include YAML::Serializable
getter dir_path : String
@[YAML::Field(ignore: true)]
@sorted_files : Array(String)?
@signature : String
def initialize(@dir_path, @book)
storage = Storage.default
@encoded_path = URI.encode @dir_path
@title = File.basename @dir_path
@encoded_title = URI.encode @title
unless File.readable? @dir_path
@err_msg = "Directory #{@dir_path} is not readable."
Logger.warn "#{@err_msg} Please make sure the " \
"file permission is configured correctly."
return
end
unless DirEntry.validate_directory_entry @dir_path
@err_msg = "Directory #{@dir_path} is not valid directory entry."
Logger.warn "#{@err_msg} Please make sure the " \
"directory has valid images."
return
end
size_sum = 0
sorted_files.each do |file_path|
size_sum += File.size file_path
end
@size = size_sum.humanize_bytes
@signature = Dir.directory_entry_signature @dir_path
id = storage.get_entry_id @dir_path, @signature
if id.nil?
id = random_str
storage.insert_entry_id({
path: @dir_path,
id: id,
signature: @signature,
})
end
@id = id
@mtime = sorted_files.map do |file_path|
File.info(file_path).modification_time
end.max
@pages = sorted_files.size
end
def path : String
@dir_path
end
def createtime : Time
ctime @dir_path
end
def read_page(page_num)
img = nil
begin
files = sorted_files
file_path = files[page_num - 1]
data = File.read(file_path).to_slice
if data
img = Image.new data, MIME.from_filename(file_path),
File.basename(file_path), data.size
end
rescue e
Logger.warn "Unable to read page #{page_num} of #{@dir_path}. Error: #{e}"
end
img
end
def page_dimensions
sizes = [] of Hash(String, Int32)
sorted_files.each_with_index do |path, i|
data = File.read(path).to_slice
begin
data.not_nil!
size = ImageSize.get data
sizes << {
"width" => size.width,
"height" => size.height,
}
rescue e
Logger.warn "Failed to read page #{i} of entry #{@dir_path}. #{e}"
sizes << {"width" => 1000_i32, "height" => 1000_i32}
end
end
sizes
end
def examine : Bool
existence = File.exists? @dir_path
return false unless existence
files = DirEntry.get_valid_files @dir_path
signature = Dir.directory_entry_signature @dir_path
existence = files.size > 0 && @signature == signature
@sorted_files = nil unless existence
# For more efficient, update a directory entry with new property
# and return true like Title.examine
existence
end
def sorted_files
cached_sorted_files = @sorted_files
return cached_sorted_files if cached_sorted_files
@sorted_files = DirEntry.get_valid_files_sorted @dir_path
@sorted_files.not_nil!
end
def self.validate_directory_entry(dir_path)
files = DirEntry.get_valid_files dir_path
files.size > 0
end
def self.get_valid_files(dir_path)
files = [] of String
Dir.entries(dir_path).each do |fn|
next if fn.starts_with? "."
path = File.join dir_path, fn
next unless is_supported_image_file path
next if File.directory? path
next unless File.readable? path
files << path
end
files
end
def self.get_valid_files_sorted(dir_path)
files = DirEntry.get_valid_files dir_path
files.sort! { |a, b| compare_numerically a, b }
end
end

View File

@ -1,5 +1,4 @@
require "image_size"
require "yaml"
abstract class Entry
getter id : String, book : Title, title : String,
@ -229,255 +228,3 @@ abstract class Entry
abstract def examine : Bool?
end
class ArchiveEntry < Entry
include YAML::Serializable
getter zip_path : String
def initialize(@zip_path, @book)
storage = Storage.default
@encoded_path = URI.encode @zip_path
@title = File.basename @zip_path, File.extname @zip_path
@encoded_title = URI.encode @title
@size = (File.size @zip_path).humanize_bytes
id = storage.get_entry_id @zip_path, File.signature(@zip_path)
if id.nil?
id = random_str
storage.insert_entry_id({
path: @zip_path,
id: id,
signature: File.signature(@zip_path).to_s,
})
end
@id = id
@mtime = File.info(@zip_path).modification_time
unless File.readable? @zip_path
@err_msg = "File #{@zip_path} is not readable."
Logger.warn "#{@err_msg} Please make sure the " \
"file permission is configured correctly."
return
end
archive_exception = validate_archive @zip_path
unless archive_exception.nil?
@err_msg = "Archive error: #{archive_exception}"
Logger.warn "Unable to extract archive #{@zip_path}. " \
"Ignoring it. #{@err_msg}"
return
end
file = ArchiveFile.new @zip_path
@pages = file.entries.count do |e|
SUPPORTED_IMG_TYPES.includes? \
MIME.from_filename? e.filename
end
file.close
end
def path : String
@zip_path
end
def createtime : Time
ctime @zip_path
end
private def sorted_archive_entries
ArchiveFile.open @zip_path do |file|
entries = file.entries
.select { |e|
SUPPORTED_IMG_TYPES.includes? \
MIME.from_filename? e.filename
}
.sort! { |a, b|
compare_numerically a.filename, b.filename
}
yield file, entries
end
end
def read_page(page_num)
raise "Unreadble archive. #{@err_msg}" if @err_msg
img = nil
begin
sorted_archive_entries do |file, entries|
page = entries[page_num - 1]
data = file.read_entry page
if data
img = Image.new data, MIME.from_filename(page.filename),
page.filename, data.size
end
end
rescue e
Logger.warn "Unable to read page #{page_num} of #{@zip_path}. Error: #{e}"
end
img
end
def page_dimensions
sizes = [] of Hash(String, Int32)
sorted_archive_entries do |file, entries|
entries.each_with_index do |e, i|
begin
data = file.read_entry(e).not_nil!
size = ImageSize.get data
sizes << {
"width" => size.width,
"height" => size.height,
}
rescue e
Logger.warn "Failed to read page #{i} of entry #{zip_path}. #{e}"
sizes << {"width" => 1000_i32, "height" => 1000_i32}
end
end
end
sizes
end
def examine : Bool
File.exists? @zip_path
end
end
class DirEntry < Entry
include YAML::Serializable
getter dir_path : String
@[YAML::Field(ignore: true)]
@sorted_files : Array(String)?
@signature : String
def initialize(@dir_path, @book)
storage = Storage.default
@encoded_path = URI.encode @dir_path
@title = File.basename @dir_path
@encoded_title = URI.encode @title
unless File.readable? @dir_path
@err_msg = "Directory #{@dir_path} is not readable."
Logger.warn "#{@err_msg} Please make sure the " \
"file permission is configured correctly."
return
end
unless DirEntry.validate_directory_entry @dir_path
@err_msg = "Directory #{@dir_path} is not valid directory entry."
Logger.warn "#{@err_msg} Please make sure the " \
"directory has valid images."
return
end
size_sum = 0
sorted_files.each do |file_path|
size_sum += File.size file_path
end
@size = size_sum.humanize_bytes
@signature = Dir.directory_entry_signature @dir_path
id = storage.get_entry_id @dir_path, @signature
if id.nil?
id = random_str
storage.insert_entry_id({
path: @dir_path,
id: id,
signature: @signature,
})
end
@id = id
@mtime = sorted_files.map do |file_path|
File.info(file_path).modification_time
end.max
@pages = sorted_files.size
end
def path : String
@dir_path
end
def createtime : Time
ctime @dir_path
end
def read_page(page_num)
img = nil
begin
files = sorted_files
file_path = files[page_num - 1]
data = File.read(file_path).to_slice
if data
img = Image.new data, MIME.from_filename(file_path),
File.basename(file_path), data.size
end
rescue e
Logger.warn "Unable to read page #{page_num} of #{@dir_path}. Error: #{e}"
end
img
end
def page_dimensions
sizes = [] of Hash(String, Int32)
sorted_files.each_with_index do |path, i|
data = File.read(path).to_slice
begin
data.not_nil!
size = ImageSize.get data
sizes << {
"width" => size.width,
"height" => size.height,
}
rescue e
Logger.warn "Failed to read page #{i} of entry #{@dir_path}. #{e}"
sizes << {"width" => 1000_i32, "height" => 1000_i32}
end
end
sizes
end
def examine : Bool
existence = File.exists? @dir_path
return false unless existence
files = DirEntry.get_valid_files @dir_path
signature = Dir.directory_entry_signature @dir_path
existence = files.size > 0 && @signature == signature
@sorted_files = nil unless existence
# For more efficient, update a directory entry with new property
# and return true like Title.examine
existence
end
def sorted_files
cached_sorted_files = @sorted_files
return cached_sorted_files if cached_sorted_files
@sorted_files = DirEntry.get_valid_files_sorted @dir_path
@sorted_files.not_nil!
end
def self.validate_directory_entry(dir_path)
files = DirEntry.get_valid_files dir_path
files.size > 0
end
def self.get_valid_files(dir_path)
files = [] of String
Dir.entries(dir_path).each do |fn|
next if fn.starts_with? "."
path = File.join dir_path, fn
next unless is_supported_image_file path
next if File.directory? path
next unless File.readable? path
files << path
end
files
end
def self.get_valid_files_sorted(dir_path)
files = DirEntry.get_valid_files dir_path
files.sort! { |a, b| compare_numerically a, b }
end
end