From f837be0718d8c7d93b0211106b2dd9e92e54c107 Mon Sep 17 00:00:00 2001 From: Alex Ling Date: Fri, 28 Feb 2020 16:54:37 +0000 Subject: [PATCH 1/7] Ignore invalid zip files in library --- src/library.cr | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/library.cr b/src/library.cr index 5b72dc7..6a50185 100644 --- a/src/library.cr +++ b/src/library.cr @@ -66,12 +66,27 @@ class Title @encoded_title = URI.encode @title @entries = (Dir.entries dir) .select { |path| [".zip", ".cbz"].includes? File.extname path } + .map { |path| File.join dir, path } + .select { |path| valid_zip path } .map { |path| - Entry.new File.join(dir, path), @title, @id, storage + Entry.new path, @title, @id, storage } .select { |e| e.pages > 0 } .sort { |a, b| a.title <=> b.title } end + # When downloading from MangaDex, the zip/cbz file would not be valid + # before the download is completed. If we scan the zip file, + # Entry.new would throw, so we use this method to check before + # constructing Entry + private def valid_zip(path : String) + begin + file = Zip::File.new path + file.close + return true + rescue + return false + end + end def get_entry(eid) @entries.find { |e| e.id == eid } end From bf37c4aa1059462aa039d41ca087fc37d71d3381 Mon Sep 17 00:00:00 2001 From: Alex Ling Date: Sat, 22 Feb 2020 18:16:04 +0000 Subject: [PATCH 2/7] Sorting in library and title page --- public/js/sort-items.js | 35 +++++++++++++++++++++++++++++++++++ src/library.cr | 9 +++++++-- src/views/index.ecr | 29 ++++++++++++++++++++++------- src/views/title.ecr | 29 ++++++++++++++++++++++------- 4 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 public/js/sort-items.js diff --git a/public/js/sort-items.js b/public/js/sort-items.js new file mode 100644 index 0000000..c2a5f81 --- /dev/null +++ b/public/js/sort-items.js @@ -0,0 +1,35 @@ +$(() => { + $('option#name-up').attr('selected', ''); + $('#sort-select').change(() => { + const sort = $('#sort-select').find(':selected').attr('id'); + const ary = sort.split('-'); + const by = ary[0]; + const dir = ary[1]; + + const items = $('.item'); + items.remove(); + + items.sort((a, b) => { + var res; + if (by === 'name') + res = $(a).find('.uk-card-title').text() > $(b).find('.uk-card-title').text(); + else if (by === 'date') + res = $(a).attr('data-mtime') > $(b).attr('data-mtime'); + else { + const ap = $(a).attr('data-progress'); + const bp = $(b).attr('data-progress'); + if (ap === bp) + // if progress is the same, we compare by name + res = $(a).find('.uk-card-title').text() > $(b).find('.uk-card-title').text(); + else + res = ap > bp; + } + if (dir === 'up') + return res; + else + return !res; + }); + var html = ''; + $('#item-container').append(items); + }); +}); diff --git a/src/library.cr b/src/library.cr index 6a50185..23d1bda 100644 --- a/src/library.cr +++ b/src/library.cr @@ -16,7 +16,8 @@ end class Entry JSON.mapping zip_path: String, book_title: String, title: String, \ size: String, pages: Int32, cover_url: String, id: String, \ - title_id: String, encoded_path: String, encoded_title: String + title_id: String, encoded_path: String, encoded_title: String, + mtime: Time def initialize(path, @book_title, @title_id, storage) @zip_path = path @@ -32,6 +33,7 @@ class Entry .size @id = storage.get_id @zip_path, false @cover_url = "/api/page/#{@title_id}/#{@id}/1" + @mtime = File.info(@zip_path).modification_time end def read_page(page_num) Zip::File.open @zip_path do |file| @@ -57,7 +59,7 @@ end class Title JSON.mapping dir: String, entries: Array(Entry), title: String, - id: String, encoded_title: String + id: String, encoded_title: String, mtime: Time def initialize(dir : String, storage) @dir = dir @@ -73,6 +75,9 @@ class Title } .select { |e| e.pages > 0 } .sort { |a, b| a.title <=> b.title } + mtimes = [File.info(dir).modification_time] + mtimes += @entries.map{|e| e.mtime} + @mtime = mtimes.max end # When downloading from MangaDex, the zip/cbz file would not be valid # before the download is completed. If we scan the zip file, diff --git a/src/views/index.ecr b/src/views/index.ecr index 05a7de7..1aee880 100644 --- a/src/views/index.ecr +++ b/src/views/index.ecr @@ -1,14 +1,28 @@

Library

<%= titles.size %> titles found

