mirror of
https://github.com/hkalexling/Mango.git
synced 2025-08-02 02:45:29 -04:00
Implement DirectoryEntry
This commit is contained in:
parent
10587f48cb
commit
55ccd928a2
@ -337,3 +337,145 @@ class ZippedEntry < Entry
|
||||
File.exists? @zip_path
|
||||
end
|
||||
end
|
||||
|
||||
class DirectoryEntry < 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 DirectoryEntry.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
|
||||
|
||||
mtimes = sorted_files.map { |file_path| File.info(file_path).modification_time }
|
||||
@mtime = mtimes.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 exists? : Bool
|
||||
existence = File.exists? @dir_path
|
||||
return false unless existence
|
||||
files = DirectoryEntry.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,
|
||||
# Fix a directory instance with new property
|
||||
# and return true
|
||||
existence
|
||||
end
|
||||
|
||||
def sorted_files
|
||||
cached_sorted_files = @sorted_files
|
||||
return cached_sorted_files if cached_sorted_files
|
||||
@sorted_files = DirectoryEntry.get_valid_files_sorted @dir_path
|
||||
@sorted_files.not_nil!
|
||||
end
|
||||
|
||||
def self.validate_directory_entry(dir_path)
|
||||
files = DirectoryEntry.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 = DirectoryEntry.get_valid_files dir_path
|
||||
files.sort! { |a, b| compare_numerically a, b }
|
||||
end
|
||||
end
|
||||
|
@ -19,7 +19,7 @@ class File
|
||||
# information as long as the above changes do not happen together with
|
||||
# a file/folder rename, with no library scan in between.
|
||||
def self.signature(filename) : UInt64
|
||||
if is_supported_file filename
|
||||
if is_supported_file(filename) || is_supported_image_file(filename)
|
||||
File.info(filename).inode
|
||||
else
|
||||
0u64
|
||||
@ -64,6 +64,9 @@ class Dir
|
||||
path = File.join dirname, fn
|
||||
if File.directory? path
|
||||
signatures << Dir.contents_signature path, cache
|
||||
if DirectoryEntry.validate_directory_entry path
|
||||
signatures << Dir.directory_entry_signature path, cache
|
||||
end
|
||||
else
|
||||
# Only add its signature value to `signatures` when it is a
|
||||
# supported file
|
||||
@ -76,4 +79,19 @@ class Dir
|
||||
cache[dirname] = hash
|
||||
hash
|
||||
end
|
||||
|
||||
def self.directory_entry_signature(dirname, cache = {} of String => String)
|
||||
return cache[dirname + "?entry"] if cache[dirname + "?entry"]?
|
||||
Fiber.yield
|
||||
signatures = [] of String
|
||||
image_files = DirectoryEntry.get_valid_files_sorted dirname
|
||||
if image_files.size > 0
|
||||
image_files.each do |path|
|
||||
signatures << File.signature(path).to_s
|
||||
end
|
||||
end
|
||||
hash = Digest::SHA1.hexdigest(signatures.join)
|
||||
cache[dirname + "?entry"] = hash
|
||||
hash
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user