mirror of
https://github.com/hkalexling/Mango.git
synced 2025-08-02 02:45:29 -04:00
136 lines
3.4 KiB
Crystal
136 lines
3.4 KiB
Crystal
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.is_valid? @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 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.image_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.sorted_image_files @dir_path
|
|
@sorted_files.not_nil!
|
|
end
|
|
|
|
def self.image_files(dir_path)
|
|
Dir.entries(dir_path)
|
|
.reject(&.starts_with? ".")
|
|
.map { |fn| File.join dir_path, fn }
|
|
.select { |fn| is_supported_image_file fn }
|
|
.reject { |fn| File.directory? fn }
|
|
.select { |fn| File.readable? fn }
|
|
end
|
|
|
|
def self.sorted_image_files(dir_path)
|
|
self.image_files(dir_path)
|
|
.sort { |a, b| compare_numerically a, b }
|
|
end
|
|
|
|
def self.is_valid?(path : String) : Bool
|
|
image_files(path).size > 0
|
|
end
|
|
end
|