-
- +
+
+ +
+
+
+ +
+
-
+
<%- titles.each_with_index do |t, i| -%> -
+
@@ -27,4 +41,5 @@ <% content_for "script" do %> + <% end %> diff --git a/src/views/title.ecr b/src/views/title.ecr index 42546ac..017993a 100644 --- a/src/views/title.ecr +++ b/src/views/title.ecr @@ -1,15 +1,29 @@

<%= title.title %>

<%= title.entries.size %> entries found

-
- +
+
+ +
+
+
+ +
+
-
+
<%- title.entries.each_with_index do |e, i| -%> -
+
@@ -51,4 +65,5 @@ <% content_for "script" do %> + <% end %> From 73b38492ba7d107dab442a066e8c3fc4cb11614f Mon Sep 17 00:00:00 2001 From: Alex Ling Date: Mon, 24 Feb 2020 15:45:05 +0000 Subject: [PATCH 3/7] Remove console in minified JS files --- gulpfile.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gulpfile.js b/gulpfile.js index b088d3a..dc6f33d 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -4,7 +4,9 @@ const minifyCss = require('gulp-minify-css'); gulp.task('minify-js', () => { return gulp.src('public/js/*.js') - .pipe(minify()) + .pipe(minify({ + removeConsole: true + })) .pipe(gulp.dest('dist/js')); }); From cb76a961263004790939847ae2de4dc033624660 Mon Sep 17 00:00:00 2001 From: Alex Ling Date: Fri, 28 Feb 2020 16:55:39 +0000 Subject: [PATCH 4/7] Removing the logging of the library json on scan --- src/library.cr | 1 - 1 file changed, 1 deletion(-) diff --git a/src/library.cr b/src/library.cr index 23d1bda..f422d33 100644 --- a/src/library.cr +++ b/src/library.cr @@ -202,6 +202,5 @@ class Library .select { |title| !title.entries.empty? } .sort { |a, b| a.title <=> b.title } @logger.debug "Scan completed" - @logger.debug "Scanned library: \n#{self.to_pretty_json}" end end From c89c74c71bf50ed27ef8c6cf40218de19a3caf3b Mon Sep 17 00:00:00 2001 From: Alex Ling Date: Fri, 28 Feb 2020 17:53:35 +0000 Subject: [PATCH 5/7] Bump version to 0.1.2 --- src/mango.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mango.cr b/src/mango.cr index 38616ff..c73a226 100644 --- a/src/mango.cr +++ b/src/mango.cr @@ -2,7 +2,7 @@ require "./server" require "./context" require "option_parser" -VERSION = "0.1.0" +VERSION = "0.1.2" config_path = nil From dc3bbd10d6ff05fc9ced8c67c01b82895d807cec Mon Sep 17 00:00:00 2001 From: Alex Ling Date: Wed, 26 Feb 2020 17:24:16 +0000 Subject: [PATCH 6/7] Close zip file after listing entries to prevent leaking --- src/library.cr | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/library.cr b/src/library.cr index f422d33..06805f8 100644 --- a/src/library.cr +++ b/src/library.cr @@ -25,12 +25,14 @@ class Entry @title = File.basename path, File.extname path @encoded_title = URI.encode @title @size = (File.size path).humanize_bytes - @pages = Zip::File.new(path).entries + file = Zip::File.new path + @pages = file.entries .select { |e| ["image/jpeg", "image/png"].includes? \ MIME.from_filename? e.filename } .size + file.close @id = storage.get_id @zip_path, false @cover_url = "/api/page/#{@title_id}/#{@id}/1" @mtime = File.info(@zip_path).modification_time From 5645f272df34751b078ea2d5e811e098f0312298 Mon Sep 17 00:00:00 2001 From: Alex Ling Date: Fri, 28 Feb 2020 18:08:56 +0000 Subject: [PATCH 7/7] When an invalid zip file is found, instead of ignoring it silently, log a warning message --- src/library.cr | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/library.cr b/src/library.cr index 06805f8..fcdfb58 100644 --- a/src/library.cr +++ b/src/library.cr @@ -61,9 +61,9 @@ end class Title JSON.mapping dir: String, entries: Array(Entry), title: String, - id: String, encoded_title: String, mtime: Time + id: String, encoded_title: String, mtime: Time, logger: MLogger - def initialize(dir : String, storage) + def initialize(dir : String, storage, @logger : MLogger) @dir = dir @id = storage.get_id @dir, true @title = File.basename dir @@ -91,6 +91,8 @@ class Title file.close return true rescue + @logger.warn "File #{path} is corrupted or is not a valid zip "\ + "archive. Ignoring it." return false end end @@ -200,7 +202,7 @@ class Library end @titles = (Dir.entries @dir) .select { |path| File.directory? File.join @dir, path } - .map { |path| Title.new File.join(@dir, path), @storage } + .map { |path| Title.new File.join(@dir, path), @storage, @logger } .select { |title| !title.entries.empty? } .sort { |a, b| a.title <=> b.title } @logger.debug "Scan completed"