From 25b90a8724c8cc446d77d3d7311aa54cbdc10819 Mon Sep 17 00:00:00 2001 From: Leeingnyo Date: Sun, 15 Aug 2021 20:21:36 +0900 Subject: [PATCH 01/10] Apply cache on page, cover api Get image data and use it for hashing --- src/routes/api.cr | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/routes/api.cr b/src/routes/api.cr index a66210a..f865a61 100644 --- a/src/routes/api.cr +++ b/src/routes/api.cr @@ -1,6 +1,7 @@ require "../mangadex/*" require "../upload" require "koa" +require "digest" struct APIRouter @@api_json : String? @@ -81,6 +82,7 @@ struct APIRouter tid = env.params.url["tid"] eid = env.params.url["eid"] page = env.params.url["page"].to_i + prev_e_tag = env.request.headers["If-None-Match"]? title = Library.default.get_title tid raise "Title ID `#{tid}` not found" if title.nil? @@ -90,7 +92,14 @@ struct APIRouter raise "Failed to load page #{page} of " \ "`#{title.title}/#{entry.title}`" if img.nil? - send_img env, img + e_tag = Digest::SHA1.hexdigest img.data + if prev_e_tag == e_tag + env.response.status_code = 304 + "" + else + env.response.headers["ETag"] = e_tag + send_img env, img + end rescue e Logger.error e env.response.status_code = 500 @@ -102,12 +111,14 @@ struct APIRouter Koa.path "tid", desc: "Title ID" Koa.path "eid", desc: "Entry ID" Koa.response 200, schema: Bytes, media_type: "image/*" + Koa.response 304, "" Koa.response 500, "Page not found or not readable" Koa.tag "library" get "/api/cover/:tid/:eid" do |env| begin tid = env.params.url["tid"] eid = env.params.url["eid"] + prev_e_tag = env.request.headers["If-None-Match"]? title = Library.default.get_title tid raise "Title ID `#{tid}` not found" if title.nil? @@ -118,7 +129,14 @@ struct APIRouter raise "Failed to get cover of `#{title.title}/#{entry.title}`" \ if img.nil? - send_img env, img + e_tag = Digest::SHA1.hexdigest img.data + if prev_e_tag == e_tag + env.response.status_code = 304 + "" + else + env.response.headers["ETag"] = e_tag + send_img env, img + end rescue e Logger.error e env.response.status_code = 500 From 2426ef05eca594c1a88b154b4d0d52a7713bc640 Mon Sep 17 00:00:00 2001 From: Leeingnyo Date: Sun, 15 Aug 2021 20:59:11 +0900 Subject: [PATCH 02/10] Apply cache on dimensions api Use zip_path and mtime for hashing It used for weak validation --- src/routes/api.cr | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/routes/api.cr b/src/routes/api.cr index f865a61..d854b1d 100644 --- a/src/routes/api.cr +++ b/src/routes/api.cr @@ -649,21 +649,31 @@ struct APIRouter "height" => Int32, }], } + Koa.response 304 get "/api/dimensions/:tid/:eid" do |env| begin tid = env.params.url["tid"] eid = env.params.url["eid"] + prev_e_tag = env.request.headers["If-None-Match"]? title = Library.default.get_title tid raise "Title ID `#{tid}` not found" if title.nil? entry = title.get_entry eid raise "Entry ID `#{eid}` of `#{title.title}` not found" if entry.nil? - sizes = entry.page_dimensions - send_json env, { - "success" => true, - "dimensions" => sizes, - }.to_json + file_hash = Digest::SHA1.hexdigest (entry.zip_path + entry.mtime.to_s) + e_tag = "W/#{file_hash}" + if e_tag == prev_e_tag + env.response.status_code = 304 + "" + else + sizes = entry.page_dimensions + env.response.headers["ETag"] = e_tag + send_json env, { + "success" => true, + "dimensions" => sizes, + }.to_json + end rescue e Logger.error e send_json env, { From 31d425d462bfbe45c5559d0a964ba7eb2c185911 Mon Sep 17 00:00:00 2001 From: Alex Ling Date: Tue, 17 Aug 2021 07:14:24 +0000 Subject: [PATCH 03/10] Document the 304 responses --- src/routes/api.cr | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/routes/api.cr b/src/routes/api.cr index d854b1d..d2e4d4f 100644 --- a/src/routes/api.cr +++ b/src/routes/api.cr @@ -76,6 +76,7 @@ struct APIRouter Koa.path "page", schema: Int32, desc: "The page number to return (starts from 1)" Koa.response 200, schema: Bytes, media_type: "image/*" Koa.response 500, "Page not found or not readable" + Koa.response 304, "Page not modified (only available when `If-None-Match` is set)" Koa.tag "reader" get "/api/page/:tid/:eid/:page" do |env| begin @@ -111,7 +112,7 @@ struct APIRouter Koa.path "tid", desc: "Title ID" Koa.path "eid", desc: "Entry ID" Koa.response 200, schema: Bytes, media_type: "image/*" - Koa.response 304, "" + Koa.response 304, "Page not modified (only available when `If-None-Match` is set)" Koa.response 500, "Page not found or not readable" Koa.tag "library" get "/api/cover/:tid/:eid" do |env| @@ -649,7 +650,7 @@ struct APIRouter "height" => Int32, }], } - Koa.response 304 + Koa.response 304, "Not modified (only available when `If-None-Match` is set)" get "/api/dimensions/:tid/:eid" do |env| begin tid = env.params.url["tid"] From 4a261d5ff8cb61dfb0c288cbd75f5cf53e26bc7c Mon Sep 17 00:00:00 2001 From: Leeingnyo Date: Mon, 16 Aug 2021 00:55:54 +0900 Subject: [PATCH 04/10] Set Cache-Control header at page, dimensions API --- src/routes/api.cr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/routes/api.cr b/src/routes/api.cr index d2e4d4f..e04150b 100644 --- a/src/routes/api.cr +++ b/src/routes/api.cr @@ -99,6 +99,7 @@ struct APIRouter "" else env.response.headers["ETag"] = e_tag + env.response.headers["Cache-Control"] = "public, max-age=86400" send_img env, img end rescue e @@ -670,6 +671,7 @@ struct APIRouter else sizes = entry.page_dimensions env.response.headers["ETag"] = e_tag + env.response.headers["Cache-Control"] = "public, max-age=86400" send_json env, { "success" => true, "dimensions" => sizes, From b02b28d3e37d66e70de026f368350b8df57fe8c0 Mon Sep 17 00:00:00 2001 From: Leeingnyo Date: Mon, 16 Aug 2021 01:42:07 +0900 Subject: [PATCH 05/10] Implement to preload images when viewer is paged mode --- public/js/reader.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/public/js/reader.js b/public/js/reader.js index f227972..a2a422a 100644 --- a/public/js/reader.js +++ b/public/js/reader.js @@ -11,6 +11,7 @@ const readerComponent = () => { lastSavedPage: page, selectedIndex: 0, // 0: not selected; 1: the first page margin: 30, + preloadLookahead: 3, /** * Initialize the component by fetching the page dimensions @@ -52,6 +53,13 @@ const readerComponent = () => { if (savedMargin) { this.margin = savedMargin; } + + // Preload Images + this.preloadLookahead = 3; + const limit = Math.min(page + this.preloadLookahead, this.items.length + 1); + for (let idx = page + 1; idx <= limit; idx++) { + this.preloadImage(this.items[idx - 1].url); + } }) .catch(e => { const errMsg = `Failed to get the page dimensions. ${e}`; @@ -60,6 +68,12 @@ const readerComponent = () => { this.msg = errMsg; }) }, + /** + * Preload an image, which is expected to be cached + */ + preloadImage(url) { + (new Image()).src = url; + }, /** * Handles the `change` event for the page selector */ @@ -111,6 +125,10 @@ const readerComponent = () => { if (newIdx <= 0 || newIdx > this.items.length) return; + if (newIdx + this.preloadLookahead < this.items.length + 1) { + this.preloadImage(this.items[newIdx + this.preloadLookahead - 1].url); + } + this.toPage(newIdx); if (isNext) From d544252e3e54e61012d0f9e3b4c2a539f79db773 Mon Sep 17 00:00:00 2001 From: Leeingnyo Date: Wed, 18 Aug 2021 22:00:39 +0900 Subject: [PATCH 06/10] Add preload lookahead controller --- public/js/reader.js | 6 +++++- src/views/reader.html.ecr | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/public/js/reader.js b/public/js/reader.js index a2a422a..79943af 100644 --- a/public/js/reader.js +++ b/public/js/reader.js @@ -55,7 +55,7 @@ const readerComponent = () => { } // Preload Images - this.preloadLookahead = 3; + this.preloadLookahead = +localStorage.getItem('preloadLookahead') ?? 3; const limit = Math.min(page + this.preloadLookahead, this.items.length + 1); for (let idx = page + 1; idx <= limit; idx++) { this.preloadImage(this.items[idx - 1].url); @@ -305,6 +305,10 @@ const readerComponent = () => { marginChanged() { localStorage.setItem('margin', this.margin); this.toPage(this.selectedIndex); + }, + + preloadLookaheadChanged() { + localStorage.setItem('preloadLookahead', this.preloadLookahead); } }; } diff --git a/src/views/reader.html.ecr b/src/views/reader.html.ecr index 6b7bb11..9b4e693 100644 --- a/src/views/reader.html.ecr +++ b/src/views/reader.html.ecr @@ -98,6 +98,13 @@ +
+ +
+ +
+
+
From 4d1ad8fb383ce0f5ae6910a232980b8fd05b4e6b Mon Sep 17 00:00:00 2001 From: Leeingnyo Date: Wed, 18 Aug 2021 21:22:34 +0900 Subject: [PATCH 07/10] Prevent load images --- src/views/reader.html.ecr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/reader.html.ecr b/src/views/reader.html.ecr index 9b4e693..ff86d17 100644 --- a/src/views/reader.html.ecr +++ b/src/views/reader.html.ecr @@ -21,7 +21,7 @@
-